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

Thread: reading pots to adjust delay or delayext

  1. #1
    Member vangalvin's Avatar
    Join Date
    Jan 2016
    Location
    New Zealand
    Posts
    22

    reading pots to adjust delay or delayext

    I have been working on a project for my son who has just moved from an acoustic guitar to electric guitar. The teensy 3.2 seems to be a great platform to build an effects pedal that has all sorts of features. One of the issues I have had is when using ADC1 for the pots, I seem to be getting a little bit of jitter that causes the delay to click. So i implemented some smoothing. I did try and use a resistor and cap to smooth the signal but still noticed the occasional click on occasion.

    Here is a copy of the code that I am using but was wondering if I could move the smoothing routine in to a class so I do not need to have the code repeated for each pot. My programming skills are not overly advanced and although I have written a few of my own functions and some really basic classes I was unsure if the variables set for the class stay with the object created.

    Here is the code that seems to work prety well for me.
    Code:
    #include <ADC.h>        //ADCZ to read the POT values
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <Bounce.h>     //Button Library
    
    
    ADC *adc = new ADC();; // adc object
    Bounce button0 = Bounce(2, 15);
    
    
    // GUItool: begin automatically generated code
    AudioInputUSB            usb1;           //xy=68,39
    AudioMixer4              mixer1;         //xy=209,51
    AudioEffectDelayExternal dly(AUDIO_MEMORY_23LC1024); //xy=382,215
    AudioMixer4              mixer2;         //xy=682,49
    AudioOutputUSB           usb2;           //xy=1027,37
    AudioOutputAnalog        dac1;           //xy=1027,85
    AudioConnection          patchCord1(usb1, 0, mixer1, 0);
    AudioConnection          patchCord2(usb1, 1, mixer1, 1);
    AudioConnection          patchCord3(mixer1, dly);
    AudioConnection          patchCord4(mixer1, 0, mixer2, 0);
    AudioConnection          patchCord5(dly, 0, mixer2, 1);
    AudioConnection          patchCord6(dly, 7, mixer1, 3);
    AudioConnection          patchCord7(dly, 7, mixer2, 2);
    AudioConnection          patchCord8(mixer2, 0, usb2, 0);
    AudioConnection          patchCord9(mixer2, 0, usb2, 1);
    AudioControlSGTL5000     audioShield;    //xy=81,135
    // GUItool: end automatically generated code
    
    
    const int ledPin = 13;
    int knob1 = A16;          // Effects Knob
    int knob2 = A17;          // Effects Knob
    int knob3 = A18;          // Effects Knob
    
    
    
    
    #define SDCARD_CS_PIN    10   // CS for Caltex Card
    #define SPIRAM_CS_PIN    6    //CS for SRAM
    //#define SDCARD_MOSI_PIN  7   //MOSI on Caltex Card
    //#define SDCARD_MISO_PIN  12   //MISO on Caltex Card
    //#define SDCARD_SCK_PIN   14   //SCK on caltex card
    
    
    void set_adc1_to_3v3(){
      ADC1_SC3 = 0; // cancel calibration
      ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref 3.3v
    
    
      ADC1_SC3 = ADC_SC3_CAL;  // begin calibration
    
    
      uint16_t sum;
    
    
      //serial_print("wait_for_cal\n");
    
    
      while( (ADC1_SC3 & ADC_SC3_CAL))
      {
        // wait
      }
    
    
      __disable_irq();
    
    
        sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
        sum = (sum / 2) | 0x8000;
        ADC1_PG = sum;
        sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
        sum = (sum / 2) | 0x8000;
        ADC1_MG = sum;
    
    
      __enable_irq(); 
    }
    
    
    void setup() {
        pinMode(SDCARD_CS_PIN, OUTPUT);   //Enable SD CS pin for output
        pinMode(SPIRAM_CS_PIN, OUTPUT);   //Enable SRAM CS pin for output
        digitalWrite(SDCARD_CS_PIN, HIGH); //Make sure the pin is HIGG on start up
        digitalWrite(SPIRAM_CS_PIN, HIGH); //Make sure the pin is HIGG on start up
        
            AudioMemory(50);
    //Setup For Delay 
    //mixer1.gain(0, 1);
    //mixer1.gain(1, 1);
    //mixer2.gain(0, 0.7);
    //mixer2.gain(1, 0.7);
    
    
    //Setup for Loop
    mixer1.gain(0, 0.5);
    mixer1.gain(1, 0.5);
    mixer1.gain(2, 0);
    mixer1.gain(3, 0.7);
    
    
    mixer2.gain(0, 1);
    mixer2.gain(1, 0);
    mixer2.gain(2, 1);
    mixer2.gain(3, 0);
    
    
    // All this just to check one POT
    adc->setAveraging(16, ADC_1); // set number of averages
    adc->setResolution(8, ADC_1); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_LOW_SPEED, ADC_1);
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_1);                                                                                                                                                                                                                                                                                                                                                         adc->setReference( ADC_REFERENCE::REF_3V3, ADC_1 );
    set_adc1_to_3v3();
    
    
    delay(200);
    
    
            dly.delay(0, 0);
    
    
    }
    
    
    float mapfloat(float x, float in_min, float in_max, float out_min, float out_max){
     return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }
    
    
    float NEW_WEIGHT = 0.2;
    float SPD_WEIGHT = 0.4;
    int k1val = 0;
    int k2val = 0;
    int k3val = 0;
    int k1val_old = 0;
    int k2val_old = 0;
    int k3val_old = 0;
    int k1diff = 0;
    int k2diff = 0;
    int k3diff = 0;
    int k1diff_speed = 2;
    int k2diff_speed = 2;
    int k3diff_speed = 2;
    int k1val_last = 0;
    int k2val_last = 0;
    int k3val_last = 0;
    void loop() {
    
    
    k1val = adc->analogRead(knob1, ADC_1);
    k2val = adc->analogRead(knob2, ADC_1);
    k3val = adc->analogRead(knob3, ADC_1);
    
    
    k1diff = NEW_WEIGHT * k1val + (1-NEW_WEIGHT) * (k1diff + k1diff_speed);   //updates diff_value, our smoothed pot outputs. Note that diff_speed is used too!
    k1diff_speed = SPD_WEIGHT * (k1diff - k1val_old) + (1-SPD_WEIGHT) * k1diff_speed;  //updates diff_speed, or the rate of change of the smoothed output
    k1val_old = k1diff;  //diff_old_value is to let us calculate the speed
    
    
    k2diff = NEW_WEIGHT * k2val + (1-NEW_WEIGHT) * (k2diff + k2diff_speed);   //updates diff_value, our smoothed pot outputs. Note that diff_speed is used too!
    k2diff_speed = SPD_WEIGHT * (k2diff - k2val_old) + (1-SPD_WEIGHT) * k2diff_speed;  //updates diff_speed, or the rate of change of the smoothed output
    k2val_old = k2diff;  //diff_old_value is to let us calculate the speed
    
    
    k3diff = NEW_WEIGHT * k3val + (1-NEW_WEIGHT) * (k3diff + k3diff_speed);   //updates diff_value, our smoothed pot outputs. Note that diff_speed is used too!
    k3diff_speed = SPD_WEIGHT * (k3diff - k3val_old) + (1-SPD_WEIGHT) * k3diff_speed;  //updates diff_speed, or the rate of change of the smoothed output
    k3val_old = k3diff;  //diff_old_value is to let us calculate the speed
    
    
    if((k1diff >= k1val_last + 4) || (k1diff <= k1val_last - 4)){
      k1val_last = k1diff;
      Serial.print("Change Delay : ");
      Serial.println(k1diff);
      dly.delay(7, map(k1val, 0, 255, 0, 1400));
    }
    
    
    if((k2diff >= k2val_last + 4) || (k2diff <= k2val_last - 4)){
      k2val_last = k2diff;
      Serial.print("Change Mixer Port 0 : ");
      Serial.println(k2diff);
    //  mixer2.gain(0, mapfloat(k2diff, 0, 255, 0.001, 1.001));
      mixer1.gain(0, mapfloat(k2diff, 0, 255, 0.001, 1.001));
      mixer1.gain(1, mapfloat(k2diff, 0, 255, 0.001, 1.001));
    
    
    mixer1.gain(3, 0.7);
    }
    
    
    if((k3diff >= k3val_last + 4) || (k3diff <= k3val_last - 4)){
      k3val_last = k3diff;
      Serial.print("Change Mixer Port 1 : ");
      Serial.println(k3diff);
    //  mixer2.gain(1, mapfloat(k3diff, 0, 255, 0.001, 1.001));
      mixer1.gain(3, mapfloat(k3diff, 0, 255, 0.001, 1.001));
    }
    
    
      delay(100);
    }//end loop
    And this was the class I was thinking about setting up to handle the smoothing.
    do the variables in the class become unique to the object or are they shared between the objects. For instance if an object is created such as
    ctrlKnob kv1(A16, 0);

    then it was updated using something like..
    update(adc->analogRead(knob1, ADC_1));

    would the variable lastknobval be set inside the kv1 object until the update is called again?
    is the variable unique to kv1 or if another object was created would setting the variable in the kv1 object also change the variable for other objects created?

    Code:
    class ctrlKnob {
      int knob;           // the pin of the knob (A16, A17, A18)
      int knobval = 0;        // the value of the knob
      int lastknobval = 0;    // previous knob value
      float NEW_WEIGHT = 0.6;
      float SPD_WEIGHT = 0.7;
      int diff_speed = 1;
      
      public:
      ctrlKnob(int knob, int knobval){
         lastknobval = knobval;
         Serial.println(knobval);
      }
      
     int Update(int value){
    
    
    //diff_value is the smoothed output from the pots
    //value is the new reading 
    //diff_speed is the rate of change of the pot value
    
    
    Serial.print(" lastknobval: ");
    Serial.print(lastknobval);
    Serial.print(" ");
    //NEW_WEIGHT and SPD_WEIGHT are constants (range: 0 to 1) used to adjust how much the filter filters out: lower is more filtering
      knobval = NEW_WEIGHT * value + (1-NEW_WEIGHT) * (knobval + diff_speed);   //updates diff_value, our smoothed pot outputs. Note that diff_speed is used too!
      knobval = SPD_WEIGHT * (knobval - lastknobval) + (1-SPD_WEIGHT) * diff_speed;  //updates diff_speed, or the rate of change of the smoothed output
      lastknobval = knobval;  //diff_old_value is to let us calculate the speed
      //Serial.println("knobval");
     
      return(knobval);
      }
    };

  2. #2
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,329
    Why don't you use ALPS rotary encoders which are more precise and long-term stable ?

  3. #3
    Member vangalvin's Avatar
    Join Date
    Jan 2016
    Location
    New Zealand
    Posts
    22
    Quote Originally Posted by Theremingenieur View Post
    Why don't you use ALPS rotary encoders which are more precise and long-term stable ?
    I can see many bonuses in doing this on the next project, however for this one I was trying to use what I had in my parts bin. I have not yet played around with encoders but after seeing the i2c alps encoder that is looking like a great idea.

    Thank you for the suggestion.

  4. #4
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,060
    1... I think you should read the pots at startup and set gains on their current value or you'll click on the first move (that or make it wait until the default is "picked up" by the knob


    2... consider ResponsiveAnalogRead() to smooth the gain readings

  5. #5
    Member vangalvin's Avatar
    Join Date
    Jan 2016
    Location
    New Zealand
    Posts
    22
    Quote Originally Posted by oddson View Post
    1... I think you should read the pots at startup and set gains on their current value or you'll click on the first move (that or make it wait until the default is "picked up" by the knob
    The initial click when moving the pot is not too much of an issue as once you have the level set it should be nice and stable at that level. setting the pot to get to the desired delay etc will only be done during the setup phase and one it is set and the reading is stable it should not need to keep updating the delay function.


    Quote Originally Posted by oddson View Post
    2... consider ResponsiveAnalogRead() to smooth the gain readings
    I will give that a go, looks like it will be a lot smoother than what I was doing
    Thanks for that.

    That should allow for a better "only update if pot value has changed" routine.

Posting Permissions

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