vjmuzik
Well-known member
As a cool proof of concept I wanted to see how complicated it would be to read wavetables off of an SD card instead of having them be limited by the flash memory of the Teensy. Now since I'm completely unfamiliar with the audio library and I didn't want to spend too much time on this rather than trying to stream off the SD card I just copy the wavetable to ram. Although ram is definitely more limited in turns of size compared to flash memory it's more dynamic since you don't have to re-upload a new sketch to switch instruments.
I designed it so that it can read the files that are generated from the Teensy Soundfont Decoder as long as they are unmodified in every way imaginable since this is spaghetti code to a certain degree the formatting has to be spot on. The largest instrument it can handle on the Teensy 3.6 is roughly 200kb or ~80% of the ram, it should be safe to say that it can work with up to 128 different samples per instrument(I've only tested up to 22 different samples since it hit the ram limit at that point). I have tested it with numerous wavetables that were generated from the Teensy Soundfont Decoder of varying lengths just to try and make sure it was sort of robust and as long as it didn't hit the ram limit it didn't have any issues.
So the way this works is you put the wavetable files on a SD card, then put it in your Teensy and use the serial monitor to select your file, if you don't know the names of your files you can type "ls" to list the files on the SD card, then you can just copy and paste the "*.cpp" file into the serial monitor. It will automatically search for the corresponding "*.h" file and it will fail if it is not found so make sure both are on the card, it will freeze if you try to put the "*.h" file in the serial monitor since I didn't put in any way to check.
I'm going to include the library files and some sample wavetables I used with this since I had to slightly modify the SD library so the Audio library didn't complain about using the SdFat Beta library.
I can only guarantee that this is working on a Teensy 3.6 using the builtin SD card slot since I know it will have to be modified to work with the other boards and the RamMonitor library doesn't work with a Teensy 4.0.
All that being said, to keep things simple, I left this as only one voice so I didn't make it too complicated on myself but it could definitely be expanded to multi voice and multi instrument if anyone is up for the challenge.
SdFat Beta Library
RamMonitor Library
View attachment SD-modified.zip
View attachment sample wavetables.zip
I designed it so that it can read the files that are generated from the Teensy Soundfont Decoder as long as they are unmodified in every way imaginable since this is spaghetti code to a certain degree the formatting has to be spot on. The largest instrument it can handle on the Teensy 3.6 is roughly 200kb or ~80% of the ram, it should be safe to say that it can work with up to 128 different samples per instrument(I've only tested up to 22 different samples since it hit the ram limit at that point). I have tested it with numerous wavetables that were generated from the Teensy Soundfont Decoder of varying lengths just to try and make sure it was sort of robust and as long as it didn't hit the ram limit it didn't have any issues.
So the way this works is you put the wavetable files on a SD card, then put it in your Teensy and use the serial monitor to select your file, if you don't know the names of your files you can type "ls" to list the files on the SD card, then you can just copy and paste the "*.cpp" file into the serial monitor. It will automatically search for the corresponding "*.h" file and it will fail if it is not found so make sure both are on the card, it will freeze if you try to put the "*.h" file in the serial monitor since I didn't put in any way to check.
I'm going to include the library files and some sample wavetables I used with this since I had to slightly modify the SD library so the Audio library didn't complain about using the SdFat Beta library.
I can only guarantee that this is working on a Teensy 3.6 using the builtin SD card slot since I know it will have to be modified to work with the other boards and the RamMonitor library doesn't work with a Teensy 4.0.
All that being said, to keep things simple, I left this as only one voice so I didn't make it too complicated on myself but it could definitely be expanded to multi voice and multi instrument if anyone is up for the challenge.
SdFat Beta Library
RamMonitor Library
View attachment SD-modified.zip
View attachment sample wavetables.zip
Code:
#include "SdFat.h"
#include "RamMonitor.h"
#include <Audio.h>
AudioSynthWavetable wavetable; //xy=107,296
AudioInputUSB usb2; //xy=127,230
AudioOutputUSB usb1; //xy=410,291
AudioOutputAnalogStereo dacs1; //xy=527,341
AudioMixer4 mixer2; //xy=291,319
AudioMixer4 mixer1; //xy=294,238
AudioConnection patchCord1(wavetable, 0, mixer1, 1);
AudioConnection patchCord2(wavetable, 0, mixer2, 1);
AudioConnection patchCord3(usb2, 0, mixer1, 0);
AudioConnection patchCord4(usb2, 1, mixer2, 0);
AudioConnection patchCord5(mixer2, 0, usb1, 1);
AudioConnection patchCord6(mixer2, 0, dacs1, 1);
AudioConnection patchCord7(mixer1, 0, usb1, 0);
AudioConnection patchCord8(mixer1, 0, dacs1, 0);
RamMonitor ram;
SdFs sd;
FsFile dir;
FsFile file;
struct sample_data{
// SAMPLE VALUES
int16_t* sample;
bool LOOP;
int INDEX_BITS;
float PER_HERTZ_PHASE_INCREMENT;
uint32_t MAX_PHASE;
uint32_t LOOP_PHASE_END;
uint32_t LOOP_PHASE_LENGTH;
uint16_t INITIAL_ATTENUATION_SCALAR;
// VOLUME ENVELOPE VALUES
uint32_t DELAY_COUNT;
uint32_t ATTACK_COUNT;
uint32_t HOLD_COUNT;
uint32_t DECAY_COUNT;
uint32_t RELEASE_COUNT;
int32_t SUSTAIN_MULT;
// VIRBRATO VALUES
uint32_t VIBRATO_DELAY;
uint32_t VIBRATO_INCREMENT;
float VIBRATO_PITCH_COEFFICIENT_INITIAL;
float VIBRATO_PITCH_COEFFICIENT_SECOND;
// MODULATION VALUES
uint32_t MODULATION_DELAY;
uint32_t MODULATION_INCREMENT;
float MODULATION_PITCH_COEFFICIENT_INITIAL;
float MODULATION_PITCH_COEFFICIENT_SECOND;
int32_t MODULATION_AMPLITUDE_INITIAL_GAIN;
int32_t MODULATION_AMPLITUDE_SECOND_GAIN;
};
sample_data *instrument_0_sample_data;
struct instrument_data {
uint8_t sample_count;
uint8_t* sample_note_ranges;
sample_data* samples;
};
instrument_data *instrument_0_data = NULL;
uint32_t instrument_0_samples = 0;
uint32_t **instrument_0;
uint32_t instrument_0_sample_length = 0;
uint8_t *instrument_0_ranges;
char *instrument_0_header;
void setup() {
AudioMemory(20);
mixer1.gain(0, 1);
mixer1.gain(1, 1);
mixer2.gain(0, 1);
mixer2.gain(1, 1);
mixer1.gain(3, .1);
mixer2.gain(3, .1);
Serial.begin(9600);
ram.initialize();
wavetable.amplitude(1);
usbMIDI.setHandleNoteOn(onNoteOn);
usbMIDI.setHandleNoteOff(onNoteOff);
// Wait for USB Serial
while(true){
START:
if(file.isOpen()) file.close();
if(dir.isOpen()) dir.close();
while (!Serial) {
yield();
}
Serial.println("Type file name to start");
report_ram();
while (!Serial.available()) {
yield();
usbMIDI.read();
}
char file_name[256] = {};
Serial.readBytes(file_name, Serial.available());
if (!sd.begin(BUILTIN_SDCARD)) {
// sd.initErrorHalt(&Serial);
Serial.print("SD begin error!: ");
Serial.println(sd.card()->errorCode());
printSdErrorText(&Serial, sd.card()->errorCode());
Serial.println();
sd.end();
goto START;
return;
}
if (!dir.open("/")){
Serial.println("Dir open failed!");
Serial.print("Error code: ");
Serial.println(sd.card()->errorCode());
printSdErrorText(&Serial, sd.card()->errorCode());
Serial.println();
goto START;
}
if(file_name[0] == 'l' && file_name[1] == 's'){
dir.ls(&Serial);
goto START;
}
Serial.print("Trying to open \"");
Serial.print(file_name);
Serial.println("\"");
if(dir.exists(file_name)){
if (!file.open(file_name, O_RDONLY)) {
Serial.println("File open failed!");
goto START;
}
}
else {
file.close();
Serial.println("File not found!");
goto START;
}
PARSE_HEADER:
wavetable.stop();
while (file.available()) {
char c = (char)file.read();
if(c == '\n') Serial.print("\\n");
if(c == '\t') Serial.print("\\t");
if(c == '\0') Serial.print("\\0");
Serial.print(c);
}
// Serial.println();
file.rewind();
AudioNoInterrupts();
while (file.available()) {
char c = (char)file.read();
if(c == 'c' && file.read() == 'o' && file.read() == 'n' && file.read() == 's' && file.read() == 't' && file.read() == ' '){
c = (char)file.read();
if((c == 'A' && file.read() == 'u' && file.read() == 'd' && file.read() == 'i' && file.read() == 'o' && file.read() == 'S' && file.read() == 'y' && file.read() == 'n' && file.read() == 't' && file.read() == 'h' && file.read() == 'W' && file.read() == 'a' && file.read() == 'v' && file.read() == 'e' && file.read() == 't' && file.read() == 'a' && file.read() == 'b' && file.read() == 'l' && file.read() == 'e' && file.read() == ':' && file.read() == ':' && file.read() == 's') || (c == 's' && file.read() == 'a' && file.read() == 'm' && file.read() == 'p' && file.read() == 'l' && file.read() == 'e' && file.read() == '_' && file.read() == 'd' && file.read() == 'a' && file.read() == 't' && file.read() == 'a')){//Search for sample data
c = (char)file.read();
while(c != '['){//Advance to number of samples
c = (char)file.read();
}
if(c == '['){//Read number of samples and initailize instrument
char num[8];
char delim[] = "]";
char* ptr = delim;
file.fgets(num, sizeof(num), delim);
if(instrument_0_samples){//Delete previous instrument
wavetable.setInstrument(*((AudioSynthWavetable::instrument_data*)NULL));
for(uint8_t i = 0; i < instrument_0_samples; i++){
Serial.print("Deleting old: ");
Serial.println(i);
delete [] instrument_0[i];
}
delete [] instrument_0;
delete [] instrument_0_sample_data;
delete [] instrument_0_data;
delete [] instrument_0_ranges;
}
instrument_0_samples = strtoul(num, &ptr, 10);
Serial.print("Number of samples: ");
Serial.println(instrument_0_samples);
instrument_0 = new uint32_t*[instrument_0_samples];
instrument_0_sample_data = new sample_data[instrument_0_samples];
instrument_0_data = new instrument_data;
instrument_0_data->sample_count = (uint8_t)instrument_0_samples;
instrument_0_data->samples = instrument_0_sample_data;
instrument_0_ranges = new uint8_t[instrument_0_samples];
}
c = 0;
while(c != '{'){//Advance to start of sample data
c = (char)file.read();
}
uint8_t samples = 0;
while(samples != instrument_0_samples){//Parse sample data
c = 0;
while(c != '{'){//Advance to start of sample data
c = (char)file.read();
}
file.read();//Skip \n
c = 0;
while(c != '\n'){//Skip already initialized pointer
c = (char)file.read();
}
file.read();//Skip \t
file.read();//Skip \t
c = (char)file.read();//Read LOOP variable
if(c == 't') instrument_0_sample_data[samples].LOOP = true;//Set LOOP variable
else instrument_0_sample_data[samples].LOOP = false;
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
file.read();//Skip \t
file.read();//Skip \t
char num[12];
char delim[2] = ",";
char* ptr = delim;
int16_t data1,data2,data3,data4,data5,data6,data7,data8;
float float1,float2;
file.fgets(num, sizeof(num), delim);//Read INDEX_BITS variable
instrument_0_sample_data[samples].INDEX_BITS = strtol(num, &ptr, 10);//Set INDEX_BITS variable
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
if(true){//Read line for PER_HERTZ_PHASE_INCREMENT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT variable 2
data2 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT variable 3
data3 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to fourth data
c = (char)file.read();
}
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT variable 4
data4 = strtol(num, &ptr, 10);
c = 0;
while(c != '*'){//Advance to first float
c = (char)file.read();
}
file.read();
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to fifth data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT variable 5
data5 = strtol(num, &ptr, 10);
c = 0;
while(c != '+'){//Advance to second float
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read PER_HERTZ_PHASE_INCREMENT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].PER_HERTZ_PHASE_INCREMENT = (data1 << (data2 - data3)) * WAVETABLE_CENTS_SHIFT(data4) * float1 / WAVETABLE_NOTE_TO_FREQUENCY(data5) / AUDIO_SAMPLE_RATE_EXACT + float2;//Set PER_HERTZ_PHASE_INCREMENT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MAX_PHASE
c = 0;
while(c != ')'){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MAX_PHASE variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MAX_PHASE variable 2
data2 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to third data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MAX_PHASE variable 3
data3 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to fourth data
c = (char)file.read();
}
file.read();
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MAX_PHASE variable 4
data4 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MAX_PHASE = ((uint32_t)data1 - data2) << (data3 - data4);//Set MAX_PHASE
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for LOOP_PHASE_END
c = 0;
while(c != ')'){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_END variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_END variable 2
data2 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to third data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_END variable 3
data3 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to fourth data
c = (char)file.read();
}
file.read();
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_END variable 4
data4 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].LOOP_PHASE_END = ((uint32_t)data1 - data2) << (data3 - data4);//Set LOOP_PHASE_END
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for LOOP_PHASE_LENGTH
c = 0;
while(c != ')'){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 2
data2 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to third data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 3
data3 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to fourth data
c = (char)file.read();
}
file.read();
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 4
data4 = strtol(num, &ptr, 10);
file.read();
file.read();
c = 0;
while(c != ')'){//Advance to fifth data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 5
data5 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to sixth data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 6
data6 = strtol(num, &ptr, 10);
c = 0;
while(c != '('){//Advance to seventh data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 7
data7 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to eigth data
c = (char)file.read();
}
file.read();
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read LOOP_PHASE_LENGTH variable 8
data8 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].LOOP_PHASE_LENGTH = (((uint32_t)data1 - data2) << (data3 - data4)) - (((uint32_t)data5 - data6) << (data7 - data8));//Set LOOP_PHASE_LENGTH
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for INITIAL_ATTENUATION_SCALAR
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read INITIAL_ATTENUATION_SCALAR float 1
float1 = strtof(num, &ptr);
instrument_0_sample_data[samples].INITIAL_ATTENUATION_SCALAR = uint16_t(UINT16_MAX * WAVETABLE_DECIBEL_SHIFT(float1));//Set INITIAL_ATTENUATION_SCALAR
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for DELAY_COUNT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read DELAY_COUNT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '+'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read DELAY_COUNT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].DELAY_COUNT = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / AudioSynthWavetable::ENVELOPE_PERIOD + float2);//Set DELAY_COUNT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for ATTACK_COUNT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read ATTACK_COUNT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '+'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read ATTACK_COUNT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].ATTACK_COUNT = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / AudioSynthWavetable::ENVELOPE_PERIOD + float2);//Set ATTACK_COUNT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for HOLD_COUNT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read HOLD_COUNT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '+'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read HOLD_COUNT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].HOLD_COUNT = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / AudioSynthWavetable::ENVELOPE_PERIOD + float2);//Set HOLD_COUNT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for DECAY_COUNT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read DECAY_COUNT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '+'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read DECAY_COUNT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].DECAY_COUNT = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / AudioSynthWavetable::ENVELOPE_PERIOD + float2);//Set DECAY_COUNT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for RELEASE_COUNT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read RELEASE_COUNT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '+'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read RELEASE_COUNT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].RELEASE_COUNT = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / AudioSynthWavetable::ENVELOPE_PERIOD + float2);//Set RELEASE_COUNT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for SUSTAIN_MULT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
file.read();
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read SUSTAIN_MULT float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read SUSTAIN_MULT float 2
float2 = strtof(num, &ptr);
instrument_0_sample_data[samples].SUSTAIN_MULT = int32_t((float1 - WAVETABLE_DECIBEL_SHIFT(float2)) * AudioSynthWavetable::UNITY_GAIN);//Set SUSTAIN_MULT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for VIBRATO_DELAY
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_DELAY float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_DELAY variable 1
data1 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].VIBRATO_DELAY = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / (data1 * AudioSynthWavetable::LFO_PERIOD));//Set VIBRATO_DELAY
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for VIBRATO_INCREMENT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_INCREMENT float 1
float1 = strtof(num, &ptr);
instrument_0_sample_data[samples].VIBRATO_INCREMENT = uint32_t(float1 * AudioSynthWavetable::LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));//Set VIBRATO_INCREMENT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for VIBRATO_PITCH_COEFFICIENT_INITIAL
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_INITIAL variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_INITIAL float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_INITIAL variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].VIBRATO_PITCH_COEFFICIENT_INITIAL = (WAVETABLE_CENTS_SHIFT(data1) - float1) * data2;//Set VIBRATO_PITCH_COEFFICIENT_INITIAL
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for VIBRATO_PITCH_COEFFICIENT_SECOND
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_SECOND float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_SECOND variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read VIBRATO_PITCH_COEFFICIENT_SECOND variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].VIBRATO_PITCH_COEFFICIENT_SECOND = (float1 - WAVETABLE_CENTS_SHIFT(data1)) * data2;//Set VIBRATO_PITCH_COEFFICIENT_SECOND
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_DELAY
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_DELAY float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_DELAY variable 1
data1 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MODULATION_DELAY = uint32_t(float1 * AudioSynthWavetable::SAMPLES_PER_MSEC / (data1 * AudioSynthWavetable::LFO_PERIOD));//Set MODULATION_DELAY
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_INCREMENT
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_INCREMENT float 1
float1 = strtof(num, &ptr);
instrument_0_sample_data[samples].MODULATION_INCREMENT = uint32_t(float1 * AudioSynthWavetable::LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));//Set MODULATION_INCREMENT
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_PITCH_COEFFICIENT_INITIAL
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_INITIAL variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_INITIAL float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_INITIAL variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MODULATION_PITCH_COEFFICIENT_INITIAL = (WAVETABLE_CENTS_SHIFT(data1) - float1) * data2;//Set MODULATION_PITCH_COEFFICIENT_INITIAL
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_PITCH_COEFFICIENT_SECOND
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_SECOND float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_SECOND variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_PITCH_COEFFICIENT_SECOND variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MODULATION_PITCH_COEFFICIENT_SECOND = (float1 - WAVETABLE_CENTS_SHIFT(data1)) * data2;//Set MODULATION_PITCH_COEFFICIENT_SECOND
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_AMPLITUDE_INITIAL_GAIN
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_INITIAL_GAIN variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '-'){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_INITIAL_GAIN float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_INITIAL_GAIN variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MODULATION_AMPLITUDE_INITIAL_GAIN = int32_t(UINT16_MAX * (WAVETABLE_DECIBEL_SHIFT(data1) - float1)) * data2;//Set MODULATION_AMPLITUDE_INITIAL_GAIN
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
if(true){//Read line for MODULATION_PITCH_COEFFICIENT_SECOND
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
c = 0;
while(c != '('){//Advance to first data
c = (char)file.read();
}
delim[0] = ' ';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_SECOND_GAIN float 1
float1 = strtof(num, &ptr);
c = 0;
while(c != '('){//Advance to second data
c = (char)file.read();
}
file.read();
delim[0] = ')';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_SECOND_GAIN variable 1
data1 = strtol(num, &ptr, 10);
c = 0;
while(c != '*'){//Advance to third data
c = (char)file.read();
}
file.read();
delim[0] = ',';
ptr = delim;
file.fgets(num, sizeof(num), delim);//Read MODULATION_AMPLITUDE_SECOND_GAIN variable 2
data2 = strtol(num, &ptr, 10);
instrument_0_sample_data[samples].MODULATION_AMPLITUDE_SECOND_GAIN = int32_t(UINT16_MAX * (float1 - WAVETABLE_DECIBEL_SHIFT(data1))) * data2;//Set MODULATION_AMPLITUDE_SECOND_GAIN
c = 0;
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
// Serial.print("data1: ");
// Serial.println(data1);
// Serial.print("data2: ");
// Serial.println(data2);
// Serial.print("data3: ");
// Serial.println(data3);
// Serial.print("data4: ");
// Serial.println(data4);
// Serial.print("data5: ");
// Serial.println(data5);
// Serial.print("data6: ");
// Serial.println(data6);
// Serial.print("data7: ");
// Serial.println(data7);
// Serial.print("data8: ");
// Serial.println(data8);
// Serial.print("float1: ");
// Serial.println(float1);
// Serial.print("float2: ");
// Serial.println(float2);
Serial.print("LOOP: ");
Serial.println(instrument_0_sample_data[samples].LOOP);
Serial.print("INDEX_BITS: ");
Serial.println(instrument_0_sample_data[samples].INDEX_BITS);
Serial.print("PER_HERTZ_PHASE_INCREMENT: ");
Serial.println(instrument_0_sample_data[samples].PER_HERTZ_PHASE_INCREMENT);
Serial.print("MAX_PHASE: ");
Serial.println(instrument_0_sample_data[samples].MAX_PHASE);
Serial.print("LOOP_PHASE_END: ");
Serial.println(instrument_0_sample_data[samples].LOOP_PHASE_END);
Serial.print("LOOP_PHASE_LENGTH: ");
Serial.println(instrument_0_sample_data[samples].LOOP_PHASE_LENGTH);
Serial.print("INITIAL_ATTENUATION_SCALAR: ");
Serial.println(instrument_0_sample_data[samples].INITIAL_ATTENUATION_SCALAR);
Serial.print("DELAY_COUNT: ");
Serial.println(instrument_0_sample_data[samples].DELAY_COUNT);
Serial.print("ATTACK_COUNT: ");
Serial.println(instrument_0_sample_data[samples].ATTACK_COUNT);
Serial.print("HOLD_COUNT: ");
Serial.println(instrument_0_sample_data[samples].HOLD_COUNT);
Serial.print("DECAY_COUNT: ");
Serial.println(instrument_0_sample_data[samples].DECAY_COUNT);
Serial.print("RELEASE_COUNT: ");
Serial.println(instrument_0_sample_data[samples].RELEASE_COUNT);
Serial.print("SUSTAIN_MULT: ");
Serial.println(instrument_0_sample_data[samples].SUSTAIN_MULT);
Serial.print("VIBRATO_DELAY: ");
Serial.println(instrument_0_sample_data[samples].VIBRATO_DELAY);
Serial.print("VIBRATO_INCREMENT: ");
Serial.println(instrument_0_sample_data[samples].VIBRATO_INCREMENT);
Serial.print("VIBRATO_PITCH_COEFFICIENT_INITIAL: ");
Serial.println(instrument_0_sample_data[samples].VIBRATO_PITCH_COEFFICIENT_INITIAL);
Serial.print("VIBRATO_PITCH_COEFFICIENT_SECOND: ");
Serial.println(instrument_0_sample_data[samples].VIBRATO_PITCH_COEFFICIENT_SECOND);
Serial.print("MODULATION_DELAY: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_DELAY);
Serial.print("MODULATION_INCREMENT: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_INCREMENT);
Serial.print("MODULATION_PITCH_COEFFICIENT_INITIAL: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_PITCH_COEFFICIENT_INITIAL);
Serial.print("MODULATION_PITCH_COEFFICIENT_SECOND: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_PITCH_COEFFICIENT_SECOND);
Serial.print("MODULATION_AMPLITUDE_INITIAL_GAIN: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_AMPLITUDE_INITIAL_GAIN);
Serial.print("MODULATION_AMPLITUDE_SECOND_GAIN: ");
Serial.println(instrument_0_sample_data[samples].MODULATION_AMPLITUDE_SECOND_GAIN);
samples++;
}
}
else if(c == 'u' && file.read() == 'i' && file.read() == 'n' && file.read() == 't' && file.read() == '3' && file.read() == '2' && file.read() == '_' && file.read() == 't'){//Search for samples
c = (char)file.read();
while(c != '_'){//Advance to Sample Number
c = (char)file.read();
}
uint8_t current_sample = 0;
if(c == '_'){//Read Sample Number
char num[8];
char delim[] = "_";
char* ptr = delim;
file.fgets(num, sizeof(num), delim);
Serial.print("Sample number: ");
// Serial.println(num);
current_sample = strtoul(num, &ptr, 10);
Serial.println(current_sample);
}
while(c != '['){//Advance to Sample Length
c = (char)file.read();
}
if(c == '['){//Read Sample Length
char num[8];
char delim[] = "]";
char* ptr = delim;
file.fgets(num, sizeof(num), delim);
Serial.print("Sample size: ");
// Serial.println(num);
instrument_0_sample_length = strtoul(num, &ptr, 10);
Serial.println(instrument_0_sample_length);
}
while(c != '{'){//Advance to sample
c = (char)file.read();
}
if(c == '{'){//Read Sample
file.read();
uint32_t samples = 0;
char num[12];
char delim[] = ",";
char* ptr = delim;
Serial.print("Samples: ");
// Serial.println(num);
instrument_0[current_sample] = new uint32_t[instrument_0_sample_length];
while(samples != instrument_0_sample_length){
while(file.peek() == '\n') file.read();
if(file.peek() == '}') break;
file.fgets(num, sizeof(num), delim);
instrument_0[current_sample][samples] = strtoul(num, &ptr, 16);
Serial.print(instrument_0[current_sample][samples], HEX);
Serial.print(", ");
samples++;
}
Serial.println();
instrument_0_sample_data[current_sample].sample = (int16_t*)instrument_0[current_sample];
report_ram();
}
}
else if(file.read() == '_' && file.read() == 't'){//Search for key ranges
while(c != '{'){//Advance to next line
c = (char)file.read();
}
uint8_t samples = 0;
char num[8];
char delim[] = ",";
char* ptr = delim;
while(samples != instrument_0_samples){
file.fgets(num, sizeof(num), delim);
instrument_0_ranges[samples] = (uint8_t)strtol(num, &ptr, 10);
samples++;
}
instrument_0_data->sample_note_ranges = instrument_0_ranges;
wavetable.setInstrument(*((AudioSynthWavetable::instrument_data*)instrument_0_data));
delete [] instrument_0_header;
instrument_0_header = NULL;
break;
}
}
else if(c == 'i' && file.read() == 'n' && file.read() == 'c' && file.read() == 'l' && file.read() == 'u' && file.read() == 'd' && file.read() == 'e' && file.read() == ' ' && file.read() == '\"'){
instrument_0_header = new char[256];
char delim[] = "\"";
uint8_t header_length = file.fgets(instrument_0_header, 256, delim);
instrument_0_header[header_length-1] = '\0';
Serial.print("Header file: ");
Serial.println(instrument_0_header);
}
else if(c == 'e' && file.read() == 'x' && file.read() == 't' && file.read() == 'e' && file.read() == 'r' && file.read() == 'n'){
while(c != '\n'){//Advance to next line
c = (char)file.read();
}
}
}
file.close();
AudioInterrupts();
if(instrument_0_header != NULL){
Serial.print("Header detected! ");
Serial.println(instrument_0_header);
if(dir.exists(instrument_0_header)){
if (!file.open(instrument_0_header, O_RDONLY)) {
Serial.println("Header not found!");
delete [] instrument_0_header;
instrument_0_header = NULL;
goto START;
}
else goto PARSE_HEADER;
}
else Serial.println("Header does not exist!");
}
Serial.println(F("Done"));
dir.close();
}
}
void loop() {
}
void report_ram_stat(const char* aname, uint32_t avalue){
Serial.print(aname);
Serial.print(": ");
Serial.print(avalue);
Serial.print(" b (");
Serial.print((((float) avalue) / ram.total()) * 100, 1);
Serial.println("%)");
}
void report_ram(){
ram.run();
bool lowmem;
bool crash;
Serial.println("==== memory report ====");
report_ram_stat("free", ram.adj_free());
report_ram_stat("stack total", ram.stack_total());
report_ram_stat("heap used", ram.heap_used());
report_ram_stat("heap total", ram.heap_total());
lowmem = ram.warning_lowmem();
crash = ram.warning_crash();
if(lowmem || crash) {
Serial.println();
if(crash) Serial.println("**warning: stack and heap crash possible");
else if(lowmem) Serial.println("**warning: unallocated memory running low");
}
Serial.println();
}
void onNoteOn(uint8_t channel, uint8_t note, uint8_t velocity){
Serial.println("NoteOn");
if(instrument_0_data != NULL) wavetable.playNote(note, velocity);
Serial.print("CPU: ");
Serial.print(" ");
Serial.print("wavetable=");
Serial.print(wavetable.processorUsage());
Serial.print(",");
Serial.print(wavetable.processorUsageMax());
Serial.print(" ");
Serial.print("all=");
Serial.print(AudioProcessorUsage());
Serial.print(",");
Serial.print(AudioProcessorUsageMax());
Serial.print(" ");
Serial.print("Memory: ");
Serial.print(AudioMemoryUsage());
Serial.print(",");
Serial.print(AudioMemoryUsageMax());
Serial.println();
Serial.print("Key ranges: ");
for(uint8_t i = 0; i < instrument_0_data->sample_count; i++){
Serial.print(instrument_0_data->sample_note_ranges[i]);
Serial.print(", ");
}
Serial.println();
}
void onNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){
Serial.println("NoteOff");
wavetable.stop();
Serial.print("CPU: ");
Serial.print(" ");
Serial.print("wavetable=");
Serial.print(wavetable.processorUsage());
Serial.print(",");
Serial.print(wavetable.processorUsageMax());
Serial.print(" ");
Serial.print("all=");
Serial.print(AudioProcessorUsage());
Serial.print(",");
Serial.print(AudioProcessorUsageMax());
Serial.print(" ");
Serial.print("Memory: ");
Serial.print(AudioMemoryUsage());
Serial.print(",");
Serial.print(AudioMemoryUsageMax());
Serial.println();
}