Saving patches

Status
Not open for further replies.

urbanspaceman

Well-known member
Hi, if i make my own synth on teensy
there is a way to save some 'patches/presets' on the SD card?

for example
very simple synth with one osc (1 control), one filter (2 controls) etc...
i make some tweaks on this knob then i want to save this configuaration to recall it later...

thanks
 
Different layers on that one. If your application is simple just using the existing EEPROM is the normal method to save config data:

https://www.arduino.cc/en/Reference/EEPROM

So if you have a fixed number of devices you just hard code EEPROM locations (taking care of byte/16 bit sizeing) for them and create procedures to read and write them.

This obviously hard codes things, and is also limited by the EEPROM size but it's the dead simple way to manage a dozen values or so. If you want to go beyond that then you need to work out some fixed format that allows you to iterate through your values without having to name them all yourself and that does get a bit tricky, more so if you want to be able to use saved settings on a new synth config. Results from that can go into a binary file on a SD card or into EEPROM.
 
Thanks Gremilin, I need to find a generic method, such my 'circuit' can load different sketches, which is different synth for example.
And the parameters may be different.

I think a structure on the SD like this

FOLDER (with unique name connected to the patch, if the patch is for example 'Moog_imitation', the folder name is 'Moog_imitation')
1 XML file for every patch
any files to support patch (samples)
 
urbanspaceman,

If by "my 'circuit' can load different sketches," you mean that you want to reconfigure the Audio Design instead of actually reprogramming the Teensy with a new sketch, you may want to read this thread: Adding-and-removing-AudioStream-and-AudioConnections-during-program-execution. It sounds like removing objects in an audio design during run-time is not a good idea.

Recently I wanted to save presets for a stompbox to an SD card. It isn't quite what you were asking (no XML), but maybe this code will help. This is just the proof-of-concept code that I later merged into my larger project. Feel free to rip any of it if you find it useful. By the way, in my stompbox, I ended up writing multiple effect sections and then using mixer objects to 'reconfigure' things on-the-fly.

Code:
#include <SD.h>
#include <SPI.h>

#define SD_CS 10 // SD card CS pin

// Parameter data structure for potentiometers, arranged into banks for presets

const int numParamBanks = 3;  // number of parameter banks
const int numParams = 5;      // number of parameters in each bank
const int numPresets = 3;     // number of presets containing the parameter banks
struct paramBank {
  int parameter[numParamBanks][numParams];
} preset[numPresets];

void setup() {

  // Necessary for SD card operation on Teensy with audio shield
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
 
  Serial.begin(9600);
  while (!Serial);
  if (!SD.begin(SD_CS)) {
    Serial.println("Initialization of SD card failed");
  }
  presetRandom();
  for (int i=0; i < numPresets; i++) {
    presetWrite(i);
  }
  presetInitialize();
  for (int i=0; i < numPresets; i++) {
    presetPrint(i);
  }
  for (int i=0; i < numPresets; i++) {
    presetRead(i);
  }
  for (int i=0; i < numPresets; i++) {
    presetPrint(i);
  }
}

void loop() {

}

void presetRandom() {
  Serial.println("Parameter initialization...");
  for (int i=0; i < numPresets; i++) {
    for (int j=0; j < numParamBanks; j++) {
      for (int k=0; k < numParams; k++) {
        preset[i].parameter[j][k] = random(1,1023);
      }
    }
  }
}

void presetInitialize() {
  Serial.println("Parameter initialization...");
  for (int i=0; i < numPresets; i++) {
    for (int j=0; j < numParamBanks; j++) {
      for (int k=0; k < numParams; k++) {
        preset[i].parameter[j][k] = 1;
      }
    }
  }
}

void presetWrite(int presetNumber) {
  if ((presetNumber >= 0) && (presetNumber < numPresets)) {
    char filename[13];
    String fname = "Preset" + String(presetNumber);
    fname = fname + ".dat";
    fname.toCharArray(filename,13);
    if (SD.exists(filename)) {
      Serial.print("Removing ");
      Serial.println(filename);
      SD.remove(filename);
    }
    Serial.print("Writing to ");
    Serial.println(filename);    
    File presetFile = SD.open(filename,FILE_WRITE);
    for (int j=0; j < numParamBanks; j++) {
      for (int k=0; k < numParams; k++) {
        presetFile.print(String(preset[presetNumber].parameter[j][k]));
        presetFile.print(",");
        Serial.print(String(preset[presetNumber].parameter[j][k]));
        Serial.print(",");  
      }
    }
    Serial.println();
    presetFile.close();
  }
  else {
    Serial.print("Error in presetWrite: Preset number (");
    Serial.print(presetNumber);
    Serial.println(") is out of range.");
  }
}

void presetRead(int presetNumber) {
  if ((presetNumber >= 0) && (presetNumber < numPresets)) {
    char filename[13];
    String fname = "Preset" + String(presetNumber);
    fname = fname + ".dat";
    fname.toCharArray(filename,13);
    Serial.print("Reading from ");
    Serial.println(filename);
    File presetFile = SD.open(filename,FILE_READ);
    for (int j=0; j < numParamBanks; j++) {
      for (int k=0; k < numParams; k++) {
        preset[presetNumber].parameter[j][k] = presetFile.parseInt();
        Serial.print(String(preset[presetNumber].parameter[j][k]));
        Serial.print(" ");  
      }
    }
    Serial.println();
    presetFile.close();
  }
  else {
    Serial.print("Error in presetRead: Preset number (");
    Serial.print(presetNumber);
    Serial.println(") is out of range.");
  }    

}

void presetPrint(int presetNumber) {
  Serial.print("Preset ");
  Serial.print(presetNumber);
  Serial.print(": ");
  for (int j=0; j < numParamBanks; j++) {
    for (int k=0; k < numParams; k++) {
      Serial.print(preset[presetNumber].parameter[j][k]);
      Serial.print(" ");  
    }
  }
  Serial.println();
  Serial.println();
}
 
No, i don't want to remove object from patches while running
i want to do something similar with your pedal, saving the state of machine in a file to recall it later
if i read right your code, you save an array of parameters and their values in a .dat file
 
if i read right your code, you save an array of parameters and their values in a .dat file

That is correct. The preset files are just a list of comma-separated values. I just read the values back into the same data structure. It isn't pretty, like XML. With my stompbox, the SD card isn't really user-accessible and I wasn't worried about trading presets or editing them on a computer... I was just looking for a simple way to save a few presets, particularly to have a decent starting point after cycling power and as a way to relatively quickly switch between a few different "sounds."

Oh, I should add that each of the three presets (three in the example code, but easily expandable by editing the numPresets constant) is an individual .dat file. For example, Preset0.dat, Preset1.dat, and Preset2.dat.
 
Last edited:
Status
Not open for further replies.
Back
Top