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
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:
#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;
}