Code first:
I decided to take on learning about how to make the Teensy 3.2 a sequencer/sample player. I have it soldered to the PJRC audio board. The basic idea is, I turn the Teensy on, and it runs through a pattern or number of steps in which it turns an led on one at a time for each step (8 led's total), no sounds to play until I tell it. Meanwhile it waits for one of 8 sample buttons to be pressed. The button press here is the step you want to edit, or play a sound on.
From there you press one of 8 buttons again. This time however, the buttons represent one of 8 WAV samples on the SD card. I have envelope code in there because I do plan on adding envelopes to the samples. The Teensy keeps track of the step you want to edit it, and the sample you want to play in it. It should then (although I don't have this in place yet) exit the while (1) loop and back to the main loop, where it plays the sequence until undergoing editing again.
I first tried these samples on the 2_02 Audio Tutorial Example. They are all 44100Hz and saved in 16 bit PCM WAV format. I have gotten all samples to play well with the 2_02 Example, no clipping or anything. I wanted to test that they work in the sketch above. In case 1 of the first switch statement in the main loop, there are the lines:
playSdWav1.play("LA.WAV");
delay(10);
Yet I hear no audio. I have placed these lines in the setup to see if they'd play, but no luck. I tried placing the statement:
if (playSdWav1.isPlaying()==False) {
Around the above two statements and still no luck. I can't tell if the teensy is trying to play the tunes but some other instruction is keeping it from doing so. I have also placed delays longer than 10 ms (1000 or 10000) to stop the code but still nothing. I have the Teensy in the 72MHz setting, not 96MHz, is this possibly why?
One thing I should note just in case, when I go to 96MHz (overclock) on the processor speed, the Teensy cannot seem to find or open the SD card. At 72MHz it has no problem. In terms of hardware, all I have is the 8 leds, 8 pushbuttons, and 1 pot to change the tempo. I also checked the Audio Memory Usage and it printed 0.
Thank you
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>
// GUItool: begin automatically generated code
AudioPlaySdWav playSdWav3; //xy=192,208
AudioPlaySdWav playSdWav1; //xy=193,61
AudioPlaySdWav playSdWav2; //xy=196,144
AudioPlaySdWav playSdWav8; //xy=195,546
AudioPlaySdWav playSdWav6; //xy=196,402
AudioPlaySdWav playSdWav4; //xy=198,274
AudioPlaySdWav playSdWav5; //xy=198,333
AudioPlaySdWav playSdWav7; //xy=200,471
AudioMixer4 mixer3; //xy=510,358
AudioMixer4 mixer2; //xy=518,217
AudioMixer4 mixer1; //xy=521.0000305175781,67
AudioMixer4 mixer4; //xy=532,467
AudioMixer4 mixer5; //xy=719,259
AudioOutputI2S i2s1; //xy=915,246
AudioConnection patchCord1(playSdWav3, 0, mixer1, 2);
AudioConnection patchCord2(playSdWav3, 1, mixer2, 2);
AudioConnection patchCord3(playSdWav1, 0, mixer1, 0);
AudioConnection patchCord4(playSdWav1, 1, mixer2, 0);
AudioConnection patchCord5(playSdWav2, 0, mixer1, 1);
AudioConnection patchCord6(playSdWav2, 1, mixer2, 1);
AudioConnection patchCord7(playSdWav8, 0, mixer3, 3);
AudioConnection patchCord8(playSdWav8, 1, mixer4, 3);
AudioConnection patchCord9(playSdWav6, 0, mixer3, 1);
AudioConnection patchCord10(playSdWav6, 1, mixer4, 1);
AudioConnection patchCord11(playSdWav4, 0, mixer1, 3);
AudioConnection patchCord12(playSdWav4, 1, mixer2, 3);
AudioConnection patchCord13(playSdWav5, 0, mixer3, 0);
AudioConnection patchCord14(playSdWav5, 1, mixer4, 0);
AudioConnection patchCord15(playSdWav7, 0, mixer3, 2);
AudioConnection patchCord16(playSdWav7, 1, mixer4, 2);
AudioConnection patchCord17(mixer3, 0, mixer5, 2);
AudioConnection patchCord18(mixer2, 0, mixer5, 1);
AudioConnection patchCord19(mixer1, 0, mixer5, 0);
AudioConnection patchCord20(mixer4, 0, mixer5, 3);
AudioConnection patchCord21(mixer5, 0, i2s1, 0);
AudioConnection patchCord22(mixer5, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=327,664.9999923706055
// GUItool: end automatically generated code
int tempo = 100000; //# loop cycles till next step, hook up to pot
int pattern = 0; //step number in the 8-step sequence
int counter = 0; //loop cycle number
int change = 0;//keep track of step selected to change
int sample1 = 0;//keep track of sample number selected
int sample2 = 10;//keep track of sample number selected
int sample3 = 10;//keep track of sample number selected
int sample4 = 10;//keep track of sample number selected
int sample5 = 10;//keep track of sample number selected
int sample6 = 10;//keep track of sample number selected
int sample7 = 10;//keep track of sample number selected
int sample8 = 10;//keep track of sample number selected
//Include the names of all samples here
char* mySamples[] = {"\"EERIE.WAV\"", "\"LA.WAV\"", "\"RCALOCKGROOVE3.WAV\"",
"\"TIMESPAN.WAV\"", "\"BEADCURTAIN.WAV\"", "\"RCA2.WAV\"", "\"RCALOCKGROOVE2.WAV\"", "\"RCALOOP3.WAV\""
};
// Bounce objects to read pushbuttons
//First 8 control samples
Bounce button0 = Bounce(0, 15);
Bounce button1 = Bounce(1, 15);
Bounce button2 = Bounce(2, 15); // 15 ms debounce time
Bounce button3 = Bounce(3, 15);
Bounce button4 = Bounce(4, 15); // 15 ms debounce time
Bounce button5 = Bounce(5, 15);
Bounce button6 = Bounce(6, 15); // 15 ms debounce time
Bounce button8 = Bounce(8, 15);
void setup() {
Serial.begin(9600);
AudioMemory(12);
sgtl5000_1.enable();
sgtl5000_1.volume(0.6);
SPI.setMOSI(7);
SPI.setSCK(14);
if (!(SD.begin(10))) {
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
//Buttons for each step, used for editing the steps
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
// Status LED's all begin off
pinMode(9, OUTPUT); digitalWrite(9, LOW);
pinMode(20, OUTPUT); digitalWrite(20, LOW);
pinMode(11, OUTPUT); digitalWrite(11, LOW);
pinMode(12, OUTPUT); digitalWrite(12, LOW);
pinMode(21, OUTPUT); digitalWrite(21, LOW);
pinMode(22, OUTPUT); digitalWrite(22, LOW);
pinMode(23, OUTPUT); digitalWrite(23, LOW);
pinMode(19, OUTPUT); digitalWrite(19, LOW);
pinMode(18, OUTPUT); digitalWrite(18, HIGH);
//Mixers, 16 channels total
//Mixer 1
mixer1.gain(0, 0.5);
mixer1.gain(1, 0.5);
mixer1.gain(2, 0.5);
mixer1.gain(3, 0.5);
//Mixer 2
mixer2.gain(0, 0.5);
mixer2.gain(1, 0.5);
mixer2.gain(2, 0.5);
mixer2.gain(3, 0.5);
//Mixer 3
mixer3.gain(0, 0.5);
mixer3.gain(1, 0.5);
mixer3.gain(2, 0.5);
mixer3.gain(3, 0.5);
//Mixer 4
mixer4.gain(0, 0.5);
mixer4.gain(1, 0.5);
mixer4.gain(2, 0.5);
mixer4.gain(3, 0.5);
//Mixer 5
mixer5.gain(0, 0.5);
mixer5.gain(1, 0.5);
mixer5.gain(2, 0.5);
mixer5.gain(3, 0.5);
delay(1000);
Serial.println("Mixers Initialized");
//Envelope defaults (in ms except for sustain)
//delay 0
//attack 1.5
//hold 0.5
//decay 15
//sustain 0-1.0
//release 30
/*
//Envelope 1
envelope1.delay(0);
envelope1.attack(30);
envelope1.hold(5);
envelope1.decay(15);
envelope1.sustain(0.5);
envelope1.release(50);
//Envelope 2
envelope2.delay(0);
envelope2.attack(30);
envelope2.hold(5);
envelope2.decay(15);
envelope2.sustain(0.5);
envelope2.release(50);
//Envelope 3
envelope3.delay(0);
envelope3.attack(30);
envelope3.hold(5);
envelope3.decay(15);
envelope3.sustain(0.5);
envelope3.release(50);
//Envelope 4
envelope4.delay(0);
envelope4.attack(30);
envelope4.hold(5);
envelope4.decay(15);
envelope4.sustain(0.5);
envelope4.release(50);
//Envelope 5
envelope5.delay(0);
envelope5.attack(30);
envelope5.hold(5);
envelope5.decay(15);
envelope5.sustain(0.5);
envelope5.release(50);
//Envelope 6
envelope6.delay(0);
envelope6.attack(30);
envelope6.hold(5);
envelope6.decay(15);
envelope6.sustain(0.5);
envelope6.release(50);
//Envelope 7
envelope7.delay(0);
envelope7.attack(30);
envelope7.hold(5);
envelope7.decay(15);
envelope7.sustain(0.5);
envelope7.release(50);
//Envelope 8
envelope8.delay(0);
envelope8.attack(30);
envelope8.hold(5);
envelope8.decay(15);
envelope8.sustain(0.5);
envelope8.release(50);
Serial.println("Envelopes Initialized");*/
}
void loop() {
button0.update();
button1.update();
button2.update();
button3.update();
button4.update();
button5.update();
button6.update();
button8.update();
//Serial.println("Buttons Updated");
/*
//Change volume using thumbwheel pot
int volKnob = analogRead(A1); // knob = 0 to 1023
float vol = (float)volKnob / 1023.0;
sgtl5000_1.volume(vol);*/
//Advance counter
counter++;
//It's time to advance to the next step if:
if (counter > tempo) {
counter = 0; //Reset the counter variable
//Reset Pattern to 0 if at 8
if (pattern == 8) {
pattern = 0;
}
//Advance pattern/step
pattern++;
Serial.print("Pattern:"); Serial.println(pattern);
//Prepare the setup to move to next step:
//First turn off all leds
digitalWrite(19, LOW); digitalWrite(9, LOW); digitalWrite(20, LOW); digitalWrite(11, LOW);
digitalWrite(12, LOW); digitalWrite(21, LOW); digitalWrite(22, LOW); digitalWrite(23, LOW);
Serial.println("All LEDs off, play next step");
//Change the tempo using pot
int tempoKnob = analogRead(A0); //knob = 0 to 1023
float tempo = tempoKnob *100000 / 1023;
Serial.println(tempo);
//Use parameters for step we are now in. We'll use a series of case
//statements switched on the "pattern" variable that we incremented earlier.
//Maybe for pitch later on or something
//Also turn on leds at each step, after led 8 turns on, they all turn off
//May consider turning on one at a time in the future
switch (pattern) {
case 1:
//stored parameter + live parameter
playSdWav1.play("LA.WAV");
delay(10);
digitalWrite(19, HIGH);
Serial.println("Step 1"); break;
case 2:
//playSdWav2.play(mySamples[sample2]);
delay(10);
digitalWrite(9, HIGH);
Serial.println("Step 2"); break;
case 3:
//playSdWav3.play(mySamples[sample3]);
delay(10);
digitalWrite(20, HIGH);
Serial.println("Step 3"); break;
case 4:
//playSdWav4.play(mySamples[sample4]);
delay(10);
digitalWrite(11, HIGH);
Serial.println("Step 4"); break;
case 5:
//playSdWav5.play(mySamples[sample5]);
delay(10);
digitalWrite(12, HIGH);
Serial.println("Step 5"); break;
case 6:
//playSdWav6.play(mySamples[sample6]);
delay(10);
digitalWrite(21, HIGH);
Serial.println("Step 6"); break;
case 7:
//playSdWav7.play(mySamples[sample7]);
delay(10);
digitalWrite(22, HIGH);
Serial.println("Step 7"); break;
case 8:
//playSdWav8.play(mySamples[sample8]);
delay(10);
digitalWrite(23, HIGH);
Serial.println("Step 8"); break;
}
}
//Check to see if buttons are pressed at any point
if (button0.fallingEdge()) {
Serial.println("Step 1 to edit");
change = 1;
changeStep(1);
}
if (button1.fallingEdge()) {
Serial.println("Step 2 to edit");
change = 2;
changeStep(2);
}
if (button2.fallingEdge()) {
Serial.println("Step 3 to edit");
change = 3;
changeStep(3);
}
if (button3.fallingEdge()) {
Serial.println("Step 4 to edit");
change = 4;
changeStep(4);
}
if (button4.fallingEdge()) {
Serial.println("Step 5 to edit");
change = 5;
changeStep(5);
}
if (button5.fallingEdge()) {
Serial.println("Step 6 to edit");
change = 6;
changeStep(6);
}
if (button6.fallingEdge()) {
Serial.println("Step 7 to edit");
change = 7;
changeStep(7);
}
if (button8.fallingEdge()) {
Serial.println("Step 8 to edit");
change = 8;
changeStep(8);
}
}
void changeStep(int step_num) {
/* The first thing we do is to turn off all indicator lights so
that we can properly indicate which step we're currently editing. */
digitalWrite(19, LOW); digitalWrite(9, LOW); digitalWrite(20, LOW); digitalWrite(11, LOW);
digitalWrite(12, LOW); digitalWrite(21, LOW); digitalWrite(22, LOW); digitalWrite(23, LOW);
Serial.println("LEDS identifying which step we are editing");
//Turn on LED that coincides with step we are editing
switch (step_num) {
case 1:
digitalWrite(19, HIGH);
Serial.println("Step 1");
delay(1000);
digitalWrite(19, LOW);
break;
case 2:
digitalWrite(9, HIGH);
Serial.println("Step 2");
delay(1000);
digitalWrite(9, LOW);
break;
case 3:
digitalWrite(20, HIGH);
Serial.println("Step 3");
delay(1000);
digitalWrite(20, LOW);
break;
case 4:
digitalWrite(11, HIGH);
Serial.println("Step 4");
delay(1000);
digitalWrite(11, LOW);
break;
case 5:
digitalWrite(12, HIGH);
Serial.println("Step 5");
delay(1000);
digitalWrite(12, LOW);
break;
case 6:
digitalWrite(21, HIGH);
Serial.println("Step 6");
delay(1000);
digitalWrite(21, LOW);
break;
case 7:
digitalWrite(22, HIGH);
Serial.println("Step 7");
delay(1000);
digitalWrite(22, LOW);
break;
case 8:
digitalWrite(23, HIGH);
Serial.println("Step 8");
delay(1000);
digitalWrite(23, LOW);
break;
}
//This while loop allows us to edit the sequence
while (1) {
button0.update();
button1.update();
button2.update();
button3.update();
button4.update();
button5.update();
button6.update();
button8.update();
//We must still keep track of the loop cycle number while in edit mode
counter++;
if (counter > tempo) {
Serial.println("counter:"); Serial.println(counter);
counter = 0;
}
//Check to see if buttons are pressed at any point
//If so, play music
if (button0.fallingEdge()) {
Serial.println("playing EERIE.WAV");
addSample(1);
//sample = 0;
}
if (button1.fallingEdge()) {
addSample(2);
//sample = 1;
Serial.println("Playing LA.WAV");
}
if (button2.fallingEdge()) {
addSample(3);
//sample = 2;
Serial.println("Playing Rca Lockgroove 3.WAV");
}
if (button3.fallingEdge()) {
addSample(4);
//sample = 3;
Serial.println("Playing TIMESPAN.WAV");
}
if (button4.fallingEdge()) {
addSample(5);
//sample = 4;
Serial.println("Playing BEADCUTAIN.WAV");
}
if (button5.fallingEdge()) {
addSample(6);
//sample = 5;
Serial.println("Playing RCA2.WAV");
}
if (button6.fallingEdge()) {
addSample(7);
//sample = 6;
Serial.println("Playing RCA LOCKGROOVE 2.WAV");
}
if (button8.fallingEdge()) {
addSample(8);
//sample = 7;
Serial.println("Playing RCALOOPS3");
}
}
}
void addSample(int samp_num) {
/* The first thing we do is to turn off all indicator lights so
that we can properly indicate which step we're currently editing. */
digitalWrite(19, LOW); digitalWrite(9, LOW); digitalWrite(20, LOW); digitalWrite(11, LOW);
digitalWrite(12, LOW); digitalWrite(21, LOW); digitalWrite(22, LOW); digitalWrite(23, LOW);
Serial.println("in add sample function, leds are off");
//Turn on LED that coincides with sample number we are using
switch (samp_num) {
case 1:
digitalWrite(19, HIGH);
break;
case 2:
digitalWrite(9, HIGH);
break;
case 3:
digitalWrite(20, HIGH);
break;
case 4:
digitalWrite(11, HIGH);
break;
case 5:
digitalWrite(12, HIGH);
break;
case 6:
digitalWrite(21, HIGH);
break;
case 7:
digitalWrite(22, HIGH);
break;
case 8:
digitalWrite(23, HIGH);
break;
}
Serial.print("change"); Serial.println(change);
if (change == 1) {
//envelope1.noteOn();
Serial.println("Fine");
playSdWav1.play("EERIE.WAV");
delay(10);
sample1 = samp_num;
/*if(button0.risingEdge()) {
Serial.print("Button 0 De=PRessessed");
envelope1.noteOff();
}*/
}
if (change == 2) {
//envelope2.noteOn();
playSdWav2.play(mySamples[samp_num]);
delay(10);
sample2 = samp_num;
/*if(button1.risingEdge()) {
envelope2.noteOff();
}*/
}
if (change == 3) {
//envelope3.noteOn();
playSdWav3.play(mySamples[samp_num]);
delay(10);
sample3 = samp_num;
/*if(button2.risingEdge()) {
envelope3.noteOff();
}*/
}
if (change == 4) {
//envelope4.noteOn();
playSdWav4.play(mySamples[samp_num]);
delay(10);
sample4 = samp_num;
/*if(button3.risingEdge()) {
envelope4.noteOff();
}*/
}
if (change == 5) {
//envelope5.noteOn();
playSdWav5.play(mySamples[samp_num]);
delay(10);
sample5 = samp_num;
/*if(button4.risingEdge()) {
envelope5.noteOff();
}*/
}
if (change == 6) {
//envelope6.noteOn();
playSdWav6.play(mySamples[samp_num]);
delay(10);
sample6 = samp_num;
/*if(button5.risingEdge()) {
envelope6.noteOff();
}*/
}
if (change == 7) {
//envelope7.noteOn();
playSdWav7.play(mySamples[samp_num]);
delay(10);
sample7 = samp_num;
/*if(button6.risingEdge()) {
envelope7.noteOff();
}*/
}
if (change == 8) {
//envelope8.noteOn();
playSdWav8.play(mySamples[samp_num]);
delay(10);
sample8 = samp_num;
/*if(button8.risingEdge()) {
envelope8.noteOff();
}*/
}
}
I decided to take on learning about how to make the Teensy 3.2 a sequencer/sample player. I have it soldered to the PJRC audio board. The basic idea is, I turn the Teensy on, and it runs through a pattern or number of steps in which it turns an led on one at a time for each step (8 led's total), no sounds to play until I tell it. Meanwhile it waits for one of 8 sample buttons to be pressed. The button press here is the step you want to edit, or play a sound on.
From there you press one of 8 buttons again. This time however, the buttons represent one of 8 WAV samples on the SD card. I have envelope code in there because I do plan on adding envelopes to the samples. The Teensy keeps track of the step you want to edit it, and the sample you want to play in it. It should then (although I don't have this in place yet) exit the while (1) loop and back to the main loop, where it plays the sequence until undergoing editing again.
I first tried these samples on the 2_02 Audio Tutorial Example. They are all 44100Hz and saved in 16 bit PCM WAV format. I have gotten all samples to play well with the 2_02 Example, no clipping or anything. I wanted to test that they work in the sketch above. In case 1 of the first switch statement in the main loop, there are the lines:
playSdWav1.play("LA.WAV");
delay(10);
Yet I hear no audio. I have placed these lines in the setup to see if they'd play, but no luck. I tried placing the statement:
if (playSdWav1.isPlaying()==False) {
Around the above two statements and still no luck. I can't tell if the teensy is trying to play the tunes but some other instruction is keeping it from doing so. I have also placed delays longer than 10 ms (1000 or 10000) to stop the code but still nothing. I have the Teensy in the 72MHz setting, not 96MHz, is this possibly why?
One thing I should note just in case, when I go to 96MHz (overclock) on the processor speed, the Teensy cannot seem to find or open the SD card. At 72MHz it has no problem. In terms of hardware, all I have is the 8 leds, 8 pushbuttons, and 1 pot to change the tempo. I also checked the Audio Memory Usage and it printed 0.
Thank you