Hiyall
I am building a device that takes a 5pin DIN MIDI input(awaiting parts so not implemented) from drum pads, and then plays audio from banks of samples. The banks of samples need to be added to by the user, which is why using the SD card works nicely.
I'm trying to avoid using a raspberry pi to avoid the bloat and variables of having an OS and the time taken by a boot up. That being said, I might need to resort to using a pi if I run into fairly immovable issues with a T4 + Audio Board.
The code obviously works when playing a couple of samples at the same time using RAW, but when it comes to properly spamming it, it crashes leaving me with an eeeeeeeeeeeeeee sound which is fun. This thing needs to be pretty bombproof which is one of the reasons why I went microcontroller over pi. There are 10 pads which, although it's unlikely that all of them will be sounding at the same time, should support all 10 being played at the same time.
I assume that the SD class is causing a bit of an issue, however that being out of the way I can imagine that I would still not be able to solve this problem by playing directly from the SD.
The way I see it currently is that there are 4 possibilities:
1. I have a mistake in my code, or haven't optimised it properly for audio
2. The SD class isn't up to scratch, but there might be an alternative which would allow 10 simultaneous RAW file playbacks
3. Loading the files from the SD card to the Flash chip on boot, and then play the files from there would work
4. The hardware isn't quite suited for what is necessary, and I should use a PI or similar.
Thanks everyone!
I am building a device that takes a 5pin DIN MIDI input(awaiting parts so not implemented) from drum pads, and then plays audio from banks of samples. The banks of samples need to be added to by the user, which is why using the SD card works nicely.
I'm trying to avoid using a raspberry pi to avoid the bloat and variables of having an OS and the time taken by a boot up. That being said, I might need to resort to using a pi if I run into fairly immovable issues with a T4 + Audio Board.
The code obviously works when playing a couple of samples at the same time using RAW, but when it comes to properly spamming it, it crashes leaving me with an eeeeeeeeeeeeeee sound which is fun. This thing needs to be pretty bombproof which is one of the reasons why I went microcontroller over pi. There are 10 pads which, although it's unlikely that all of them will be sounding at the same time, should support all 10 being played at the same time.
I assume that the SD class is causing a bit of an issue, however that being out of the way I can imagine that I would still not be able to solve this problem by playing directly from the SD.
The way I see it currently is that there are 4 possibilities:
1. I have a mistake in my code, or haven't optimised it properly for audio
2. The SD class isn't up to scratch, but there might be an alternative which would allow 10 simultaneous RAW file playbacks
3. Loading the files from the SD card to the Flash chip on boot, and then play the files from there would work
4. The hardware isn't quite suited for what is necessary, and I should use a PI or similar.
Thanks everyone!
Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// GUItool: begin automatically generated code
AudioPlaySdRaw playSdRaw1; //xy=181.66666666666663,553.3333333333333
AudioPlaySdRaw playSdRaw3; //xy=184.99999999999997,664.9999999999999
AudioPlaySdRaw playSdRaw8; //xy=194.99999999999997,969.9999999999999
AudioPlaySdRaw playSdRaw9; //xy=195.00000762939453,1031.6667079925537
AudioPlaySdRaw playSdRaw10; //xy=198.3333282470703,1090.0000438690186
AudioPlaySdRaw playSdRaw5; //xy=201.66666666666663,781.6666666666665
AudioPlaySdRaw playSdRaw2; //xy=203.33333333333331,606.6666666666666
AudioPlaySdRaw playSdRaw7; //xy=203.33333333333331,916.6666666666665
AudioPlaySdRaw playSdRaw6; //xy=205,833.3333463668823
AudioPlaySdRaw playSdRaw4; //xy=206.66666666666663,721.6666666666665
AudioAmplifier amp2; //xy=333.0000457763672,605.9999933242798
AudioAmplifier amp1; //xy=334.3333740234375,554.3333101272583
AudioAmplifier amp3; //xy=337.0000534057617,664.000002861023
AudioAmplifier amp4; //xy=337.47621154785156,730.6666965484619
AudioAmplifier amp5; //xy=337.47620391845703,784.6667003631592
AudioAmplifier amp8; //xy=337,910
AudioAmplifier amp9; //xy=337.47615814208984,976.666693687439
AudioAmplifier amp10; //xy=337.4761505126953,1030.6666975021362
AudioAmplifier amp6; //xy=344.47620391845703,833.0000019073486
AudioAmplifier amp11; //xy=344.4761505126953,1078.9999990463257
AudioMixer4 mixer10; //xy=513,988
AudioMixer4 mixer8; //xy=515.4762802124023,612.8571166992188
AudioMixer4 mixer7; //xy=517.7142944335938,768.5238037109375
AudioMixer4 mixer9; //xy=681.4285888671875,719
AudioEffectFlange flange1; //xy=828.5714721679688,780.4285888671875
AudioEffectFreeverb freeverb1; //xy=833.5714721679688,701.4285888671875
AudioEffectBitcrusher bitcrusher1; //xy=838.333366394043,739.9999885559082
AudioMixer4 mixer1; //xy=980.5714721679688,734.1428833007812
AudioAmplifier amp7; //xy=1107,734.0000610351562
AudioOutputI2S i2s1; //xy=1232.571418762207,728.2857475280762
AudioConnection patchCord1(playSdRaw1, amp1);
AudioConnection patchCord2(playSdRaw3, amp3);
AudioConnection patchCord3(playSdRaw8, amp9);
AudioConnection patchCord4(playSdRaw9, amp10);
AudioConnection patchCord5(playSdRaw10, amp11);
AudioConnection patchCord6(playSdRaw5, amp5);
AudioConnection patchCord7(playSdRaw2, amp2);
AudioConnection patchCord8(playSdRaw7, amp8);
AudioConnection patchCord9(playSdRaw6, amp6);
AudioConnection patchCord10(playSdRaw4, amp4);
AudioConnection patchCord11(amp2, 0, mixer8, 1);
AudioConnection patchCord12(amp1, 0, mixer8, 0);
AudioConnection patchCord13(amp3, 0, mixer8, 2);
AudioConnection patchCord14(amp4, 0, mixer7, 0);
AudioConnection patchCord15(amp5, 0, mixer7, 1);
AudioConnection patchCord16(amp8, 0, mixer10, 0);
AudioConnection patchCord17(amp9, 0, mixer10, 1);
AudioConnection patchCord18(amp10, 0, mixer10, 2);
AudioConnection patchCord19(amp6, 0, mixer7, 2);
AudioConnection patchCord20(amp11, 0, mixer10, 3);
AudioConnection patchCord21(mixer10, 0, mixer9, 2);
AudioConnection patchCord22(mixer8, 0, mixer9, 0);
AudioConnection patchCord23(mixer7, 0, mixer9, 1);
AudioConnection patchCord24(mixer9, freeverb1);
AudioConnection patchCord25(mixer9, flange1);
AudioConnection patchCord26(mixer9, 0, mixer1, 0);
AudioConnection patchCord27(mixer9, bitcrusher1);
AudioConnection patchCord28(flange1, 0, mixer1, 3);
AudioConnection patchCord29(freeverb1, 0, mixer1, 1);
AudioConnection patchCord30(bitcrusher1, 0, mixer1, 2);
AudioConnection patchCord31(mixer1, amp7);
AudioConnection patchCord32(amp7, 0, i2s1, 0);
AudioConnection patchCord33(amp7, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=584,113
// GUItool: end automatically generated code
File root;
String padFiles[10];
int numBanksTotal;
int numBank;
bool fx1Toggle;
bool fx2Toggle;
bool fx3Toggle;
Bounce bankL = Bounce(0,5);
Bounce bankR = Bounce(1,5);
Bounce fx1 = Bounce(2,5);
Bounce fx2 = Bounce(3,5);
Bounce fx3 = Bounce(4,5);
void setup() {
// put your setup code here, to run once:
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
// Configure SPI
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
Serial.begin(9600);
//while(!Serial);
fx1Toggle=false;
fx2Toggle=false;
fx3Toggle=false;
Serial.println(AudioMemoryUsageMax());
AudioMemory(16);
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
usbMIDI.setHandleNoteOn(myNoteOn);
usbMIDI.setHandleNoteOff(myNoteOff);
numBank=0;
checkFileSystem();
setPadFiles();
setAudioSettings();
}
void setAudioSettings(){
//going to need to have all of the settings as variables that can be updated
Serial.print("FX1: ");
Serial.println(fx1Toggle);
Serial.print("FX2: ");
Serial.println(fx2Toggle);
Serial.print("FX3: ");
Serial.println(fx3Toggle);
setIndicators();
}
void checkFileSystem(){
//read the SD, are there folders? make a list of the folders
//all of the pads will be assigned, but there should be a check when loading
//print out info to the console for debug
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here, but print a message repetitively
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
root = SD.open("/");
printDirectory(root, 0);
Serial.print("number of banks found: ");
Serial.println(numBanksTotal);
}
void loop() {
// put your main code here, to run repeatedly:
checkMIDI();
checkButtons();
//Serial.println(AudioMemoryUsage());
}
void checkButtons(){
//check if the UI buttons have been pressed
bankL.update();
bankR.update();
fx1.update();
fx2.update();
fx3.update();
if(bankL.fallingEdge()){
numBank--;
if(numBank<0)numBank=numBanksTotal-1;
setPadFiles();
}
if(bankR.fallingEdge()){
numBank++;
if(numBank>=numBanksTotal)numBank=0;
setPadFiles();
}
if(fx1.fallingEdge()){
fx1Toggle=!fx1Toggle;
Serial.print("FX1: ");
Serial.println(fx1Toggle);
if(fx1Toggle)freeverb1.roomsize(0.8);
else freeverb1.roomsize(0.0);
setIndicators();
}
if(fx2.fallingEdge()){
fx2Toggle=!fx2Toggle;
Serial.print("FX2: ");
Serial.println(fx2Toggle);
if(fx2Toggle)bitcrusher1.bits(4);
else bitcrusher1.bits(16);
setIndicators();
}
if(fx3.fallingEdge()){
fx3Toggle=!fx3Toggle;
Serial.print("FX3: ");
Serial.println(fx3Toggle);
setIndicators();
}
}
void checkMIDI(){
//is there a MIDI input?
usbMIDI.read();
}
void playNote(int midiNote){
Serial.println(midiNote);
if(midiNote==60)playSdRaw1.play(padFiles[0].c_str());
if(midiNote==62)playSdRaw2.play(padFiles[1].c_str());
if(midiNote==64)playSdRaw3.play(padFiles[2].c_str());
if(midiNote==66)playSdRaw4.play(padFiles[3].c_str());
if(midiNote==70)playSdRaw5.play(padFiles[4].c_str());
if(midiNote==73)playSdRaw6.play(padFiles[5].c_str());
if(midiNote==74)playSdRaw7.play(padFiles[6].c_str());
if(midiNote==80)playSdRaw8.play(padFiles[7].c_str());
if(midiNote==80)playSdRaw9.play(padFiles[8].c_str());
if(midiNote==80)playSdRaw10.play(padFiles[9].c_str());
}
void myNoteOn(byte channel, byte note, byte velocity) {
// When using MIDIx4 or MIDIx16, usbMIDI.getCable() can be used
// to read which of the virtual MIDI cables received this message.
Serial.print("Note On, ch=");
Serial.print(channel, DEC);
Serial.print(", note=");
Serial.print(note, DEC);
Serial.print(", velocity=");
Serial.println(velocity, DEC);
playNote(int(note));
}
void myNoteOff(byte channel, byte note, byte velocity) {
Serial.print("Note Off, ch=");
Serial.print(channel, DEC);
Serial.print(", note=");
Serial.print(note, DEC);
Serial.print(", velocity=");
Serial.println(velocity, DEC);
}
void setIndicators(){
if(fx1Toggle)digitalWrite(14,HIGH);
else digitalWrite(14,LOW);
if(fx2Toggle)digitalWrite(15,HIGH);
else digitalWrite(15,LOW);
if(fx3Toggle)digitalWrite(16,HIGH);
else digitalWrite(16,LOW);
}
void setPadFiles(){
//set the pad filenames
Serial.print("pads set to bank: ");
Serial.println(numBank);
String adjNumBank;
if(numBank<10)adjNumBank="bank0"+String(numBank);
else adjNumBank = "bank"+String(numBank);
padFiles[0]=adjNumBank+"/pad0.RAW";
padFiles[1]=adjNumBank+"/pad1.RAW";
padFiles[2]=adjNumBank+"/pad2.RAW";
padFiles[3]=adjNumBank+"/pad3.RAW";
padFiles[4]=adjNumBank+"/pad4.RAW";
padFiles[5]=adjNumBank+"/pad5.RAW";
padFiles[6]=adjNumBank+"/pad6.RAW";
padFiles[7]=adjNumBank+"/pad7.RAW";
padFiles[8]=adjNumBank+"/pad8.RAW";
padFiles[9]=adjNumBank+"/pad9.RAW";
//playSdRaw1.play(padFiles[0].c_str());
//debug test
for(int i=0;i<10;i++){
Serial.println(padFiles[i]);
}
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
//Serial.print('\t');
}
//Serial.print(entry.name());
if (entry.isDirectory()) {
//Serial.println("/");
if(String(entry.name()).startsWith("BANK"))numBanksTotal++;
Serial.println(entry.name());
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
//Serial.print("\t\t");
//Serial.println(entry.size(), DEC);
}
entry.close();
}
}