Audio callback function not triggering with my Seed

Hello,

I’m building a noise gate that eventually will end up as a 500 series module.

I have a breadboard with the following components:

  • Seed
  • LCD screen
  • 1 pot to adjust the LCD contrast
  • 2 pots to adjust the noise gate threshold and knee settings
  • 2 3.5mm audio jacks for audio in/out

The Pots and LCD screen work i.e. I can adjust the pots and see their values update on the LCD screen.

But I cannot get the audio in/out to work. It looks like the audio callback function is not getting called. I can confirm this as the controls function, within the audio callback function never gets called and the I var never increments. Any help would be appreciated.

Thanks!

My code follows…

// noise gate using seed platform

// include libs
#include "daisy_seed.h"

// Use the daisy namespace to prevent having to type
// daisy:: before all libdaisy functions
using namespace daisy;

// Declare a DaisySeed object called hardware
DaisySeed hardware;

// create a var and pin defs for the LCD 
LcdHD44780 lcd;
LcdHD44780::Config lcd_config;
// number matches the light blue pin numbers on the seed pin out diagram 
#define PIN_LCD_RS 21 // LCD pin 4
#define PIN_LCD_EN 22 // LCD pin 6
#define PIN_LCD_D4 23 // LCD: pin 11
#define PIN_LCD_D5 24 // LCD: pin 12
#define PIN_LCD_D6 25 // LCD: pin 13
#define PIN_LCD_D7 28 // LCD: pin 14
// LCD: pin 5 r/w goes to ground

// vars for the noise gate
float thresholdNg, attackNg, decayNg, kneeNg;   

//Helper functions
void Controls();                                                                // knob and lcd function
void GetNoiseGateSample(float &outl, float &outr, float inl, float inr);        // noise gate function
float clip(float n, float lower, float upper);                                  // clip/clamp function

// vars for the knobs
float knob1Value, knob2Value;                      

// var used to convert float to char for the LCD
char buff[16];  // var to hold our char

// vars for debug
int i = 0;

// audio call back func
void AudioCallback(AudioHandle::InterleavingInputBuffer in, AudioHandle::InterleavingOutputBuffer out, size_t size)
{
    float outl, outr, inl, inr;     // vars for the audio in/out ports

    Controls(); // call func to handle input knobs & output LCD

    //audio
    for(size_t i = 0; i < size; i += 2)
    {
        // get the audio in
        inl = in[i];        // left
        inr = in[i + 1];    // right

        // call the noise gate function
        GetNoiseGateSample(outl, outr, inl, inr);

        // send audio out
        out[i] = outl;      // left out
        out[i + 1] = outr;  // right out
    }

    i++;    // debug to confirm this func is getting called
}

int main(void)
{
    // Configure and Initialize the Daisy Seed
    // These are separate to allow reconfiguration of any of the internal
    // components before initialization.
    hardware.Configure();
    hardware.Init();

    // Knob vars & init
    AdcChannelConfig adcConfig[2];                      // config the ADC, the # = total number of knobs to monitor
    adcConfig[0].InitSingle(hardware.GetPin(15));       // knob 1 is blue pin 15 - threshold
    adcConfig[1].InitSingle(hardware.GetPin(16));       // knob 2 is blue pin 16 - knee
    hardware.adc.Init(adcConfig, 2);                    // the num represents the total # of knobs
    hardware.adc.Start();                               // start reading values from the knobs

    // set initial noise gate parameters 
    thresholdNg = 0.5f;             // max app it's .5
    attackNg = 1.0f;                // max app its 1
    decayNg = 20.0f;                // max app its 20
    kneeNg = .75f;                  // max app its .75

    // LCD vars & init
    lcd_config.cursor_on    = true;
    lcd_config.cursor_blink = false;
    lcd_config.rs           = hardware.GetPin(PIN_LCD_RS);
    lcd_config.en           = hardware.GetPin(PIN_LCD_EN);
    lcd_config.d4           = hardware.GetPin(PIN_LCD_D4);
    lcd_config.d5           = hardware.GetPin(PIN_LCD_D5);
    lcd_config.d6           = hardware.GetPin(PIN_LCD_D6);
    lcd_config.d7           = hardware.GetPin(PIN_LCD_D7);
    lcd.Init(lcd_config);

    // start callback
    hardware.StartAudio(AudioCallback);

    while(1) {
        // for debugging, confirm the controls function is working properly
        //Controls(); // call func to handle input knobs & output LCD
        //System::Delay(500);
    }
}

void Controls()
{
        lcd.Clear();    // clear the LCD

        // get the knob values
        knob1Value = hardware.adc.GetFloat(0);
        knob2Value = hardware.adc.GetFloat(1);

        // convert the float to a char
        sprintf(buff, "T" FLT_FMT3 " K" FLT_FMT3 "\n", FLT_VAR3(knob1Value),FLT_VAR3(knob2Value));

        // update the LCD
        lcd.SetCursor(0, 0);
        lcd.Print(buff);

        lcd.SetCursor(1, 0);
        lcd.PrintInt(i);
}

void GetNoiseGateSample(float &outl, float &outr, float inl, float inr)
{
   // FROM MAX NOISE GATE DOCUMENTATION AND THE MAX Dynamics processing patch example
   /* 
   Similar to a compressor with an envelope follower and a threshold, but instead of reducing the gain of the audio energy
   that exceeds the threshold, a gate ateenuates that fall below the threshold. Instead of a ratio, the gate has a knee which 
   is proportional of the threshold within which the audio is attenuated rather than cut altogether, with defaul settings:
   attack = 1, decay = 20, threshold = .5, knee = .75...

   - sound above 0.5 are left alone (i.e. gain = 1, no change)
   - sound below 0.5 and above 0.375 (the threshold * the knee) are scaled between 0 and 1
   - sound below 0.375 are gated out (i.e. g = 0, no sound)

   gate formula g = (e-(t*k)) / (t-(t*k))
   where:
   g = gain 0 to 1
   e = envelope signal (TODO: what is an envelope signal?)
   t = threshold
   k = knee
    */

    // 1. attack param X 44.1 (sample rate?)
    //float attackl = attackNg * sample_rate;    // TO-DO, only need this 1x move to global?
    //float attackr = attackNg * sample_rate;

    // 2. decay param X 44.1 (sample rate?)
    //float decayl = decayNg * sample_rate;      // TO-DO, only need this 1x move to global?
    //float decayr = decayNg * sample_rate;

    // 3. convert incoming signal to abs value
    float inlAbs = fabsf(inl);               // convert inl float to a single precision version
    float inrAbs = fabsf(inr);

    // 4. smooth incoming signal: incoming signal (3), ramp up attack param (1), ramp down decay param (2)
    float rampSmoothl = inlAbs;    // TODO - how achieve this with dasiySP?
    float rampSmoothr = inrAbs;    // TODO - how achieve this with dasiySP?

    // 5. convert threshold param into a signal (doesn't seem to change the value)
    // TODO

    // 6. convert knee param into a signal (doesn't seem to change the value)
    // TODO

    // 7. multiply threshold (5) X knee (6)
    float thresXknee = thresholdNg * kneeNg;

    // 8. subtract threshold (5) - (threshold (5) X knee (6)) (7)
    float thresDelta = thresholdNg - (thresXknee);

    // 9. subtract rampsmooth (4) - (threshold (5) X knee (6))
    float rampSmoothDeltal = rampSmoothl - thresXknee;  // TODO - how achieve this with dasiySP?
    float rampSmoothDeltar = rampSmoothr - thresXknee;  // TODO - how achieve this with dasiySP?

    // 10. divide rampsmooth (9) / threshold result (8)
    float preclampl = rampSmoothDeltal / thresDelta;
    float preclampr = rampSmoothDeltar / thresDelta;

    // 11. clamp result of (10) range 0 to 1
    // TODO - is there a clamp function 
    float gainl = clip(preclampl,0.0f,1.0f);
    float gainr = clip(preclampr,0.0f,1.0f);

    // 11b. new - smooth the distortion when the waveform crosses the knee
    auto sq = [] (float x) { return x * x; };
    gainl = 1 - sq (1 - gainl);
    gainr = 1 - sq (1 - gainr);

    // 12. out signal = camp (11) * incoming signal 
    outl = gainl * inl;
    outr = gainr * inr;
}

float clip(float n, float lower, float upper) 
{
  return std::max(lower, std::min(n, upper));
}

Solved it, I had to move the LCD code to the main functions while loop

1 Like

Hi @Tummy, check out my Daisy project at

https://oscillator.se/opensource

I am working with an lcd too Maybe you can find something useful in the code?

Thanks I got it sorted, but I’ll definetly check out your code!

1 Like