Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: Help needed for the Granular effect

Threaded View

  1. #1
    Junior Member
    Join Date
    Feb 2019
    Posts
    7

    Help needed for the Granular effect

    I'm making an electronic drumset with piezo sensors and now I want to change the pitch of the instruments (kick, hi-hat, snare) using rotary encoders.
    Everything works just fine. I have no compiler errors and my serial monitor shows the values I want to see. But (almost) nothing happens when I use the setSpeed() or beginPitchShift() methods of my granular effect objects.
    I'm using the Teensy 3.5 with Audioshield. Sorry if my code is hard/annoying to read. This is my very first physical computing project and I'm also relatively new to programming as a whole.
    I'll also include the whole project as a .zip file, if anyone wants to recreate it.

    Code:
    #include <Encoder.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    #include "AudioSampleKick.h"    // INDEX = 0
    #include "AudioSampleHat.h"     // INDEX = 1
    #include "AudioSampleSnare.h"   // INDEX = 2
    
    AudioPlayMemory          sounds[4];     // This and other arrays have a length of 4, because initially 4 instruments were planned
    AudioEffectGranular      granulars[4];  // Granular Effect for every sound
    AudioMixer4              mix;
    AudioOutputI2S           speakers;
    AudioConnection          c1(sounds[0], granulars[0]);   // Sounds connect to their respective effect
    AudioConnection          c2(sounds[1], granulars[1]);
    AudioConnection          c3(sounds[2], granulars[2]);
    AudioConnection          c4(granulars[0], 0, mix, 0);   // After the effects, the sounds get sent into the mixer
    AudioConnection          c5(granulars[1], 0, mix, 1);
    AudioConnection          c6(granulars[2], 0, mix, 2);
    AudioConnection          c7(mix, 0, speakers, 0);       // Mixer output goes into both stereo channels
    AudioConnection          c8(mix, 0, speakers, 1);
    
    //AudioConnection          c1(sounds[0], 0, mix, 0);    An unsuccessful attempt to solve the problem: "Maybe the effect needs to be applied after the mixer just                                                                                                    
    //AudioConnection          c2(sounds[1], 0, mix, 1);                                                   like in the example?"
    //AudioConnection          c3(sounds[2], 0, mix, 2);
    //AudioConnection          c4(mix, granulars[2]);
    //AudioConnection          c5(granulars[2], 0, speakers, 0);
    //AudioConnection          c6(granulars[2], 0, speakers, 1);
    
    AudioControlSGTL5000     audioShield;
    
    #define GRAN_MEM_SIZE 12800         // This is pretty much copied from the example. I have no idea how many integers I should use...
    int16_t granMems[GRAN_MEM_SIZE][3];
    
    Encoder volEnc(26, 27);   // Encoder which controls the sgtl5000 volume, see onVolChange()
    int vol = 0;
    float defaultVol = 0.5;
    float gainMult[4] = {0.02, 0.025, 0.025};  // Volume multiplicator for every sound.
    
    Encoder pitchEnc[3] = {Encoder(34, 35), Encoder(29, 28), Encoder(38, 39)};  // Pitch Encoders
    int pitchVal[3] = {0, 0, 0};
    
    int count = 3;    // Actual count of the instruments. Used for for loops.
    int pins[4] = {32, 31, 33, 34};   // Pins used for the instruments. Last one is unused.
    int tolerances[4] = {4, 5, 5, 4}; // Tolerance value for each piezo sensor. If a value is surpassed, a sound gets played.
    int values[4];                    // Piezo sensor values stored each loop
    int defaults[4];                  // For some reason the default value of my sensors is not always 0. That's why they are taken into account.
    int durations[4] = {20000, 20000, 20000, 20000};    // Microsecond durations in which the peak of the piezo sensor gets recorded.
                                                        // The sound gets played when the duration is over.
    int recordTimer[4]; // Used together with the durations
    int recordHigh[4];  // Peak of the piezo sensor
    bool isRecording[4] = {false, false, false, false}; // Boolean for each sensor. Recording can only start if the boolean is false.
    
    void setup() {
      Serial.begin(4800);
      AudioMemory(100);
      audioShield.enable();
      audioShield.volume(defaultVol);
    
      for(int i = 0; i < count; i++){
        granulars[i].begin(granMems[i], GRAN_MEM_SIZE);
        pinMode(pins[i], INPUT);
        defaults[i] = analogRead(pins[i]);
        Serial.println("Piezo " + String(i) + " default value is " + String(defaults[i]));
      }
    }
    
    void loop() {
      if(vol != volEnc.read()) onVolChange();
      
      for(int i = 0; i < count; i++){
        int newPitch = round((float)pitchEnc[i].read() / 8.0);
        if(newPitch != pitchVal[i]) onPitchChange(i, newPitch);
        
        values[i] = analogRead(pins[i]);
        if(!isRecording[i] && values[i] > defaults[i] + tolerances[i]){
          isRecording[i] = true;
          recordHigh[i] = 0;
          recordTimer[i] = micros();
        }
        if(isRecording[i]){
          if(values[i] > recordHigh[i]){
            recordHigh[i] = values[i];
          }
          if(micros() >= recordTimer[i] + durations[i]){
            isRecording[i] = false;
            mix.gain(i, ((float)recordHigh[i] * gainMult[i]));
            switch(i){
              case 0:
                sounds[i].play(AudioSampleKick);
                break;
              case 1:
                sounds[i].play(AudioSampleHat);
                break;
              case 2:
                sounds[i].play(AudioSampleSnare);
                break;
            }
            Serial.println(   "Channel: " + String(i) + " Peak: " + String(recordHigh[i]) + " Volume: " + String(((float)recordHigh[i] * gainMult[i])) + " Length: "
                              + String(sounds[i].lengthMillis()));
          }
        }
      }
    }
    
    void onVolChange(){
      if(volEnc.read() > 50) volEnc.write(50);
      if(volEnc.read() < -50) volEnc.write(-50);
      vol = volEnc.read();
      float newVol = (defaultVol + ((float)vol / 100.0));
      audioShield.volume(newVol);
      Serial.println(newVol);
    }
    
    void onPitchChange(int enc, int newPitch){
      pitchVal[enc] = newPitch;
      pitchEnc[enc].write(newPitch * 8);
      float newSpeed = pow(2.0, ((float)newPitch / 12.0));
      granulars[enc].setSpeed(newSpeed);    
      //granulars[enc].beginPitchShift(newSpeed * 100.0); // I tried setSpeed() first, because I already knew the calculation for the ratio parameter.
      Serial.println("Encoder=" + String(enc) + " Value=" + String(pitchEnc[enc].read()) + " Pitch=" + String(newPitch) + " Speed=" + String(newSpeed));
    }
    Attached Files Attached Files
    Last edited by Elekris; 02-10-2019 at 11:15 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •