/*
-Sept 23 '19 Added code to modify the MODULATION_PITCH_COEFFICIENT (initial and secondary) to reflect the value of the MOD Wheel (Continuous Controller #1)
- modified the "synthWavetable.h and .cpp files to handle these changing variables in real-time (during update routine)
*/
#include <SD.h>
#include <Audio.h>
#include <MIDI.h>
#include <LiquidCrystal.h>
#include <Encoder.h>
const int TOTAL_VOICES = 48;
const int TOTAL_MIXERS = 17; // + 3 for the Graphic EQ
AudioSynthWavetable wavetable[TOTAL_VOICES];
AudioMixer4 mixer[TOTAL_MIXERS];
AudioOutputPT8211 pt8211_1;
AudioFilterBiquad filter1;
AudioFilterBiquad filter2;
AudioFilterBiquad filter3;
AudioFilterBiquad filter4;
AudioFilterBiquad filter5;
AudioFilterBiquad filter6;
AudioFilterBiquad filter7;
AudioMixer4 mixer1;
AudioMixer4 mixer2;
AudioMixer4 mixer3;
AudioConnection patchCord[] = {
{ wavetable[0], 0, mixer[0], 0 },{ wavetable[1], 0, mixer[0], 1 },{ wavetable[2], 0, mixer[0], 2 },{ wavetable[3], 0, mixer[0], 3 },{ mixer[0], 0, mixer[TOTAL_MIXERS - 2], 0 },
{ wavetable[4], 0, mixer[1], 0 },{ wavetable[5], 0, mixer[1], 1 },{ wavetable[6], 0, mixer[1], 2 },{ wavetable[7], 0, mixer[1], 3 },{ mixer[1], 0, mixer[TOTAL_MIXERS - 2], 1 },
{ wavetable[8], 0, mixer[2], 0 },{ wavetable[9], 0, mixer[2], 1 },{ wavetable[10], 0, mixer[2], 2 },{ wavetable[11], 0, mixer[2], 3 },{ mixer[2], 0, mixer[TOTAL_MIXERS - 2], 2 },
{ wavetable[12], 0, mixer[3], 0 },{ wavetable[13], 0, mixer[3], 1 },{ wavetable[14], 0, mixer[3], 2 },{ wavetable[15], 0, mixer[3], 3 },{ mixer[3], 0, mixer[TOTAL_MIXERS - 2], 3 },
{ wavetable[16], 0, mixer[4], 0 },{ wavetable[17], 0, mixer[4], 1 },{ wavetable[18], 0, mixer[4], 2 },{ wavetable[19], 0, mixer[4], 3 },{ mixer[4], 0, mixer[TOTAL_MIXERS - 3], 0 },
{ wavetable[20], 0, mixer[5], 0 },{ wavetable[21], 0, mixer[5], 1 },{ wavetable[22], 0, mixer[5], 2 },{ wavetable[23], 0, mixer[5], 3 },{ mixer[5], 0, mixer[TOTAL_MIXERS - 3], 1 },
{ wavetable[24], 0, mixer[6], 0 },{ wavetable[25], 0, mixer[6], 1 },{ wavetable[26], 0, mixer[6], 2 },{ wavetable[27], 0, mixer[6], 3 },{ mixer[6], 0, mixer[TOTAL_MIXERS - 3], 2 },
{ wavetable[28], 0, mixer[7], 0 },{ wavetable[29], 0, mixer[7], 1 },{ wavetable[30], 0, mixer[7], 2 },{ wavetable[31], 0, mixer[7], 3 },{ mixer[7], 0, mixer[TOTAL_MIXERS - 3], 3 },
{ wavetable[32], 0, mixer[8], 0 },{ wavetable[33], 0, mixer[8], 1 },{ wavetable[34], 0, mixer[8], 2 },{ wavetable[35], 0, mixer[8], 3 },{ mixer[8], 0, mixer[TOTAL_MIXERS - 4], 0 },
{ wavetable[36], 0, mixer[9], 0 },{ wavetable[37], 0, mixer[9], 1 },{ wavetable[38], 0, mixer[9], 2 },{ wavetable[39], 0, mixer[9], 3 },{ mixer[9], 0, mixer[TOTAL_MIXERS - 4], 1 },
{ wavetable[40], 0, mixer[10], 0 },{ wavetable[41], 0, mixer[10], 1 },{ wavetable[42], 0, mixer[10], 2 },{ wavetable[43], 0, mixer[10], 3 },{ mixer[10], 0, mixer[TOTAL_MIXERS - 4], 2 },
{ wavetable[44], 0, mixer[11], 0 },{ wavetable[45], 0, mixer[11], 1 },{ wavetable[46], 0, mixer[11], 2 },{ wavetable[47], 0, mixer[11], 3 },{ mixer[11], 0, mixer[TOTAL_MIXERS - 4], 3 },
{ mixer[TOTAL_MIXERS - 2], 0, mixer[TOTAL_MIXERS - 1], 0 },
{ mixer[TOTAL_MIXERS - 3], 0, mixer[TOTAL_MIXERS - 1], 1 },
{ mixer[TOTAL_MIXERS - 4], 0, mixer[TOTAL_MIXERS - 1], 2 },
{ mixer[TOTAL_MIXERS - 5], 0, mixer[TOTAL_MIXERS - 1], 3 },
};
AudioConnection patchCord1(mixer[TOTAL_MIXERS - 1], 0, filter1, 0); // Graphic EQ band 1
AudioConnection patchCord2(mixer[TOTAL_MIXERS - 1], 0, filter2, 0); // Graphic EQ band 2
AudioConnection patchCord3(mixer[TOTAL_MIXERS - 1], 0, filter3, 0); //
AudioConnection patchCord4(mixer[TOTAL_MIXERS - 1], 0, filter4, 0); //
AudioConnection patchCord5(mixer[TOTAL_MIXERS - 1], 0, filter5, 0); //
AudioConnection patchCord6(mixer[TOTAL_MIXERS - 1], 0, filter6, 0); //
AudioConnection patchCord7(mixer[TOTAL_MIXERS - 1], 0, filter7, 0); // Graphic EQ band 7
AudioConnection patchCord8(filter1, 0, mixer1, 0);
AudioConnection patchCord9(filter2, 0, mixer1,1);
AudioConnection patchCord10(filter3, 0, mixer1, 2);
AudioConnection patchCord11(filter4, 0, mixer1, 3);
AudioConnection patchCord12(filter5, 0, mixer2, 0);
AudioConnection patchCord13(filter6, 0, mixer2, 1);
AudioConnection patchCord14(filter7, 0, mixer2, 2);
AudioConnection patchCord15(mixer1, 0, mixer3, 0);
AudioConnection patchCord16(mixer2, 0, mixer3, 1);
AudioConnection patchCord17(mixer3, 0, pt8211_1, 0);
AudioConnection patchCord18(mixer3, 0, pt8211_1, 1);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
// configure the character LCD object
// Since I am using GPIO1, which gets configured by the MIDI object (as MIDI OUT), must do this LCD display configuration AFTER MIDI port is configured
const int rs = 1, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6; // define the port pins used for the 6 LCD signals
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
File myFile;
Encoder REnc(16, 17); // set up a rotary encoder on GPIO16,17
int notes_played = 0;
int noteAlloc[TOTAL_VOICES];
String tmpString;
String paramString;
String voiceName;
int totalSampleLength = 0;
int numRanges;
int sIndex;
int fIndex;
int rangeIndex;
int err;
String paramString2;
bool voiceLoading = false;
byte programNumber = 1;
byte controlNumber = 0;
byte controlValue = 0;
int32_t RotaryEncoderValue = 0;
int numPrograms = 0;
int cents_offset;
float sample_rate;
int sample_note;
int menuItem=0;
volatile byte currentControl;
volatile byte currentControlValue;
bool learnMode = false;
struct config_Array {
byte ID;
byte Control_Translation_Map[16];
byte filter1_value[127];
byte filter2_value[127];
byte filter3_value[127];
byte filter4_value[127];
byte filter5_value[127];
byte filter6_value[127];
byte filter7_value[127];
byte MIDI_channel;
};
config_Array cfg;
struct sample_data {
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;
// VIBRATO 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;
};
AudioSynthWavetable::sample_data sd0[10];
#define MENU 9 // menu on GPIO9
#define ENTER 10 // Enter on GPIO10
#define SAVE 11 // SAVE on GPIO11
#define EXIT 12 // EXIT on GPIO12
#define LED 22 // Key pressed LED
#define MAX_MENU_ITEMS 2
#define MAX_RANGES 10
// following are constants that were defined in the AudioSynthWavetable library, and are used in main program for some calculations
#define CENTS_SHIFT(C) (pow(2.0, (C)/1200.0))
#define NOTE_TO_FREQUENCY(N) (440.0 * pow(2.0, ((N) - 69) / 12.0))
#define NOTE(N) (440.0 * pow(2.0, ((N) - 69) / 12.0))
#define DECIBEL_SHIFT(dB) (pow(10.0, (dB)/20.0))
const int32_t UNITY_GAIN = INT32_MAX;
const int32_t LFO_SMOOTHNESS = 3;
const float LFO_PERIOD = (AUDIO_BLOCK_SAMPLES / (1 << (LFO_SMOOTHNESS - 1)));
static float SAMPLES_PER_MSEC = (AUDIO_SAMPLE_RATE_EXACT / 1000.0);
static const int32_t ENVELOPE_PERIOD = 8;
#define MAX_WAVE_SAMPLES 120000 // usually limited to about 95000, but can go to 120000 or so if DMAMEM is specified in the array declaration (otherwise it has to share 512K mem with program FLASH
uint32_t DMAMEM SAMPLE_BUFFER[MAX_WAVE_SAMPLES]; // This stores the actual waveform data- broken into up to MAX_RANGES regions
uint8_t DefaultVoice_ranges[MAX_RANGES];
AudioSynthWavetable::instrument_data DefaultVoice = { numRanges, DefaultVoice_ranges, sd0 };
void setup() {
pinMode(MENU, INPUT_PULLUP);
pinMode(ENTER, INPUT_PULLUP);
pinMode(SAVE, INPUT_PULLUP);
pinMode(EXIT, INPUT_PULLUP);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(115200);
delay(1000);
Serial.println("starting up");
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.turnThruOff(); // this is supposed to stop MIDI IN being echoed to the Tx port associated with that MIDI port.
// however, still interferes with the LCD display when it is using GPIO1, unless you configure the LCD display after using the MIDI.begin() command.
lcd.begin(20, 2);
// Print a message to the LCD.
lcd.print("SoundFont");
lcd.setCursor(0, 2);
lcd.print("Synthesizer ");
delay(2000);
checkSDCard();
//initConfigFile();
loadConfigFile();
lcd.clear();
lcd.print("Config parameters");
lcd.setCursor(0, 1);
lcd.print("loaded");
delay(1000);
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);
MIDI.setHandleProgramChange(handleProgramChange);
MIDI.setHandleControlChange(handleControlChange);
MIDI.setHandlePitchBend(handlePitchBendChange);
MIDI.setHandleAfterTouchChannel(handleAfterTouchChannel);
AudioMemory(120); // estimate 120 blocks needed as there are 48 total voices and 20 mixers and 7 filters plus some extras for unknowns
// de-allocate all 48 voices
for (int i = 0; i < TOTAL_VOICES; i++) {
noteAlloc[i] = 0;
}
// setup all mixer gains
for (int i = 0; i < TOTAL_MIXERS - 3; i++) {
for (int j = 0; j < 4; j++) {
mixer[i].gain(j, 0.50);
}
}
for (int j = 0; j < 4; j++) {
mixer[TOTAL_MIXERS - 4].gain(j, 1);
mixer[TOTAL_MIXERS - 3].gain(j, 1);
mixer[TOTAL_MIXERS - 2].gain(j, 1);
}
mixer[TOTAL_MIXERS - 1].gain(0, 1);
mixer[TOTAL_MIXERS - 1].gain(1, 1);
for (int i = 0; i < TOTAL_VOICES; i++) {
wavetable[i].setInstrument(DefaultVoice);
wavetable[i].amplitude(1);
}
// setup default 7 band graphic EQ filter Freq and Q parameters
setFilters();
// setup default 7 band graphic EQ gains via mixers
mixer1.gain(0, 1); //
mixer1.gain(1, 1); //
mixer1.gain(2, 1); //
mixer1.gain(3, 1); //
mixer2.gain(0, 1); //
mixer2.gain(1, 1); //
mixer2.gain(2, 1); //
mixer3.gain(0, 1); // Final mix of filters 1-4
mixer3.gain(1, 1); // final mix of filter5-7
err=loadVoice(programNumber);
if (err == -1) {
lcd.clear();
lcd.print("SD Card error : ");
lcd.setCursor(0, 1);
lcd.print("voice file not found");
}
REnc.write(programNumber); // RE can change programs while in playing mode
RotaryEncoderValue = programNumber;
}
void loop() {
MIDI.read();
freeVoices();
int32_t REValue = REnc.read();
if (programNumber != REValue) {
if (REValue < 1) {
REValue = 1;
REnc.write(REValue);
}
if (REValue > 127) {
REValue = 127;
REnc.write(REValue);
}
programNumber = REValue;
loadVoice(programNumber);
}
if (digitalRead(MENU) == 0) {
menu();
}
if (digitalRead(SAVE) == 0) {
saveConfigFile();
while (digitalRead(SAVE) == 0);;;
}
}
int loadVoice(int number) {
char buffer[100];
err = -1;
voiceLoading = true;
lcd.clear();
lcd.print("Program # ");
lcd.print(number);
lcd.setCursor(0, 1); // second row
lcd.print("Empty");
char fname[20];
String filename;
String fn= String(number);
filename = fn + ".cpp";
filename.toCharArray(fname, 20);
Serial.println(fname);
myFile = SD.open(fname);
if (myFile) {
err = 0;
Serial.println("cpp file opened");
int i = 0;
while (myFile.available()) {
myFile.readBytesUntil(',', buffer, sizeof(buffer));
if ((i % 3000) == 0) {
lcd.print(".");
}
uint32_t value = strtoul(buffer, 0, 16);
SAMPLE_BUFFER[i] = value;
i++;
if (i == MAX_WAVE_SAMPLES) {
lcd.clear();
lcd.print("Too many wave samples");
lcd.setCursor(0, 1);
lcd.print("Truncated");
delay(2000);
break;
}
}
// close the file:
myFile.close();
totalSampleLength = i - 1;
Serial.println();
Serial.print("num samples");
Serial.println(totalSampleLength);
}
if (err == -1) {
voiceLoading = false;
return err;
}
filename = fn + ".h";
filename.toCharArray(fname, 20);
Serial.println(fname);
Serial.println(fname);
myFile = SD.open(fname);
if (myFile) {
err = 0;
rangeIndex = 0;
Serial.println("h file opened");
int i = 0;
int l;
lcd.print("."); // progress indicator
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
String paramString1(buffer);
int index = paramString1.indexOf("[", 0);
index++;
for (i = 0; i < 10; i++) {
buffer[i] = 0;
}
for (i = 0; i < 3; i++) {
char t = paramString1.charAt(index + i);
if (t == ']') {
buffer[i] = 0;
}
else {
buffer[i] = t;
}
}
String tmpString(buffer);
numRanges = tmpString.toInt();
Serial.print("Number of ranges= ");
Serial.println(numRanges);
if (numRanges > MAX_RANGES) {
Serial.println("Limited to MAX_RANGES value of 8");
numRanges = MAX_RANGES;
}
// get upper key values for each range from following line
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer));
String paramString2(buffer);
Serial.println(paramString2);
// first isolate the name for display purposes
fIndex = paramString2.indexOf("_", 0);
voiceName = paramString2.substring(0, fIndex);
sIndex = paramString2.indexOf("=", 0);
sIndex++;
fIndex = paramString2.indexOf(",", 0);
String tmpString2 = paramString2.substring(sIndex, fIndex);
DefaultVoice_ranges[0] = tmpString2.toInt();
Serial.println(DefaultVoice_ranges[0]);
// get the rest of the ranges
for (int i = 1; i < numRanges; i++) {
sIndex = fIndex + 1;
fIndex = paramString2.indexOf(",", sIndex);
String tmpString3 = paramString2.substring(sIndex, fIndex);
DefaultVoice_ranges[i] = tmpString3.toInt();
Serial.println(DefaultVoice_ranges[i]);
}
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // region name
Serial.println(buffer);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get loop true/false
String paramString3(buffer);
sIndex = paramString3.indexOf("true", 0);
if (sIndex >= 0) {
sd0[0].LOOP = true;
Serial.println("true");
}
else {
sd0[0].LOOP = false;
Serial.println("false");
}
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get INDEX_BITS
String paramString4(buffer);
sd0[0].INDEX_BITS = paramString4.toInt();
Serial.println(sd0[0].INDEX_BITS);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get cents_offset
String paramString5(buffer);
cents_offset = paramString5.toInt();
Serial.println(cents_offset);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get sample_rate
String paramString6(buffer);
sample_rate = paramString6.toFloat();
Serial.println(sample_rate);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get sample_note
String paramString7(buffer);
sample_note = paramString7.toFloat();
Serial.println(sample_note);
// calculate PER_HERTZ_PHASE_INCREMENT
sd0[0].PER_HERTZ_PHASE_INCREMENT = (1 << (32 - sd0[0].INDEX_BITS)) * CENTS_SHIFT(cents_offset) * sample_rate / NOTE(sample_note) / AUDIO_SAMPLE_RATE_EXACT + 0.5;
Serial.println(sd0[0].PER_HERTZ_PHASE_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MAX_PHASE
String paramString8(buffer);
int temp1 = paramString8.toInt();
Serial.println(temp1);
sd0[0].MAX_PHASE = ((uint32_t)temp1 - 1) << (32 - sd0[0].INDEX_BITS);
Serial.println(sd0[0].MAX_PHASE);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get LOOP_PHASE_END
String paramString9(buffer);
temp1 = paramString9.toInt();
int tempT = temp1;
Serial.println(temp1);
sd0[0].LOOP_PHASE_END = ((uint32_t)temp1 - 1) << (32 - sd0[0].INDEX_BITS);
Serial.println(sd0[0].LOOP_PHASE_END);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get LOOP_PHASE_LENGTH
String paramString10(buffer);
temp1 = paramString10.toInt();
Serial.println(temp1);
sd0[0].LOOP_PHASE_LENGTH = ((((uint32_t)tempT - 1) << (32 - sd0[0].INDEX_BITS)) - (((uint32_t)temp1 - 1) << (32 - sd0[0].INDEX_BITS))); // LOOP_PHASE_LENGTH // ((uint32_t)temp1 - 1) << (32 - sd0[0].INDEX_BITS);
Serial.println(sd0[0].LOOP_PHASE_LENGTH);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get INITIAL_ATTENUATION_SCALAR
String paramString11(buffer);
temp1 = paramString11.toInt();
sd0[0].INITIAL_ATTENUATION_SCALAR = (uint16_t)UINT16_MAX * DECIBEL_SHIFT(temp1);
Serial.println(sd0[0].INITIAL_ATTENUATION_SCALAR);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get DELAY_COUNT
String paramString12(buffer);
temp1 = paramString12.toFloat();
sd0[0].DELAY_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[0].DELAY_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get ATTACK_COUNT
String paramString13(buffer);
temp1 = paramString13.toFloat();
sd0[0].ATTACK_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[0].ATTACK_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get HOLD_COUNT
String paramString14(buffer);
temp1 = paramString14.toFloat();
sd0[0].HOLD_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[0].HOLD_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get DECAY_COUNT
String paramString15(buffer);
temp1 = paramString15.toFloat();
sd0[0].DECAY_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[0].DECAY_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get RELEASE_COUNT
String paramString16(buffer);
temp1 = paramString16.toFloat();
sd0[0].RELEASE_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[0].RELEASE_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get SUSTAIN_MULT
String paramString17(buffer);
temp1 = paramString17.toFloat();
sd0[0].SUSTAIN_MULT = int32_t((1.0 - DECIBEL_SHIFT(temp1)) * UNITY_GAIN);
Serial.println(sd0[0].SUSTAIN_MULT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_DELAY
String paramString18(buffer);
temp1 = paramString18.toFloat();
sd0[0].VIBRATO_DELAY = uint32_t(temp1 * SAMPLES_PER_MSEC / (2 * LFO_PERIOD));
Serial.println(sd0[0].VIBRATO_DELAY);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_INCREMENT
String paramString19(buffer);
temp1 = paramString19.toFloat();
sd0[0].VIBRATO_INCREMENT = uint32_t(temp1 * LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));
Serial.println(sd0[0].VIBRATO_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_PITCH_COEFICIENT_INITIAL
String paramString20(buffer);
temp1 = paramString20.toFloat();
sd0[0].VIBRATO_PITCH_COEFFICIENT_INITIAL = (CENTS_SHIFT(temp1) - 1.0) * 4;
Serial.println(sd0[0].VIBRATO_PITCH_COEFFICIENT_INITIAL);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_PITCH_COEFICIENT_SECOND
String paramString21(buffer);
temp1 = paramString21.toFloat();
sd0[0].VIBRATO_PITCH_COEFFICIENT_SECOND = (1.0 - CENTS_SHIFT(temp1)) * 4;
Serial.println(sd0[0].VIBRATO_PITCH_COEFFICIENT_SECOND);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_DELAY
String paramString22(buffer);
temp1 = paramString22.toFloat();
sd0[0].MODULATION_DELAY = uint32_t(temp1 * SAMPLES_PER_MSEC / (2 * LFO_PERIOD)),
Serial.println(sd0[0].MODULATION_DELAY);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_INCREMENT
String paramString23(buffer);
temp1 = paramString23.toFloat();
sd0[0].MODULATION_INCREMENT = uint32_t(temp1 * LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));
Serial.println(sd0[0].MODULATION_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_PITCH_COEFFICIENT_INITIAL
String paramString24(buffer);
temp1 = paramString24.toInt();
sd0[0].MODULATION_PITCH_COEFFICIENT_INITIAL = (CENTS_SHIFT(temp1) - 1.0) * 4;
Serial.println(sd0[0].MODULATION_PITCH_COEFFICIENT_INITIAL);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_PITCH_COEFFICIENT_SECOND
String paramString25(buffer);
temp1 = paramString25.toInt();
sd0[0].MODULATION_PITCH_COEFFICIENT_SECOND = (1.0 - CENTS_SHIFT(temp1)) * 4;
Serial.println(sd0[0].MODULATION_PITCH_COEFFICIENT_SECOND);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_AMPLITUDE_INITIAL_GAIN
String paramString26(buffer);
temp1 = paramString26.toInt();
sd0[0].MODULATION_AMPLITUDE_INITIAL_GAIN = (int32_t)(UINT16_MAX * (DECIBEL_SHIFT(temp1) - 1.0)) * 4;
Serial.println(sd0[0].MODULATION_AMPLITUDE_INITIAL_GAIN);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_AMPLITUDE_SECOND_GAIN
String paramString27(buffer);
temp1 = paramString27.toInt();
sd0[0].MODULATION_AMPLITUDE_SECOND_GAIN = (int32_t)(UINT16_MAX * (1.0 - DECIBEL_SHIFT(temp1))) * 4;
Serial.println(sd0[0].MODULATION_AMPLITUDE_SECOND_GAIN);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get closing parenthesis
Serial.println(buffer);
for (int k = 1; k < numRanges; k++) {
lcd.print("."); // progress indicator
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get opening parenthesis (except in last record
Serial.println(buffer);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get region name
Serial.println(buffer);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get loop true/false
String paramString28(buffer);
sIndex = paramString28.indexOf("true", 0);
if (sIndex >= 0) {
sd0[k].LOOP = true;
Serial.println("true");
}
else {
sd0[k].LOOP = false;
Serial.println("false");
}
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get INDEX_BITS
String paramString29(buffer);
sd0[k].INDEX_BITS = paramString29.toInt();
Serial.println(sd0[k].INDEX_BITS);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get cents_offset
String paramString30(buffer);
cents_offset = paramString30.toInt();
Serial.println(cents_offset);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get sample_rate
String paramString31(buffer);
sample_rate = paramString31.toFloat();
Serial.println(sample_rate);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get sample_note
String paramString32(buffer);
sample_note = paramString32.toFloat();
Serial.println(sample_note);
// calculate PER_HERTZ_PHASE_INCREMENT
sd0[k].PER_HERTZ_PHASE_INCREMENT = (1 << (32 - sd0[k].INDEX_BITS)) * CENTS_SHIFT(cents_offset) * sample_rate / NOTE(sample_note) / AUDIO_SAMPLE_RATE_EXACT + 0.5;
Serial.println(sd0[k].PER_HERTZ_PHASE_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MAX_PHASE
String paramString33(buffer);
temp1 = paramString33.toInt();
Serial.println(temp1);
sd0[k].MAX_PHASE = ((uint32_t)temp1 - 1) << (32 - sd0[k].INDEX_BITS);
Serial.println(sd0[k].MAX_PHASE);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get LOOP_PHASE_END
String paramString34(buffer);
temp1 = paramString34.toInt();
tempT = temp1;
Serial.println(temp1);
sd0[k].LOOP_PHASE_END = ((uint32_t)temp1 - 1) << (32 - sd0[k].INDEX_BITS);
Serial.println(sd0[k].LOOP_PHASE_END);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get LOOP_PHASE_LENGTH
String paramString35(buffer);
temp1 = paramString35.toInt();
Serial.println(temp1);
sd0[k].LOOP_PHASE_LENGTH = ((((uint32_t)tempT - 1) << (32 - sd0[k].INDEX_BITS)) - (((uint32_t)temp1 - 1) << (32 - sd0[k].INDEX_BITS)));
Serial.println(sd0[k].LOOP_PHASE_LENGTH);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get INITIAL_ATTENUATION_SCALAR
String paramString36(buffer);
temp1 = paramString36.toInt();
sd0[k].INITIAL_ATTENUATION_SCALAR = (uint16_t)UINT16_MAX * DECIBEL_SHIFT(temp1);
Serial.println(sd0[k].INITIAL_ATTENUATION_SCALAR);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get DELAY_COUNT
String paramString37(buffer);
temp1 = paramString37.toFloat();
sd0[k].DELAY_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[k].DELAY_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get ATTACK_COUNT
String paramString38(buffer);
temp1 = paramString38.toFloat();
sd0[k].ATTACK_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[k].ATTACK_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get HOLD_COUNT
String paramString39(buffer);
temp1 = paramString39.toFloat();
sd0[k].HOLD_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[k].HOLD_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get DECAY_COUNT
String paramString40(buffer);
temp1 = paramString40.toFloat();
sd0[k].DECAY_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[k].DECAY_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get RELEASE_COUNT
String paramString41(buffer);
temp1 = paramString41.toFloat();
sd0[k].RELEASE_COUNT = uint32_t(temp1 * SAMPLES_PER_MSEC / ENVELOPE_PERIOD + 0.5);
Serial.println(sd0[k].RELEASE_COUNT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get SUSTAIN_MULT
String paramString42(buffer);
temp1 = paramString42.toFloat();
sd0[k].SUSTAIN_MULT = int32_t((1.0 - DECIBEL_SHIFT(temp1)) * UNITY_GAIN);
Serial.println(sd0[k].SUSTAIN_MULT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_DELAY
String paramString43(buffer);
temp1 = paramString43.toFloat();
sd0[k].VIBRATO_DELAY = uint32_t(temp1 * SAMPLES_PER_MSEC / (2 * LFO_PERIOD));
Serial.println(sd0[k].VIBRATO_DELAY);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_INCREMENT
String paramString44(buffer);
temp1 = paramString44.toFloat();
sd0[k].VIBRATO_INCREMENT = uint32_t(temp1 * LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));
Serial.println(sd0[k].VIBRATO_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_PITCH_COEFICIENT_INITIAL
String paramString45(buffer);
temp1 = paramString45.toFloat();
sd0[k].VIBRATO_PITCH_COEFFICIENT_INITIAL = (CENTS_SHIFT(temp1) - 1.0) * 4;
Serial.println(sd0[k].VIBRATO_PITCH_COEFFICIENT_INITIAL);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get VIBRATO_PITCH_COEFICIENT_SECOND
String paramString46(buffer);
temp1 = paramString46.toFloat();
sd0[k].VIBRATO_PITCH_COEFFICIENT_SECOND = (1.0 - CENTS_SHIFT(temp1)) * 4;
Serial.println(sd0[k].VIBRATO_PITCH_COEFFICIENT_SECOND);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_DELAY
String paramString47(buffer);
temp1 = paramString47.toFloat();
sd0[k].MODULATION_DELAY = uint32_t(temp1 * SAMPLES_PER_MSEC / (2 * LFO_PERIOD)),
Serial.println(sd0[k].MODULATION_DELAY);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_INCREMENT
String paramString48(buffer);
temp1 = paramString48.toFloat();
sd0[k].MODULATION_INCREMENT = uint32_t(temp1 * LFO_PERIOD * (UINT32_MAX / AUDIO_SAMPLE_RATE_EXACT));
Serial.println(sd0[k].MODULATION_INCREMENT);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_PITCH_COEFFICIENT_INITIAL
String paramString49(buffer);
temp1 = paramString49.toInt();
sd0[k].MODULATION_PITCH_COEFFICIENT_INITIAL = (CENTS_SHIFT(temp1) - 1.0) * 4;
Serial.println(sd0[k].MODULATION_PITCH_COEFFICIENT_INITIAL);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_PITCH_COEFFICIENT_SECOND
String paramString50(buffer);
temp1 = paramString50.toInt();
sd0[k].MODULATION_PITCH_COEFFICIENT_SECOND = (1.0 - CENTS_SHIFT(temp1)) * 4;
Serial.println(sd0[k].MODULATION_PITCH_COEFFICIENT_SECOND);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_AMPLITUDE_INITIAL_GAIN
String paramString51(buffer);
temp1 = paramString51.toInt();
sd0[k].MODULATION_AMPLITUDE_INITIAL_GAIN = (int32_t)(UINT16_MAX * (DECIBEL_SHIFT(temp1) - 1.0)) * 4;
Serial.println(sd0[k].MODULATION_AMPLITUDE_INITIAL_GAIN);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get MODULATION_AMPLITUDE_SECOND_GAIN
String paramString52(buffer);
temp1 = paramString52.toInt();
sd0[k].MODULATION_AMPLITUDE_SECOND_GAIN = (int32_t)(UINT16_MAX * (1.0 - DECIBEL_SHIFT(temp1))) * 4;
Serial.println(sd0[k].MODULATION_AMPLITUDE_SECOND_GAIN);
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get closing parenthesis
Serial.println(buffer);
}
uint32_t accumulator = 0; // accumulate the wave file lengths of each region, and use to make pointers into SAMPL_BUFFER
for (int k = 0; k < numRanges; k++) {
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get blank line
l = myFile.readBytesUntil('\n', buffer, sizeof(buffer)); // get wavetable sample size
String paramString78(buffer); // isolate length of region of waveform samples- then used as pointer to next region
sIndex = paramString78.indexOf("[", 0);
sIndex++;
fIndex = paramString78.indexOf("]", 0);
String tmpString3 = paramString78.substring(sIndex, fIndex);
uint16_t temp2 = tmpString3.toInt();
sd0[k].sample = (int16_t*)&SAMPLE_BUFFER[accumulator];
accumulator += temp2;
}
displayProgramName();
myFile.close();
}
if (err == -1) {
voiceLoading = false;
return err;
}
voiceLoading = false;
return err;
}
void checkSDCard() {
while (!(SD.begin(BUILTIN_SDCARD))) {
// stop here, but print a message repetitively
lcd.clear();
lcd.print("Can't access SD card");
delay(1000);
lcd.clear();
delay(1000);
}
}
int allocateVoice(byte channel, byte note) {
for (int i = 1; i < TOTAL_VOICES; i++) {
if (noteAlloc[i] == 0) {
noteAlloc[i] = note;
return i;
break;
}
}
return -1;
}
void freeVoices() {
for (int i = 0; i < TOTAL_VOICES; i++)
if (wavetable[i].isPlaying() == false && noteAlloc[i] == -1) {
noteAlloc[i] = 0;
}
}
int findVoice(byte channel, byte note) {
for (int i = 1; i < TOTAL_VOICES; i++) {
if (noteAlloc[i] == note) {
noteAlloc[i] = -1;
return i;
break;
}
}
return -1;
}
void handleNoteOn(byte channel, byte note, byte velocity) {
digitalWrite(LED, HIGH);
notes_played++;
Serial.print("note= ");
Serial.println(note);
int wavetable_id = allocateVoice(channel, note);
Serial.println(wavetable_id);
wavetable[wavetable_id].playNote(note, velocity);
int usage = AudioProcessorUsage();
Serial.print("CPU= ");
Serial.println(usage);
}
void handleNoteOff(byte channel, byte note, byte velocity) {
digitalWrite(LED, LOW);
int wavetable_id = findVoice(channel, note);
if (wavetable_id != -1)
wavetable[wavetable_id].stop();
}
void handleProgramChange(byte channel, byte number) {
if (voiceLoading == true) {
return;
}
programNumber = number;
if (programNumber == 0) {
programNumber=1;
}
for (int i = 0; i < TOTAL_VOICES;i++) { // silence all voices
wavetable[i].stop();
}
loadVoice(programNumber);
}
void handleControlChange(byte channel, byte number, byte value) {
controlNumber = number;
controlValue = value;
currentControlValue = (int) value;
if (controlNumber == 1) { // Modulation Wheel
for (int i = 0; i < numRanges; i++) {
sd0[i].MODULATION_PITCH_COEFFICIENT_INITIAL = (float)controlValue / 512.0;
sd0[i].MODULATION_PITCH_COEFFICIENT_SECOND = (float)controlValue/ 512.0;
}
}
if (controlNumber == 7) { // MIDI volume
float gain;
// simulate an Audio Taper pot
if (controlValue < 64) {
gain =(float) controlValue* (0.1 / 64.0);
}
else {
gain = 0.1 + ((controlValue - 64) * 0.9 / 64);
}
mixer3.gain(0, gain);
mixer3.gain(1,gain );
}
// now process the 7 filter gain controllers
if (learnMode == false) { // don't process filter changes while in learn mode
if (controlNumber == cfg.Control_Translation_Map[0]) adjustFilter1();
if (controlNumber == cfg.Control_Translation_Map[1]) adjustFilter2();
if (controlNumber == cfg.Control_Translation_Map[2]) adjustFilter3();
if (controlNumber == cfg.Control_Translation_Map[3]) adjustFilter4();
if (controlNumber == cfg.Control_Translation_Map[4]) adjustFilter5();
if (controlNumber == cfg.Control_Translation_Map[5]) adjustFilter6();
if (controlNumber == cfg.Control_Translation_Map[6]) adjustFilter7();
}
}
void handlePitchBendChange(byte channel, int pbValue) {
Serial.print("pitchbend= ");
Serial.println(pbValue);
}
void handleAfterTouchChannel(byte channel, byte pressure) {
for (int i = 0; i < numRanges; i++) {
sd0[i].MODULATION_PITCH_COEFFICIENT_INITIAL = (float)pressure / 512.0;
sd0[i].MODULATION_PITCH_COEFFICIENT_SECOND = (float)pressure / 512.0;
}
}
void initConfigFile() {
for (int i = 0; i < 16; i++) {
cfg.Control_Translation_Map[i] = 0; // zero out the slider to filter adjust map (only 7 of 16 used at present)
}
for (int i = 0; i < 128; i++) {
cfg.filter1_value[i] = 64; // set all filter gains to mid-point
cfg.filter2_value[i] = 64;
cfg.filter3_value[i] = 64;
cfg.filter4_value[i] = 64;
cfg.filter5_value[i] = 64;
cfg.filter6_value[i] = 64;
cfg.filter7_value[i] = 64;
}
SD.remove("config.txt");
myFile = SD.open("config.txt",FILE_WRITE);
if (myFile) {
Serial.println("writing cfg file");
for (int i = 0; i < 16; i++) {
myFile.println(cfg.Control_Translation_Map[i]);
}
for (int i = 0; i < 128; i++) {
myFile.println(cfg.filter1_value[i]);
myFile.println(cfg.filter2_value[i]);
myFile.println(cfg.filter3_value[i]);
myFile.println(cfg.filter4_value[i]);
myFile.println(cfg.filter5_value[i]);
myFile.println(cfg.filter6_value[i]);
myFile.println(cfg.filter7_value[i]);
}
cfg.MIDI_channel = 0;
myFile.println(cfg.MIDI_channel);
Serial.println("file written");
myFile.close();
}
}
void loadConfigFile() {
myFile = SD.open("config.txt");
if (myFile) {
for (int i = 0; i < 16; i++) {
cfg.Control_Translation_Map[i] = myFile.parseInt();
Serial.println(cfg.Control_Translation_Map[i]);
}
for (int i = 0; i < 128; i++) {
cfg.filter1_value[i]= myFile.parseInt();
cfg.filter2_value[i] = myFile.parseInt();
cfg.filter3_value[i] = myFile.parseInt();
cfg.filter4_value[i] = myFile.parseInt();
cfg.filter5_value[i] = myFile.parseInt();
cfg.filter6_value[i] = myFile.parseInt();
cfg.filter7_value[i] = myFile.parseInt();
}
cfg.MIDI_channel = myFile.parseInt();
myFile.close();
}
}
void saveConfigFile() {
SD.remove("config.txt");
myFile = SD.open("config.txt", FILE_WRITE);
if (myFile) {
Serial.println("writing cfg file");
for (int i = 0; i < 16; i++) {
myFile.println(cfg.Control_Translation_Map[i]);
}
for (int i = 0; i < 128; i++) {
myFile.println(cfg.filter1_value[i]);
myFile.println(cfg.filter2_value[i]);
myFile.println(cfg.filter3_value[i]);
myFile.println(cfg.filter4_value[i]);
myFile.println(cfg.filter5_value[i]);
myFile.println(cfg.filter6_value[i]);
myFile.println(cfg.filter7_value[i]);
}
myFile.println(cfg.MIDI_channel);
Serial.println("file written");
Serial.print("Program #=");
Serial.println(programNumber);
myFile.close();
}
}
void menu() {
Serial.println("menu");
while (digitalRead(MENU) == LOW);;;
delay(100);
lcd.clear();
lcd.print("Learn mode- assign");
lcd.setCursor(0, 1);
lcd.print("sliders to filters");
int32_t REValue = 0;
REnc.write(REValue);
while (digitalRead(ENTER) == HIGH) {
MIDI.read(); // continue handling incoming keyboard events
RotaryEncoderValue = REnc.read();
if (RotaryEncoderValue != REValue) {
menuItem = RotaryEncoderValue;
if (menuItem < 0) {
menuItem = 0;
REnc.write(0);
}
if (menuItem > MAX_MENU_ITEMS) {
menuItem--;
REnc.write(menuItem);
}
Serial.println(menuItem);
delay(50);
switch (menuItem) {
case 0: lcd.clear();
lcd.print("Learn mode- assign");
lcd.setCursor(0, 1);
lcd.print("sliders to filters");
break;
case 1:lcd.clear();
lcd.print("MIDI channel- use ");
lcd.setCursor(0, 1);
lcd.print("0 for OMNI Mode");
break;
}
REValue = RotaryEncoderValue;
}
}
lcd.clear();
delay(50); // debounce ENTER switch
while (digitalRead(ENTER) == 0);;;
delay(150);
switch (menuItem) {
case 0: lcd.clear();
learn();
break;
case 1: lcd.clear();
setMIDIchannel();
break;
}
REnc.write(programNumber); // Restore RE to current program number
RotaryEncoderValue = programNumber;
}
void learn() {
byte lastControl=0;
learnMode = true;
Serial.print("in learn mode");
for ( int i = 1; i < 8; i++) {
byte lastControlValue = 0;
lcd.clear();
lcd.print("move slider for");
lcd.setCursor(0, 1);
lcd.print("FILTER #");
lcd.print(i);
bool controlMoved = false;
while (controlMoved == false) {
MIDI.read();
if (currentControl != lastControl) {
controlMoved = true;
}
}
controlMoved = false;
lastControlValue = currentControlValue;
while (controlMoved == false) {
MIDI.read();
if (currentControlValue != lastControlValue) {
controlMoved = true;
lcd.print(" got it");
delay(1000);
}
}
controlMoved = false;
cfg.Control_Translation_Map[i-1] = currentControl;
lastControl = currentControl;
Serial.print("current control= ");
Serial.println(currentControl);
}
saveConfigFile(); // save new map to SD card
lcd.clear();
lcd.print("Filter slider ");
lcd.setCursor(0, 1);
lcd.print("map saved");
delay(1000);
Serial.println("leaving learn mode");
learnMode = false;
displayProgramName();
}
void displayProgramName() {
lcd.clear();
lcd.print("Prog#");
lcd.print(programNumber);
lcd.setCursor(8, 0);
lcd.print("MIDI CH=");
if (cfg.MIDI_channel == 0) {
lcd.print("OMNI");
}
else {
lcd.print(cfg.MIDI_channel);
}
lcd.setCursor(0, 1);
lcd.print(voiceName);
}
void adjustFilter1() { // filter 1 amplitude
float val;
Serial.print("filter1 value = ");
Serial.println(127-currentControlValue);
cfg.filter1_value[programNumber-1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer1.gain(0, val) ; // 1st BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter2() { // filter 2 amplitude
float val;
Serial.print("filter2 value = ");
Serial.println(127 - currentControlValue);
cfg.filter2_value[programNumber-1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer1.gain(1, val); // 2nd BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter3() { // filter 3 amplitude
float val;
Serial.print("filter3 value = ");
Serial.println(127 - currentControlValue);
cfg.filter3_value[programNumber-1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer1.gain(2, val); // 3rd BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter4() { // filter 4 amplitude
float val;
Serial.print("filter4 value = ");
Serial.println(127 - currentControlValue);
cfg.filter4_value[programNumber-1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer1.gain(3, val); // 4th BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter5() { // filter 5 amplitude
float val;
Serial.print("filter5 value = ");
Serial.println(127 - currentControlValue);
cfg.filter5_value[programNumber-1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer2.gain(0, val); // 5th BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter6() { // filter 6 amplitude
float val;
Serial.print("filter6 value = ");
Serial.println(127 - currentControlValue);
cfg.filter6_value[programNumber - 1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer2.gain(1, val); // 6th BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void adjustFilter7() { // filter 7 amplitude
float val;
Serial.print("filter7 value = ");
Serial.println(127 - currentControlValue);
cfg.filter7_value[programNumber - 1] = 127 - currentControlValue;
val = (float)((127.0 - currentControlValue) / 32.0);
mixer2.gain(2, val); // 7th BANDPASS
Serial.print("gain= ");
Serial.println(val);
}
void setMIDIchannel() {
byte MIDI_channel = 0;
int32_t REValue = 0;
REnc.write(REValue);
lcd.print("MIDI CHANNEL= 0");
delay(200);
while (digitalRead(ENTER) == HIGH) {
MIDI_channel = REnc.read();
if (MIDI_channel != REValue) {
if (MIDI_channel ==255) {
MIDI_channel = 0;
REnc.write(0);
}
if (MIDI_channel > 16) {
MIDI_channel=16;
REnc.write(16);
}
lcd.clear();
lcd.print("MIDI channel= ");
lcd.print(MIDI_channel);
REValue = MIDI_channel;
}
}
Serial.print("MIDI_channel= ");
Serial.println(MIDI_channel);
MIDI.setInputChannel(MIDI_channel);
cfg.MIDI_channel = MIDI_channel;
saveConfigFile();
displayProgramName();
REnc.write(programNumber); // restore the RE to equal current program number
}
void setFilters() {
filter1.setBandpass(0, 150, 0.7);
filter1.setBandpass(1, 150, 0.7);
filter1.setBandpass(2, 150, 0.7);
filter1.setBandpass(3, 150, 0.7);
filter2.setBandpass(0, 300, 0.7);
filter2.setBandpass(1, 300, 0.7);
filter2.setBandpass(2, 300, 0.7);
filter2.setBandpass(3, 300, 0.7);
filter3.setBandpass(0, 600, 1.4);
filter3.setBandpass(1, 600, 1.4);
filter3.setBandpass(2, 600, 1.4);
filter3.setBandpass(3, 600, 1.4);
filter4.setBandpass(0, 1000, 1.4);
filter4.setBandpass(1, 1000, 1.4);
filter4.setBandpass(2, 1000, 1.4);
filter4.setBandpass(3, 1000, 1.4);
filter5.setBandpass(0, 2000, 1.4);
filter5.setBandpass(1, 2000, 1.4);
filter5.setBandpass(2, 2000, 1.4);
filter5.setBandpass(3, 2000, 1.4);
filter6.setBandpass(0, 4000, 1.4);
filter6.setBandpass(1, 4000, 1.4);
filter6.setBandpass(2, 4000, 1.4);
filter6.setBandpass(3, 4000, 1.4);
filter7.setBandpass(0, 7000, 1.4);
filter7.setBandpass(1, 7000, 1.4);
filter7.setBandpass(2, 7000, 1.4);
filter7.setBandpass(3, 7000, 1.4);
}