Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 14 of 14

Thread: Wavetable Synthesis From SD Card

  1. #1
    Senior Member vjmuzik's Avatar
    Join Date
    Apr 2017
    Posts
    686

    Wavetable Synthesis From SD Card

    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
    SD-modified.zip
    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();
    }

  2. #2
    Senior Member
    Join Date
    Feb 2015
    Posts
    217
    As a proof of concept, I think this is really cool! It would be awesome if there was an established file format for this that worked well for embedded use. I mean I guess you could parse the sf2 file but the overhead seems prohibitive.

  3. #3
    Senior Member vjmuzik's Avatar
    Join Date
    Apr 2017
    Posts
    686
    The established format is the files generated from the Teensy Soundfont Decoder, which as the name suggest converts soundfonts into the correct format that I’m parsing. I’ve tested it with at least 2-3 dozen different sounds generated with the program so I at least know it’s consistent between each generation that my parsing doesn’t catch any error that I know of.

  4. #4
    Senior Member
    Join Date
    Feb 2015
    Posts
    217
    Sorry, I didn't mean to sound pedantic or try to take away from your accomplishment. I think it's awesome, great job

  5. #5
    Senior Member vjmuzik's Avatar
    Join Date
    Apr 2017
    Posts
    686
    No I get what you were going for and I do agree there is probably a better format that could be used like directly reading soundfont files, but at the time I figured it was easier to use the same wavetable files that were already being used with the audio library since they were already in the needed format. Otherwise I would’ve had to basically rebuild the Teensy Soundfont Decoder in my code which seemed like overkill and unnecessary since the desktop version already does its job well.

  6. #6
    Junior Member
    Join Date
    Nov 2019
    Posts
    6
    Quote Originally Posted by vjmuzik View Post
    No I get what you were going for and I do agree there is probably a better format that could be used like directly reading soundfont files, but at the time I figured it was easier to use the same wavetable files that were already being used with the audio library since they were already in the needed format. Otherwise I would’ve had to basically rebuild the Teensy Soundfont Decoder in my code which seemed like overkill and unnecessary since the desktop version already does its job well.
    I've been trying to do this for my T4 drum machine project and have so far been able to load a .WAV file as a soundfont (using the soundfont header).
    My loader currently only supports 44100 hz 8/16/24/32 bit uncompressed PCM but it works!.

    I found problems when trying to stream from the SD card, mainly interference can be heard from the audio board (which isn't good if you want to record in the studio) and I'm still searching for a solution.. The Teensy 4.0 has LOTS more memory/power compared to the DUE is was originally using but when you start loading samples you run out quickly


    Code below (it's a bit messy but works feel free to mod for your needs)...

    I used the SDfat Lib.



    Headers...
    "wavstuff.h"
    Code:
    /* Taken from Wav2Sketch */
    // compute the extra padding needed
    #pragma once
    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;
    };
    
    struct instrument_data {
       uint8_t sample_count;
       uint8_t* sample_note_ranges;
       sample_data* samples;
    };
    
    uint32_t padding(uint32_t length, uint32_t block) {
      uint32_t extra;
      extra = length % block;
      if (extra == 0) return 0;
      return block - extra;
    }
    
    struct SubChunkHeader {
      uint32_t id;
      uint32_t size;
    };
    // based on: http://soundfile.sapp.org/doc/WaveFormat/
    struct WaveFileHeader {
      uint32_t chunkId;
      uint32_t chunkSize;
      uint32_t format;
      struct {
        struct SubChunkHeader header;
        uint16_t audioFormat;
        uint16_t numChannels;
        uint32_t sampleRate;
        uint32_t byteRate;
        uint16_t blockAlign;
        uint16_t bitsPerSample;
      } subChunk1;
      struct SubChunkHeader subChunk2Header;
    } __attribute__((packed));
    The loader...
    Code:
    #include "wavstuff.h"
    
    #include "SdFat.h"
    //so we just allocate a chunk of memory with this as the header...
    //load the wav PCM data at the end and then point to it!
    //AudioSynthWavetable inst1;
    //instrument_data
    uint16_t clip32to16(float indata2) {
      //Constrained<float> constrainedFloat( indata2 , -1.0 , 1.0 );
      //float tf = constrainedFloat;
      //uint16_t oo = tf  * 32767.0f;
      //uint16_t oo = indata2  * 32767.0f;
      return ( indata2  * 32767.0f);
    }
    float clip16to32(uint16_t indata2) {
      //uint16_t oo = indata2  * 32767.0f;
      return (indata2  / 32767.0f);
    }
    sample_data * loadSampleAsInstrument(uint8_t base_note, const char *f) { /* load a wav and convert to teensy wavetable format */
      /* need to add sountfont conversion as its the only way i know how to add pitch change */
    
      WaveFileHeader header;
      SubChunkHeader sch;
      int16_t format;
      uint32_t length, padlength = 0;
      int arraylen = 0;
      int subChunk2Offset = 0;
      int headersize = sizeof(WaveFileHeader) - sizeof(SubChunkHeader);
      boolean headergood = 0;
      File32 tmpf;
    
      __disable_irq();
      //AudioNoInterrupts();
      tmpf.open(f);
    
      if (tmpf == 0) {
        tmpf.close();
        __enable_irq();
        //AudioInterrupts();
        return 0; //some problem happenend
      }
    
      if (tmpf.read(&header, headersize) < headersize) {
        tmpf.close();
        __enable_irq();
        // AudioInterrupts();
        return 0; //some problem happenend
      }
    
      //AudioInterrupts();
      header.chunkId = __REV(header.chunkId);
      header.format = __REV(header.format);
      header.subChunk1.header.id = __REV(header.subChunk1.header.id);
    
    
      while (tmpf.available()) {
        //tmpf.read((void *) & (sch), sizeof(sch));
     //Serial.print("reading..");
     // Serial.println(tmpf.curPosition() );
      
        if (tmpf.read((void *) & (sch), sizeof(sch)) != sizeof(sch)) {
          tmpf.close();
          __enable_irq();
          //AudioInterrupts();
          //we have a problem here!
          return 0;
        }
    
        sch.id = __REV(sch.id);
        //sch.size = __REV(sch.size);
        if (sch.id == 0x64617461) {
          // found the data section
          header.subChunk2Header.id = sch.id;
          header.subChunk2Header.size = sch.size;
          headergood = 1;
          break;
        } else {
          //if (sch.size == 0) {tmpf.seekCur}
          tmpf.seekCur(__REV(sch.size)); /* have to reverse edianess ?? */
        }
      }
    
      if (!headergood) {
        tmpf.close();
        __enable_irq();
        //AudioInterrupts();
        //Serial.print("wav no good!");
        return 0;
      }
      //AudioInterrupts();
      //Serial.print("sample rate:");
      Serial.println(header.subChunk1.sampleRate);
      //uses code from teensy audio's wav2sketch
      // AudioPlayMemory requires padding to 2.9 ms boundary (128 samples @ 44100)
      length = header.subChunk2Header.size;
    
      // data.dwMinLength = (data.dwChunkSize / format.dwAvgBytesPerSec) / 60;
      //data.dSecLength = ((double)data.dwChunkSize / (double)format.dwAvgBytesPerSec) - (double)data.dwMinLength*60;
      padlength = 0;
      // the length must be a multiple of the data size
      if (header.subChunk1.numChannels == 2) {
        if (length % 4) {
          // Serial.print(length);
          // Serial.println("length isnt % 4");  //("file %s data length is not a multiple of 4", filename);
        }
        length = length / 4;
      }
      if (header.subChunk1.numChannels == 1) {
        if (length % 1) {
    
          //Serial.println("length isnt % 2");
    
        }
        //if (length % 1) die("file %s data length is not a multiple of 2", filename);
        length = length / 2;
      }
      if (header.subChunk1.sampleRate == 44100) {
        padlength += padding(length, 128);
        format = 1;
      } else if (header.subChunk1.sampleRate == 22050) {
        padlength += padding(length, 64);
        format = 2;
      } else if (header.subChunk1.sampleRate == 11025) {
        padlength += padding(length, 32);
        format = 3;
      }
      arraylen = ((length + padlength) * 2 + 3) / 4 + 1;
      //len(f) / f.samplerate)
      //Serial.print ("wav size ms:");
      //Serial.println(arraylen / header.subChunk1.sampleRate);
      format |= 0x80;
    
      int memneeded = sizeof(sample_data) + (arraylen * 4);
      //int memneeded = sizeof(instrument_data) + (arraylen * 4);
      //noInterrupts();
      uint8_t * memptr = (uint8_t *) malloc(memneeded);
      uint8_t * sampdatastart = memptr + sizeof(sample_data);//+ sizeof(instrument_data);
      if (!memptr) {
        Serial.println("sample is too big");  /*no memory left */
        __enable_irq();
        //AudioInterrupts();
        //interrupts();
        return 0;
      }
      memset(memptr, 0, memneeded);
      //interrupts();
      //uint8_t * mem8ptr =  memptr + 4;
      uint16_t * mem16ptr = (uint16_t *) sampdatastart ;//(uint16_t *) memptr + 2;
      uint32_t * mem32ptr =  (uint32_t *) sampdatastart;
      uint32_t flen = ((length - padlength)  | (format << 24));
      // *mem32ptr++ = flen; dont need
      int len = flen;
      int LENGTH_BITS = 16;
      int LENGTH = len;
      int LOOPEND = LENGTH - 1;
      int LOOPSTART = 0;
    
    
      sample_data NULL_SAMPLE =
      {
        (int16_t*)sampdatastart, //16-bit PCM encoded audio sample -- location = memory + sizeof(_sample_data)
        false, //Whether or not to loop this sample
        LENGTH_BITS,  //Number of bits needed to hold length
        ((0x80000000 >> (LENGTH_BITS - 1)) * 1.0 * (44100.0 / AUDIO_SAMPLE_RATE_EXACT)) / WAVETABLE_NOTE_TO_FREQUENCY(base_note)  + 0.5, //((0x80000000 >> (index_bits - 1)) * cents_offset * sampling_rate / AUDIO_SAME_RATE_EXACT) / sample_freq + 0.5
        ((uint32_t)LENGTH - 1) << (32 - LENGTH_BITS), //(sample_length-1) << (32 - sample_length_bits)
        ((uint32_t)LOOPEND - 1) << (32 - LENGTH_BITS), //(loop_end-1) << (32 - sample_length_bits) == LOOP_PHASE_END
        (((uint32_t)LOOPEND - 1) << (32 - LENGTH_BITS)) - (((uint32_t)LOOPSTART - 1) << (32 - LENGTH_BITS)), //LOOP_PHASE_END - (loop_start-1) << (32 - sample_length_bits) == LOOP_PHASE_END - LOOP_PHASE_START == LOOP_PHASE_LENGTH
        uint16_t(UINT16_MAX * WAVETABLE_DECIBEL_SHIFT(-0 / 100.0)), //INITIAL_ATTENUATION_SCALAR
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //DELAY_COUNT
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //ATTACK_COUNT
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //HOLD_COUNT
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //DECAY_COUNT
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //RELEASE_COUNT
        int32_t(0 * AudioSynthWavetable::UNITY_GAIN), //SUSTAIN_MULT
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / (2 * AudioSynthWavetable::LFO_PERIOD)),  // VIBRATO_DELAY
        uint32_t(0 / 1000.0 * AudioSynthWavetable::LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT)), // VIBRATO_INCREMENT
        (WAVETABLE_CENTS_SHIFT(-0 / 1000.0) - 1.0) * 4, // VIBRATO_PITCH_COEFFICIENT_INITIAL
        (1.0 - WAVETABLE_CENTS_SHIFT(0 / 1000.0)) * 4, // VIBRATO_COEFFICIENT_SECONDARY
        uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / (2 * AudioSynthWavetable::LFO_PERIOD)), // MODULATION_DELAY
        uint32_t(0 / 1000.0 * AudioSynthWavetable::LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT)), // MODULATION_INCREMENT
        (WAVETABLE_CENTS_SHIFT(-0 / 1000.0) - 1.0) * 4, // MODULATION_PITCH_COEFFICIENT_INITIAL
        (1.0 - WAVETABLE_CENTS_SHIFT(0 / 1000.0)) * 4, // MODULATION_PITCH_COEFFICIENT_SECOND
        int32_t(UINT16_MAX * (WAVETABLE_DECIBEL_SHIFT(-0.1) - 1.0)) * 4, // MODULATION_AMPLITUDE_INITIAL_GAIN
        int32_t(UINT16_MAX * (1.0 - WAVETABLE_DECIBEL_SHIFT(0.1))) * 4, // MODULATION_AMPLITUDE_FINAL_GAIN
      };
    
      ///instrument_data NULL_INSTRUMENT = {1,DEFAULT_NOTE_RANGES,0};
      //memcpy(memptr,&NULL_INSTRUMENT,sizeof(instrument_data));
      //memcpy(memptr + sizeof(uint8_t) + sizeof(uint8_t*),&NULL_SAMPLE,sizeof(sample_data));
      memcpy(memptr, &NULL_SAMPLE, sizeof(sample_data));
    
      //
      //const instrument_data 808snare = {1, 808snare_ranges, 808snare_samples };
      int px = header.subChunk1.blockAlign;
      int le = header.subChunk2Header.size;
    
    
      Serial.print("num channels:");
      Serial.println(header.subChunk1.numChannels);
      Serial.print("block align:");
      Serial.println(header.subChunk1.blockAlign);
      Serial.print("bits:");
      Serial.println(header.subChunk1.bitsPerSample);
    
    
      while ((px < arraylen) && tmpf.available()) {
        uint16_t samplesize = header.subChunk1.blockAlign * header.subChunk1.numChannels;
        uint8_t samplemem[header.subChunk1.blockAlign * 4];
        //now lets convert the waw, teensy audio expects 16bit * 2
        //I think teensy's instruments are mono
        switch (header.subChunk1.bitsPerSample) {
          case 8:
            tmpf.read(&samplemem, header.subChunk1.blockAlign * 2);
            if (header.subChunk1.numChannels == 1) {
              samplemem[1] = samplemem[0];
            }
            *mem16ptr++ = samplemem[0] * 255;
            *mem16ptr++ = samplemem[1] * 255;
            break;
    
          case 24:
            tmpf.read(&samplemem, header.subChunk1.blockAlign * 2);
            if (header.subChunk1.numChannels == 1) {
              samplemem[3] = samplemem[0];
              samplemem[4] = samplemem[1];
              samplemem[5] = samplemem[5];
            }
            *mem16ptr++ = word(samplemem[2], samplemem[1]) ;//+ samplemem[0];
            *mem16ptr++ = word(samplemem[5], samplemem[4]) ;//+ samplemem[3];
            break;
    
          case 16:
            tmpf.read(&samplemem, header.subChunk1.blockAlign * 2);
            if (header.subChunk1.numChannels == 1) {
              samplemem[3] = samplemem[1];
              samplemem[2] = samplemem[0];
            }
            *mem16ptr++ = word(samplemem[1], samplemem[0]);
            *mem16ptr++ = word(samplemem[3], samplemem[2]);
            break;
    
          case 32:
            tmpf.read(&samplemem, header.subChunk1.blockAlign * 2);
            float * floatdat = (float *) samplemem;
            uint16_t * smp = (uint16_t *) samplemem;
            uint8_t swapbytes[4];
            float * ch;
            swapbytes[0] = samplemem[0];
            swapbytes[1] = samplemem[1];
            swapbytes[2] = samplemem[2];
            swapbytes[3] = samplemem[3];
            ch = (float *)swapbytes;
            *mem16ptr++ = clip32to16(*ch);
    
            swapbytes[0] = samplemem[4];
            swapbytes[1] = samplemem[5];
            swapbytes[2] = samplemem[6];
            swapbytes[3] = samplemem[7];
            ch = (float *)swapbytes;
            *mem16ptr++ = clip32to16(*ch);
            break;
        }
        px ++;
      }
      tmpf.close();
    
      __enable_irq();
      AudioInterrupts();
      //return (unsigned int *) memptr;
      // return (instrument_data *) memptr;
      return (sample_data *) memptr;
    }

  7. #7
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,878
    The Teensy has more power, but it is likely being constrained by the relatively slow SD card reader on the audio shield, using single bit SPI to transfer data. The Teensy 4.0 does have pins to support a micro SD card reader/writer that should be much faster, using SDIO mode which transfers 4 bits at a time. There are various strategies to attach those pins to a micro SD card reader, assuming you can do soldering of both through hole components and some surface mount components.

    The 'General Discussion' sub-forum is typically where these methods are discussed. Lets see, some of them include:


    Trainer4edu and Blackketter's breakout boards involve ordering PCBs from a PCB manufacturer (such as OSH park). That in turn tends to result in a several week delay to wait for the board to be manufactured.

    If you are solder challenged, later on, Paul will be releasing a Teensy 4.0 follow on board that has the micro-SD card reader built-in (similar to the older Teensy 3.5/3.6). The seller 'talldog' on tindie ('loglow' in this forum) has said that he will be releasing his breakout kit eventually, and one of the options would be to offer a Teensy 4.0 with everything soldered in place. Hyperbolic (listed above) has a board on tindie, but it is currently sold out. However, none of these are available right now.

    Note, with any of these solutions, make sure you are using a fast card. And freshly format the card before loading the files.

  8. #8
    Junior Member
    Join Date
    Nov 2019
    Posts
    6
    Thanks MichaelMeissner thats some very informative and useful info! I'll give that a go (I think i've got a spare micro sd card reader lying around) this could be just what I need

    Will post an update of how I get on...

  9. #9
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,878
    You also might want to look into this thread:


  10. #10
    Junior Member
    Join Date
    Nov 2019
    Posts
    6
    Thanks again, I was looking into this also, my issue was the erase times, I only need to store audio samples at runtime and the idea of a 10-20 second erase every startup put me off. Maybe I have missed something???

  11. #11
    Junior Member
    Join Date
    Nov 2019
    Posts
    6
    Just a quick update for anyone interested.. As suggested by MichaelMeissner I've connected a micro SD card reader to the teensy 4's SDIO port and have so far been able to play 5 simultaneous RAW Wav files. I'm running the T4 @ 450mhz and using SDfat in FIFO_SDIO mode. with a few optimisations I think you could push a few more.

  12. #12
    Senior Member
    Join Date
    Dec 2019
    Posts
    129
    Xcoder, I am having difficulty getting your code to compile. Do you have an updated version, by chance? I am getting the following compiler errors

    Code:
    Arduino: 1.8.10 (Windows 10), TD: 1.49, Board: "Teensy 4.0, MIDI, 600 MHz, Faster, US English"
    
    SDSf2: In function 'sample_data* loadSampleAsInstrument(uint8_t, const char*)':
    SDSf2:51: error: '__REV' was not declared in this scope
       header.chunkId = __REV(header.chunkId);
    
                                            ^
    
    SDSf2:164: error: 'AUDIO_SAMPLE_RATE_EXACT' was not declared in this scope
         ((0x80000000 >> (LENGTH_BITS - 1)) * 1.0 * (44100.0 / AUDIO_SAMPLE_RATE_EXACT)) / WAVETABLE_NOTE_TO_FREQUENCY(base_note)  + 0.5, //((0x80000000 >> (index_bits - 1)) * cents_offset * sampling_rate / AUDIO_SAME_RATE_EXACT) / sample_freq + 0.5
    
                                                               ^
    
    SDSf2:164: error: 'WAVETABLE_NOTE_TO_FREQUENCY' was not declared in this scope
         ((0x80000000 >> (LENGTH_BITS - 1)) * 1.0 * (44100.0 / AUDIO_SAMPLE_RATE_EXACT)) / WAVETABLE_NOTE_TO_FREQUENCY(base_note)  + 0.5, //((0x80000000 >> (index_bits - 1)) * cents_offset * sampling_rate / AUDIO_SAME_RATE_EXACT) / sample_freq + 0.5
    
                                                                                                                                ^
    
    SDSf2:168: error: 'WAVETABLE_DECIBEL_SHIFT' was not declared in this scope
         uint16_t(UINT16_MAX * WAVETABLE_DECIBEL_SHIFT(-0 / 100.0)), //INITIAL_ATTENUATION_SCALAR
    
                                                                 ^
    
    SDSf2:169: error: 'AudioSynthWavetable' was not declared in this scope
         uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //DELAY_COUNT
    
                      ^
    
    SDSf2:177: error: 'WAVETABLE_CENTS_SHIFT' was not declared in this scope
         (WAVETABLE_CENTS_SHIFT(-0 / 1000.0) - 1.0) * 4, // VIBRATO_PITCH_COEFFICIENT_INITIAL
    
                                           ^
    
    SDSf2:244: warning: unused variable 'floatdat' 
             float * floatdat = (float *) samplemem;
    
                     ^
    
    SDSf2:245: warning: unused variable 'smp' 
             uint16_t * smp = (uint16_t *) samplemem;
    
                        ^
    
    SDSf2:207: warning: unused variable 'samplesize' 
         uint16_t samplesize = header.subChunk1.blockAlign * header.subChunk1.numChannels;
    
                  ^
    
    SDSf2:268: error: 'AudioInterrupts' was not declared in this scope
       AudioInterrupts();
    
                       ^
    
    SDSf2:27: warning: unused variable 'subChunk2Offset' 
       int subChunk2Offset = 0;
    
           ^
    
    SDSf2:149: warning: unused variable 'mem32ptr' 
       uint32_t * mem32ptr =  (uint32_t *) sampdatastart;
    
                  ^
    
    SDSf2:195: warning: unused variable 'le' 
       int le = header.subChunk2Header.size;
    
           ^
    
    Multiple libraries were found for "SPI.h"
     Used: C:\Program
    Multiple libraries were found for "SdFat.h"
     Used: C:\Users\FFFF12ABB17\Documents\Arduino\libraries\SdFat
    '__REV' was not declared in this scope
    
    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.

  13. #13
    Junior Member
    Join Date
    Nov 2019
    Posts
    6
    Quote Originally Posted by RABB17 View Post
    Xcoder, I am having difficulty getting your code to compile. Do you have an updated version, by chance? I am getting the following compiler errors

    Code:
    Arduino: 1.8.10 (Windows 10), TD: 1.49, Board: "Teensy 4.0, MIDI, 600 MHz, Faster, US English"
    
    SDSf2: In function 'sample_data* loadSampleAsInstrument(uint8_t, const char*)':
    SDSf2:51: error: '__REV' was not declared in this scope
       header.chunkId = __REV(header.chunkId);
    
                                            ^
    
    SDSf2:164: error: 'AUDIO_SAMPLE_RATE_EXACT' was not declared in this scope
         ((0x80000000 >> (LENGTH_BITS - 1)) * 1.0 * (44100.0 / AUDIO_SAMPLE_RATE_EXACT)) / WAVETABLE_NOTE_TO_FREQUENCY(base_note)  + 0.5, //((0x80000000 >> (index_bits - 1)) * cents_offset * sampling_rate / AUDIO_SAME_RATE_EXACT) / sample_freq + 0.5
    
                                                               ^
    
    SDSf2:164: error: 'WAVETABLE_NOTE_TO_FREQUENCY' was not declared in this scope
         ((0x80000000 >> (LENGTH_BITS - 1)) * 1.0 * (44100.0 / AUDIO_SAMPLE_RATE_EXACT)) / WAVETABLE_NOTE_TO_FREQUENCY(base_note)  + 0.5, //((0x80000000 >> (index_bits - 1)) * cents_offset * sampling_rate / AUDIO_SAME_RATE_EXACT) / sample_freq + 0.5
    
                                                                                                                                ^
    
    SDSf2:168: error: 'WAVETABLE_DECIBEL_SHIFT' was not declared in this scope
         uint16_t(UINT16_MAX * WAVETABLE_DECIBEL_SHIFT(-0 / 100.0)), //INITIAL_ATTENUATION_SCALAR
    
                                                                 ^
    
    SDSf2:169: error: 'AudioSynthWavetable' was not declared in this scope
         uint32_t(0 * AudioSynthWavetable::SAMPLES_PER_MSEC / 8.0 + 0.5), //DELAY_COUNT
    
                      ^
    
    SDSf2:177: error: 'WAVETABLE_CENTS_SHIFT' was not declared in this scope
         (WAVETABLE_CENTS_SHIFT(-0 / 1000.0) - 1.0) * 4, // VIBRATO_PITCH_COEFFICIENT_INITIAL
    
                                           ^
    
    SDSf2:244: warning: unused variable 'floatdat' 
             float * floatdat = (float *) samplemem;
    
                     ^
    
    SDSf2:245: warning: unused variable 'smp' 
             uint16_t * smp = (uint16_t *) samplemem;
    
                        ^
    
    SDSf2:207: warning: unused variable 'samplesize' 
         uint16_t samplesize = header.subChunk1.blockAlign * header.subChunk1.numChannels;
    
                  ^
    
    SDSf2:268: error: 'AudioInterrupts' was not declared in this scope
       AudioInterrupts();
    
                       ^
    
    SDSf2:27: warning: unused variable 'subChunk2Offset' 
       int subChunk2Offset = 0;
    
           ^
    
    SDSf2:149: warning: unused variable 'mem32ptr' 
       uint32_t * mem32ptr =  (uint32_t *) sampdatastart;
    
                  ^
    
    SDSf2:195: warning: unused variable 'le' 
       int le = header.subChunk2Header.size;
    
           ^
    
    Multiple libraries were found for "SPI.h"
     Used: C:\Program
    Multiple libraries were found for "SdFat.h"
     Used: C:\Users\FFFF12ABB17\Documents\Arduino\libraries\SdFat
    '__REV' was not declared in this scope
    
    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.
    The __REV macro is defined in Arm Math.h, i had it somewhere in my original code..
    just change AudioSynthWavetable::SAMPLES_PER_MSEC to SAMPLES_PER_MSEC and paste the following into your code, it should compile.. (i think i must have used an older version of AudioSynthWavetable to modify).

    Code:
    #include <arm_math.h>
    #define AUDIO_SAMPLE_RATE_EXACT 44100.00
    #define SAMPLES_PER_MSEC (AUDIO_SAMPLE_RATE_EXACT / 1000.0)
    #define WAVETABLE_CENTS_SHIFT(C) (pow(2.0, (C)/1200.0))
    #define WAVETABLE_NOTE_TO_FREQUENCY(N) (440.0 * pow(2.0, ((N) - 69) / 12.0))
    #define WAVETABLE_DECIBEL_SHIFT(dB) (pow(10.0, (dB)/20.0))

  14. #14
    Senior Member
    Join Date
    Dec 2019
    Posts
    129
    Worked for me! Thank you

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •