Audio project not running unless I upload the code everytime

Status
Not open for further replies.

alexandros

Well-known member
I'm building an audio project with a Teensy 3.6 and the Audio Board. When I develop it and upload new code, the project runs fine. When I unplug and re-plug the Teensy, I get nothing from the headphones. When I upload the code again, I still get nothing.
To make it work I need to upload an example with audio output from the Audio examples and then upload my code and it will work fine.

Here's my code:
Code:
// GUItool: begin automatically generated code
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioSynthWaveformSine   sines[2];
AudioEffectFade          faders[2];
AudioMixer4              mixer1;
AudioOutputI2S           i2s1;
AudioConnection          patchCord1(sines[1], faders[1]);
AudioConnection          patchCord2(sines[0], faders[0]);
AudioConnection          patchCord3(faders[0], 0, mixer1, 0);
AudioConnection          patchCord4(faders[1], 0, mixer1, 1);
AudioConnection          patchCord5(mixer1, 0, i2s1, 0);
// GUItool: end automatically generated code


// define a delta value difference for the ribons, to eliminate noisy readings
#define RIBDELTA 8
// define a delta value difference for frequencies passed to the last for loop
#define FREQDELTA 50
// define the analog resolution in bits
#define ANALOGRES 10
#define FRETS 15
// define the tuning A frequency for converting from MIDI to frequency if the freq ribon
// is split to the number of frets set above
#define TUNING_A 440.0

const int ribons = 4;
int ribonPins[ribons] = { 2, 3, 6, 7 };
int ribVals[ribons] = { 0 };
int curVals[ribons] = { 0 };
// we copy the values of the ribons at the end of loop()
// otherwise they'll constantly change and the beginning of loop()
// will constantly update them
int ribValsCopy[ribons] = { 0 };
// these booleans set whether a value sent is an extreme value (0 or 1000)
bool extremeValSent[ribons] = { false };

// we constrain the analog readings to the following two extremes
// their values are set in setup() according to anaolgReadResolution()
// unless ANALOGRES is not defined, then they will default to the values below
int floorVal = 40;
int ceilVal = 1000;
int range = ceilVal - floorVal;
int fretRange = range / FRETS;

// variables for the switches (both lever and rotary)
const int numSwitches = 4;

const int numRotSwitches = 2;
const int numRotSwitchPos = 4;

int switchPins[numSwitches] = { 28, 29, 30, 31 };
int rotSwitchPins[numRotSwitches][numRotSwitchPos] { { 2, 3, 4, 5 }, { 24, 25, 26, 27 } };

int currentSwitchVals[numSwitches];
int currentRotSwitchVals[numRotSwitches][numRotSwitchPos];
// we're using pull-up resistors, so default value is 1
int switchVals[numSwitches] = { 1, 1, 1, 1 };
int oldSwitchVals[numSwitches] = { 1, 1, 1, 1 };
int rotSwitchVals[numRotSwitches][numRotSwitchPos] = { { 1, 1, 1, 1 }, { 1, 1, 1, 1 } };
int oldRotSwitchVals[numRotSwitches][numRotSwitchPos] = { { 1, 1, 1, 1 }, { 1, 1, 1, 1 } };

unsigned long lastDebounceSwitches[numSwitches] = { 0 };
unsigned long lastDebounceRotSwitches[numRotSwitches][numRotSwitchPos] = { { 0 }, { 0 } };
unsigned long debounceTime = 50;

// the following variables are for determining whether we're sustaining the notes or not
// for octaves setting
// and for setting an unfretted or tuned layout for the ribbons
// FIY: ribon 0 is the top fretboard, 2 is bottom fretboard
// ribon 1 is top volume, and 3 bottom volume
// lever switch 3 is top unfretted/tuned switch
// lever switch 1 is bottom unfretted/tuned switch
// lever switch 2 is top sustain switch
// lever switch 0 is bottom sustain switch
// rotary switch 0 is top, and 1 is bottom
int sustainNotes[2] = { 0 };
int frettedRibons[2] = { 0 };
int lowFreqs[4] = { 40, 30, 20, 0 };
int highFreqs[4] = { 1000, 500, 300, 200 };
int lowFreq[2] = { lowFreqs[3], lowFreqs[3] };
int highFreq[2] = { highFreqs[3], highFreqs[3] };
// for MIDI notes we only need the lower part, cause all we do is add it to the current MIDI
// note read by the ribon
int lowMidiNotes[4] = { 40, 30, 20, 10 };
int lowMidiNote[2] = { lowMidiNotes[3], lowMidiNotes[3] };

// these two variables are used to determine whether fading in or out is changing
// when sustain is not set, so we can avoid constantly fading in or out
// until we get a change (amp going to or coming from zero)
int curAmp[2];
int oldAmp[2] = { 0 };

// the two booleans below are used to determing whether we'll do frequency and amplitude
// calculations after we've read all ribons and switches
bool ribValChanged[2] = { false, false };

int fadeMs = 100;
// determine whether we're not touching the ribon at all
bool zeroFreq[2];
int oldRibVal[2] = { 0 };

void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(15);
  
  for (int i = 0; i < numSwitches; i++) {
    pinMode(switchPins[i], INPUT_PULLUP);
  }

  for (int i = 0; i < numRotSwitches; i++) {
    for (int j = 0; j < numRotSwitchPos; j++) {
      pinMode(rotSwitchPins[i][j], INPUT_PULLUP);
    }
  }

  for (int i = 0; i < 2; i++) {
    sines[i].amplitude(0.0);
    // a higher gain in the mixer results in only clicks when both signals are combined
    // and get above a certain amplitude, this gain solves this problem
    mixer1.gain(i, 0.25);
  }

  #ifdef ANALOGRES
    analogReadResolution(ANALOGRES);
    switch(ANALOGRES) {
      case 10:
        floorVal = 40;
        ceilVal = 1000;
        range = ceilVal - floorVal;
        fretRange = range / FRETS;
        break;
      case 12:
        floorVal = 80;
        ceilVal = 4000;
        range = ceilVal - floorVal;
        fretRange = range / FRETS;
        break;
      case 13:
        floorVal = 120;
        ceilVal = 8000;
        range = ceilVal - floorVal;
        fretRange = range / FRETS;
        break;
      default:
        break;
    }
  #endif

  //Serial.begin(115200);
  //while(!Serial) {};
}

void loop() {
  // run through the analog pins, constrain to the defined extremes
  // then test if the new value is more or less that RIBDELTA
  // than the last value stored
  for (int i = 0; i < ribons; i++) {
    curVals[i] = analogRead(ribonPins[i]);
    curVals[i] = constrain(curVals[i], floorVal, ceilVal);
    if (abs(curVals[i] - ribVals[i]) > RIBDELTA) {
      ribVals[i] = curVals[i];
      //Serial.print("Ribon "); Serial.print(i);
      //Serial.print(": "); Serial.println(ribVals[i]);
      // check if we're sending an extreme value
      if ((ribVals[i] <= floorVal) || (ribVals[i] >= ceilVal)) {
        extremeValSent[i] = true;
      }
      else {
        extremeValSent[i] = false;
      }
      ribValChanged[i] = true;
    }
    // check if we're at the extremes
    if ((curVals[i] <= floorVal) || (curVals[i] >= ceilVal)) {
      // if we're at the extremes and an extreme value hasn't been sent, send it
      if (!extremeValSent[i]) {
        ribVals[i] = curVals[i];
        //Serial.print("Ribon "); Serial.print(i);
        //Serial.print(": "); Serial.println(ribVals[i]);
        extremeValSent[i] = true;
        ribValChanged[i] = true;
      }
    }
  }

  // Using the debounce technique from the Arduino tutorials
  // because the switches seem to be quite noisy
  for (int i = 0; i < numSwitches; i++) {
    // read the state of the switch into a local variable:
    currentSwitchVals[i] = digitalRead(switchPins[i]);
    // If the switch changed, due to noise or pressing:
    if (currentSwitchVals[i] != oldSwitchVals[i]) {
      // reset the debouncing timer
      lastDebounceSwitches[i] = millis();
    }
    if ((millis() - lastDebounceSwitches[i]) > debounceTime) {
      if (currentSwitchVals[i] != switchVals[i]) {
        switchVals[i] = currentSwitchVals[i];
        switch(i) {
          case 0:
            sustainNotes[1] = !switchVals[i];
            break;
          case 1:
            frettedRibons[1] = !switchVals[i];
            break;
          case 2:
            sustainNotes[0] = !switchVals[i];
            break;
          case 3:
            frettedRibons[0] = !switchVals[i];
            break;
        }
      }
    }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  oldSwitchVals[i] = currentSwitchVals[i];
  }
  
  for (int i = 0; i < numRotSwitches; i++) {
    for (int j = 0; j < numRotSwitchPos; j++) {
      currentRotSwitchVals[i][j] = digitalRead(rotSwitchPins[i][j]);
      if (currentRotSwitchVals[i][j] != oldRotSwitchVals[i][j]) {
        lastDebounceRotSwitches[i][j] = millis();
      }
      if ((millis() - lastDebounceRotSwitches[i][j]) > debounceTime) {
        if (currentRotSwitchVals[i][j] != rotSwitchVals[i][j]) {
          rotSwitchVals[i][j] = currentRotSwitchVals[i][j];
          if (!rotSwitchVals[i][j]) {
            // by changing the position of a rotary switch, both the current and the previous
            // pin will change states, but we only care about the one that's connected to the common
            lowFreq[i] = lowFreqs[j];
            highFreq[i] = highFreqs[j];
            lowMidiNote[i] = lowMidiNotes[j];
          }
        }
      }
      oldRotSwitchVals[i][j] = currentRotSwitchVals[i][j];
    }
  }

  // after we've read all ribons and switches
  // we write the frequency and amplitude values to the oscillators
  for (int i = 0; i < 2; i++) {
    // ribons are wired this way:
    // 0 is freq for channel 1, 2 is amp for channel 1
    // 1 is freq for channel 2, 3 is amp for channel 2
    int freqIdx = i * 2;
    int ampIdx = (i * 2) + 1;
    
    // calcute frequency and amplitude only if a value of a ribon has changed
    if (ribValChanged[freqIdx] || ribValChanged[ampIdx]) {
      // using i instead of freqIdx in some places cause freqIdx is either 0 or 2
      // and sometimes we need 0 and 1
      ribValsCopy[freqIdx] = ribVals[freqIdx];
      ribValsCopy[ampIdx] = ribVals[ampIdx];
      
      // determine whether we're touching the ribon or not
      if ((ribValsCopy[freqIdx] <= floorVal) || (abs(ribValsCopy[freqIdx] - oldRibVal[i]) > FREQDELTA)) {
        zeroFreq[i] = true;
      }
      else {
        zeroFreq[i] = false;
      }
      oldRibVal[i] = ribValsCopy[freqIdx];

      //Serial.print("Ribon "); Serial.print(i);
      //Serial.print(": "); Serial.println(ribValsCopy[freqIdx]);
      
      int freq = map(ribValsCopy[freqIdx], floorVal, ceilVal, lowFreq[i], highFreq[i]);
      int midiNote = ribValsCopy[freqIdx] / fretRange;
      // can't use map for the amplitude cause we need a float
      ribValsCopy[ampIdx] -= floorVal;
      float amp = (float) ribValsCopy[ampIdx] / (float) (ceilVal - floorVal);

      sines[i].amplitude(amp);
      
      // if the ribons are set to fretted intervals divide the freq value by the fretRange variable
      if (frettedRibons[i]) {
        midiNote += lowMidiNote[i];
        float midiFreq = pow(2, (((float)midiNote - 69.0) / 12.0)) * TUNING_A;
        if (zeroFreq[i]) {
          if (!sustainNotes[i]) {
            faders[i].fadeOut(fadeMs);
          }
        }
        else {
          if (!sustainNotes[i]) {
            // update the frequency only when we're touching the ribon
            sines[i].frequency(midiFreq);
            faders[i].fadeIn(fadeMs);
          }
        }
      }
      else {
        if (zeroFreq[i]) {
          if (!sustainNotes[i]) {
            faders[i].fadeOut(fadeMs);
          }
        }
        else {
          if (!sustainNotes[i]) {
            // update the frequency only when we're touching the ribon
            sines[i].frequency(freq);
            faders[i].fadeIn(fadeMs);
          }
        }
      }
      
      if (ribValChanged[freqIdx]) {
        ribValChanged[freqIdx] = false;
      }
      if (ribValChanged[ampIdx]) {
        ribValChanged[ampIdx] = false;
      }
    }
  }
}

I'm using Arduino IDE 1.8.5, Teensyduino 1.42 or 1.43 (can't remember exactly which one), on Ubuntu Studio 18.04. Any help appreciated.
 
Looks like you don't have an AudioControlSGTL5000 object in your design. You need that to turn on the audio shield hardware.

Just copy it from any of the examples, usually 1 line near the top to create the instance and 2 lines in setup() to turn on the hardware and set the volume.
 
Status
Not open for further replies.
Back
Top