Teensy 4.0 Synthesizer Project - Crashing Issues

Status
Not open for further replies.

Spanque

New member
This is my first time playing with a Teensy and I am attempting to build a synthesizer using the Teensy 4.0 and the audioshield. I've harvested the keyboard from an old Yamaha synth and am reading the key matrix into the Teensy using a 74hc165 shift register. The keyboard has 2 separate matrix's (one for each half) each with 4 columns(output) and 6 rows(input). Ive built a basic program for reading the input from the shift register and playing the associated note for each key, i currently have it configured to be able to play 8 notes at the same time. Everything seems to work fine if I play slowly but if I smash down a few keys at the same time or just play very fast the Teensy crashes and makes a loud buzzing until I reset it. Ive tried reading the shift register using the SPI library and now using the shiftIn() function, both give me the same results. Hoping that someone with more experience might know where I've gone all wrong
Code:
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SerialFlash.h>
#include <SPI.h>

// GUItool: begin automatically generated code

AudioSynthWaveform   sine6; 
AudioSynthWaveform   sine7; 
AudioSynthWaveform   sine8; 
AudioSynthWaveform   sine3; 
AudioSynthWaveform   sine4; 
AudioSynthWaveform   sine5; 
AudioSynthWaveform   sine1;   
AudioSynthWaveform   sine2; 
AudioSynthWaveform *waves[8] = {
  &sine1, &sine2, &sine3,
  &sine4, &sine5, &sine6, &sine7, &sine8,  
};

AudioEffectEnvelope      envelope8; 
AudioEffectEnvelope      envelope7; 
AudioEffectEnvelope      envelope5; 
AudioEffectEnvelope      envelope6; 
AudioEffectEnvelope      envelope4; 
AudioEffectEnvelope      envelope3; 
AudioEffectEnvelope      envelope1;   
AudioEffectEnvelope      envelope2; 
AudioEffectEnvelope *envs[8] = {
  &envelope1, &envelope2, &envelope3,
  &envelope4, &envelope5, &envelope6, &envelope7, &envelope8
};

AudioMixer4              mixer2; //xy=548.75,280.75
AudioMixer4              mixer1;         //xy=549.75,214.75
AudioMixer4              mixer3; //xy=686.75,248.75
AudioOutputI2S           i2s1;           //xy=844.9998779296875,249.22219848632812
AudioConnection          patchCord1(sine6, envelope6);
AudioConnection          patchCord2(sine7, envelope7);
AudioConnection          patchCord3(sine8, envelope8);
AudioConnection          patchCord4(sine3, envelope3);
AudioConnection          patchCord5(sine4, envelope4);
AudioConnection          patchCord6(sine5, envelope5);
AudioConnection          patchCord7(sine1, envelope1);
AudioConnection          patchCord8(sine2, envelope2);
AudioConnection          patchCord9(envelope8, 0, mixer2, 3);
AudioConnection          patchCord10(envelope7, 0, mixer2, 2);
AudioConnection          patchCord11(envelope5, 0, mixer2, 0);
AudioConnection          patchCord12(envelope6, 0, mixer2, 1);
AudioConnection          patchCord13(envelope4, 0, mixer1, 3);
AudioConnection          patchCord14(envelope3, 0, mixer1, 2);
AudioConnection          patchCord15(envelope1, 0, mixer1, 0);
AudioConnection          patchCord16(envelope2, 0, mixer1, 1);
AudioConnection          patchCord17(mixer2, 0, mixer3, 1);
AudioConnection          patchCord18(mixer1, 0, mixer3, 0);
AudioConnection          patchCord19(mixer3, 0, i2s1, 0);
AudioConnection          patchCord20(mixer3, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=607.1111450195312,489
// GUItool: end automatically generated code
 
const int sh_ld = 0; //shift/load
const int key_out[4] = {10,12,28,33}; // keyboard output pins
const int clk = 1;
const int shift_in = 11;

float vol = .1;

byte last_shift_1[4]; // holds previous shift register data
byte shift_data_1[4]; // holds current shift register data
byte last_shift_2[4]; // holds previous shift register data
byte shift_data_2[4]; // holds current shift register data

int voice = 0; // the audio object being used, 8 existint key_state1 = 0;

byte current_key; // used to hold the current bit read
byte last_key; // used to hold the last bit read

int right_side =25; // right side which starts at key 25
byte note_tracking[49]; //tracks which note is currently being played
  
float notes[49] = {65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81,  
174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 
493.88, 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77, 1046.50};


void setup(){
  Serial.begin(9600);
   
  AudioMemory(24);
  sgtl5000_1.enable();
  sgtl5000_1.volume(.3);
  AudioProcessorUsageMaxReset();
  AudioMemoryUsageMaxReset();
  
  pinMode(sh_ld, OUTPUT);//set pin modes
  pinMode(key_out[0], OUTPUT);
  pinMode(key_out[1], OUTPUT);
  pinMode(key_out[2], OUTPUT);
  pinMode(key_out[3], OUTPUT);
  pinMode(clk, OUTPUT);
  pinMode(shift_in,INPUT);

  // set 
  digitalWrite(sh_ld, HIGH);//set to shift
  digitalWrite(key_out[0], LOW); //set output pins low
  digitalWrite(key_out[1], LOW);
  digitalWrite(key_out[2], LOW);
  digitalWrite(key_out[3], LOW);
  digitalWrite(clk, LOW);
  

   // set envelope parameters, for pleasing sound :-)
  for (int i=0; i<8; i++) {
    envs[i]->attack(9.2);
    envs[i]->hold(2.1);
    envs[i]->decay(31.4);
    envs[i]->sustain(0.6);
    envs[i]->release(84.5);
  }
  for (int i=0;i<49;i++){ // initialize all key = not pressed
    note_tracking[i] = 0;
  }
  for (int i=0;i<4;i++){ // set last shift arrays to zero
    last_shift_1[i] = 0;
  }
  for (int i=0;i<4;i++){ // set last shift arrays to zero
    last_shift_2[i] = 0;
  }
 
}
void loop(){
  
  while(voice < 8)
  {
    for(int row=0;row<4;row++)
    {
      int oct = (row * 6); //6 keys per output
      digitalWrite(key_out[row], HIGH);//set output line high 
      delayMicroseconds(500);
      
      shift_data_1[row] = read_keys_1(); // first shift register
      shift_data_2[row] = (read_keys_2() >> 1); // second shift register
                       
      for(int column=0;column<6;column++) //right side of keyboard
      {
        int note = (oct + right_side + column); // starting at beginning of right side and going through each key
        current_key = bitRead(shift_data_1[row], column);
        last_key = bitRead(last_shift_1[row], column);
        
        if ((current_key == 1) && (last_key == 0)){                            // key pressed
          AudioNoInterrupts();
          waves[voice]->begin(vol,notes[note],WAVEFORM_SINE);// play note
          envs[voice]->noteOn();
          AudioInterrupts();
          note_tracking[note] = voice; // keeps track of the voice being used for this sound
          //Serial.print(voice);
          voice ++;
          
        }
        if ((current_key == 0) && (last_key == 1)){                            // key released
          envs[note_tracking[note]]->noteOff(); 
          //Serial.print(note_tracking[note]);             
        }
      }
      
      for(int column=0;column<6;column++) //left side of keyboard
      {
        int note = (oct + column); //current note, starting at left side and gong through each key
        current_key = bitRead(shift_data_2[row], column);
        last_key = bitRead(last_shift_2[row], column);
        
        if ((current_key == 1) && (last_key == 0)){                            // key pressed
          AudioNoInterrupts();
          waves[voice]->begin(vol,notes[note],WAVEFORM_SINE);// play note
          envs[voice]->noteOn();
          AudioInterrupts();
          note_tracking[note] = voice; // keeps track of the voice being used for this sound
          Serial.print(voice);
          voice ++;
          
        }
        if ((current_key == 0) && (last_key == 1)){                            // key released
          envs[note_tracking[note]]->noteOff(); 
          Serial.print(note_tracking[note]);             
        }
      }
      last_shift_1[row] = shift_data_1[row];
      last_shift_2[row] = shift_data_2[row];
      digitalWrite(key_out[row], LOW);
    }
  
  }
  voice = 0;
}
 

byte read_keys_1 (){
  byte shift_1;
  // Write pulse to load pin
  digitalWrite(sh_ld, LOW);
  delayMicroseconds(500);
  digitalWrite(sh_ld, HIGH);
  delayMicroseconds(500);
  shift_1 = shiftIn(shift_in, clk, MSBFIRST);//shift in data
  return shift_1;
}

byte read_keys_2 (){
  byte shift_2;
  shift_2 = shiftIn(shift_in, clk, MSBFIRST);//shift in data
  return shift_2;
}

Here's the first code using SPI to read the shift register and only reading half of the keyboard, might be a little easier to read.
Code:
// GUItool: begin automatically generated code

AudioSynthWaveform   sine6; 
AudioSynthWaveform   sine7; 
AudioSynthWaveform   sine8; 
AudioSynthWaveform   sine3; 
AudioSynthWaveform   sine4; 
AudioSynthWaveform   sine5; 
AudioSynthWaveform   sine1;   
AudioSynthWaveform   sine2; 
AudioSynthWaveform *waves[8] = {
  &sine1, &sine2, &sine3,
  &sine4, &sine5, &sine6, &sine7, &sine8,  
};

AudioEffectEnvelope      envelope8; 
AudioEffectEnvelope      envelope7; 
AudioEffectEnvelope      envelope5; 
AudioEffectEnvelope      envelope6; 
AudioEffectEnvelope      envelope4; 
AudioEffectEnvelope      envelope3; 
AudioEffectEnvelope      envelope1;   
AudioEffectEnvelope      envelope2; 
AudioEffectEnvelope *envs[8] = {
  &envelope1, &envelope2, &envelope3,
  &envelope4, &envelope5, &envelope6, &envelope7, &envelope8
};

AudioMixer4              mixer2; //xy=548.75,280.75
AudioMixer4              mixer1;         //xy=549.75,214.75
AudioMixer4              mixer3; //xy=686.75,248.75
AudioOutputI2S           i2s1;           //xy=844.9998779296875,249.22219848632812
AudioConnection          patchCord1(sine6, envelope6);
AudioConnection          patchCord2(sine7, envelope7);
AudioConnection          patchCord3(sine8, envelope8);
AudioConnection          patchCord4(sine3, envelope3);
AudioConnection          patchCord5(sine4, envelope4);
AudioConnection          patchCord6(sine5, envelope5);
AudioConnection          patchCord7(sine1, envelope1);
AudioConnection          patchCord8(sine2, envelope2);
AudioConnection          patchCord9(envelope8, 0, mixer2, 3);
AudioConnection          patchCord10(envelope7, 0, mixer2, 2);
AudioConnection          patchCord11(envelope5, 0, mixer2, 0);
AudioConnection          patchCord12(envelope6, 0, mixer2, 1);
AudioConnection          patchCord13(envelope4, 0, mixer1, 3);
AudioConnection          patchCord14(envelope3, 0, mixer1, 2);
AudioConnection          patchCord15(envelope1, 0, mixer1, 0);
AudioConnection          patchCord16(envelope2, 0, mixer1, 1);
AudioConnection          patchCord17(mixer2, 0, mixer3, 1);
AudioConnection          patchCord18(mixer1, 0, mixer3, 0);
AudioConnection          patchCord19(mixer3, 0, i2s1, 0);
AudioConnection          patchCord20(mixer3, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=607.1111450195312,489
// GUItool: end automatically generated code
 
const int sh_ld = 14; //shift/load
const int key_out[4] = {18,19,1,0}; // keyboard output pins

byte last_shift[4]; // holds previous shift register data
byte shift_data[4]; // holds current shift register data

float vol = 0.1;
int voice = 0; // the audio object being used, 8 existint key_state1 = 0;

byte current_key; // used to hold the current bit read
byte last_key; // used to hold the last bit read

int first_key =25; // using right side which strts at key 25

byte note_tracking[49];
  
float notes[49] = {65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81,  
174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 
493.88, 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77, 1046.50};

SPISettings settingA(1000000, MSBFIRST, SPI_MODE0);//1mhz
unsigned long last_time = millis();
 
void setup(){
  Serial.begin(9600);
  SPI.begin();
  
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(.30);
  AudioProcessorUsageMaxReset();
  AudioMemoryUsageMaxReset();
  
  pinMode(sh_ld, OUTPUT);//set pin modes
  pinMode(key_out[0], OUTPUT);
  pinMode(key_out[1], OUTPUT);
  pinMode(key_out[2], OUTPUT);
  pinMode(key_out[3], OUTPUT);

  // set 
  digitalWrite(14, HIGH);//set to shift
  digitalWrite(key_out[0], LOW); //set output pins low
  digitalWrite(key_out[1], LOW);
  digitalWrite(key_out[2], LOW);
  digitalWrite(key_out[3], LOW);

   // set envelope parameters, for pleasing sound :-)
  for (int i=0; i<8; i++) {
    envs[i]->attack(9.2);
    envs[i]->hold(2.1);
    envs[i]->decay(31.4);
    envs[i]->sustain(0.6);
    envs[i]->release(84.5);
  }
  for (int i=0;i<49;i++){ // initialize all key = not pressed
    note_tracking[i] = 0;
  }
  for (int i=0;i<4;i++){ // set last shift arrays to zero
    last_shift[i] = 0;
  }
 
}
void loop(){
  
  
  
  while(voice < 8)
  {
    for(int row=0;row<4;row++)
    {
      int oct = (row * 6); //6 keys per output
      digitalWrite(key_out[row], HIGH);//set output line i high 
      delay(1);
      shift_data[row] = read_keys();
            
      for(int column=0;column<6;column++)
      {
        int note = (oct + first_key + column);
        current_key = bitRead(shift_data[row], column);
        last_key = bitRead(last_shift[row], column);
        
        if ((current_key == 1) && (last_key == 0)){                            // key pressed
          AudioNoInterrupts();
          waves[voice]->begin(vol,notes[note],WAVEFORM_SINE);// play note
          envs[voice]->noteOn();
          AudioInterrupts();
          note_tracking[note] = voice; // keeps track of the voice being used for this sound
          Serial.print(voice);
          voice ++;
          
        }
        if ((current_key == 0) && (last_key == 1)){                            // key released
          envs[note_tracking[note]]->noteOff(); 
          Serial.print(note_tracking[note]);             
        }
        
      }
      last_shift[row] = shift_data[row];
      digitalWrite(key_out[row], LOW);
    }
  
  }
  voice = 0;
}
 

byte read_keys (){
  byte shift_1;
  SPI.beginTransaction(settingA); // start spi with pre set settings
  digitalWrite(sh_ld, LOW);//set shift reg to load data
  delay(1); //delay 1 ms
  digitalWrite(sh_ld,HIGH);//set shift reg to shift data into teensy 
  shift_1 = SPI.transfer(0x00); // read data transfer
  SPI.endTransaction(); //end spi
  
  if(millis() - last_time >= 5000) {
    Serial.print("Proc = ");
    Serial.print(AudioProcessorUsage());
    Serial.print(" (");    
    Serial.print(AudioProcessorUsageMax());
    Serial.print("),  Mem = ");
    Serial.print(AudioMemoryUsage());
    Serial.print(" (");    
    Serial.print(AudioMemoryUsageMax());
    Serial.println(")");
    last_time = millis();
  }
    
  return shift_1;
}
 
My guess is you're reading/writing out of bounds on one of the several arrays that you've got. One recommendation is to #define the array length so you can be sure any code which accesses the array has a proper length available. For example:

Code:
#define NUM_VOICES 8

AudioSynthWaveform *waves[NUM_VOICES] = {
&sine1, &sine2, &sine3,
&sine4, &sine5, &sine6, &sine7, &sine8,  
};

AudioEffectEnvelope *envs[NUM_VOICES] = {
&envelope1, &envelope2, &envelope3,
&envelope4, &envelope5, &envelope6, &envelope7, &envelope8
};

... other code here ...

if ((current_key == 1) && (last_key == 0)){                            // key pressed
    if(voice >= NUM_VOICES) {
        Serial.printf("We just went out of bounds on the voice array!\n");
    } else {
        AudioNoInterrupts();
        waves[voice]->begin(vol,notes[note],WAVEFORM_SINE);// play note
        envs[voice]->noteOn();
        AudioInterrupts();
        note_tracking[note] = voice; // keeps track of the voice being used for this sound
        //Serial.print(voice);
        voice ++;
    }
}

Assuming my hunch is right (a big assumption) you would need to check each array in your code until you find the one(s) with out of bounds accesses.
 
Maybe you got a short circuit in your keyboard matrix when pressing multiple keys? Short circuits crashing the Teensy happened to me once with a faulty pushbutton. But since you said, that your error also occurs, when you are playing fast...
You could try to scale your program down even further so you can evaluate better.
 
I can't find anything in your code that would cause a problem, but when manipulating array it can be tricky. Last week I had three dead keys while polling a 5 octaves Casio keybed. They where dead until I saw they were 8 keys-spaced, then discovered that I update my track table past the end of the table (which for once crashed nothing !)

My advice : break your code into dedicate functions so you can call them from main loop and test each functionality without the others. it should be easier to track down your bug.
You also can also add a "debug" for loop that iterate trough your noteTracking table to check that every key answers correctly.
 
Status
Not open for further replies.
Back
Top