From 1ac38718b783ccca9f393f9f4f3df55bba8c103a Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Mon, 11 Mar 2019 13:58:51 +0100 Subject: [PATCH 01/13] Adding function for checking, if sound is produced. If not, shut down the voice. --- MicroDexed.ino | 14 +++++++++++--- config.h | 3 ++- dexed.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- dexed.h | 2 ++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index aebf63e..d68d092 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -123,6 +123,7 @@ uint8_t effect_delay_feedback = 0; uint8_t effect_delay_volume = 0; bool effect_delay_sync = 0; elapsedMicros fill_audio_buffer; +elapsedMillis control_rate; #ifdef SHOW_CPU_LOAD_MSEC elapsedMillis cpu_mem_millis; @@ -335,6 +336,13 @@ void loop() // MIDI input handling check_midi_devices(); + // Shutdown unused voices + if (control_rate > CONTROL_RATE_MS) + { + control_rate = 0; + uint8_t shutdown_voices = dexed->getNumNotesPlaying(); + } + #ifdef I2C_DISPLAY // UI if (master_timer >= TIMER_UI_HANDLING_MS) @@ -355,7 +363,7 @@ void loop() } /****************************************************************************** - * MIDI MESSAGE HANDLER + MIDI MESSAGE HANDLER ******************************************************************************/ void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) { @@ -654,9 +662,9 @@ void handleSystemReset(void) } /****************************************************************************** - * END OF MIDI MESSAGE HANDLER + END OF MIDI MESSAGE HANDLER ******************************************************************************/ - + bool checkMidiChannel(byte inChannel) { // check for MIDI channel diff --git a/config.h b/config.h index 77d4b90..6d2d771 100644 --- a/config.h +++ b/config.h @@ -60,7 +60,8 @@ //* DEXED AND EFECTS SETTINGS //************************************************************************************************* #define DEXED_ENGINE DEXED_ENGINE_MODERN // DEXED_ENGINE_MARKI // DEXED_ENGINE_OPL - +#define CONTROL_RATE_MS 200 + // EFFECTS #define FILTER_MAX_FREQ 10000 diff --git a/dexed.cpp b/dexed.cpp index 8a0a99e..33b3eee 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -63,7 +63,7 @@ Dexed::Dexed(int rate) voices[i].live = false; } - max_notes = 16; + max_notes = MAX_NOTES; currentNote = 0; resetControllers(); controllers.masterTune = 0; @@ -391,6 +391,51 @@ uint8_t Dexed::getMaxNotes(void) return max_notes; } +uint8_t Dexed::getNumNotesPlaying(void) +{ + uint8_t op_carrier = controllers.core->get_carrier_operators(data[134]); // look for carriers + uint8_t i; + + for (i = 0; i < max_notes; i++) + { + if (voices[i].live == true) + { + uint8_t op_amp = 0; + uint8_t op_carrier_num = 0; + + memset(&voiceStatus, 0, sizeof(VoiceStatus)); + + voices[i].dx7_note->peekVoiceStatus(voiceStatus); + + for (uint8_t op = 0; op < 6; op++) + { + uint8_t op_bit = static_cast(pow(2, op)); + + if ((op_carrier & op_bit) > 0) + { + { + // this voice is a carrier! + op_carrier_num++; + + if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) // this voice produces no audio output + op_amp++; + } + } + if (op_amp == op_carrier_num) + { + // all carrier-operators are silent -> disable the voice + voices[i].live = false; + voices[i].sustained = false; + voices[i].keydown = false; + Serial.print("Voice shutdown ["); + Serial.print(i,DEC); + Serial.println(F("]")); + } + } + } + } +} + bool Dexed::loadSysexVoice(uint8_t* new_data) { uint8_t* p_data = data; diff --git a/dexed.h b/dexed.h index 02a7383..de22102 100644 --- a/dexed.h +++ b/dexed.h @@ -160,6 +160,7 @@ class Dexed void keydown(uint8_t pitch, uint8_t velo); void setSustain(bool sustain); bool getSustain(void); + uint8_t getNumNotesPlaying(void); ProcessorVoice voices[MAX_NOTES]; Controllers controllers; @@ -190,6 +191,7 @@ class Dexed bool monoMode; bool refreshVoice; uint8_t engineType; + VoiceStatus voiceStatus; Lfo lfo; FmCore* engineMsfa; EngineMkI* engineMkI; From 3637e9c8070ac73d6572c69c5b9ff7b3f8df1271 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Sun, 21 Apr 2019 15:58:35 +0200 Subject: [PATCH 02/13] Several fixes. Added functions for detecting voices which do not produce any output. Fixing screen changing when volume encoder was moved. --- MicroDexed.ino | 19 ++++++++++++++++++- UI.cpp | 5 +++++ config.h | 1 + dexed.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- dexed.h | 2 ++ 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index f7dd9a6..49a284e 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -123,6 +123,8 @@ uint8_t effect_delay_feedback = 0; uint8_t effect_delay_volume = 0; bool effect_delay_sync = 0; elapsedMicros fill_audio_buffer; +elapsedMillis control_rate; +uint8_t shutdown_voices = 0; #ifdef SHOW_CPU_LOAD_MSEC elapsedMillis cpu_mem_millis; @@ -335,6 +337,21 @@ void loop() // MIDI input handling check_midi_devices(); + // Shutdown unused voices + if (control_rate > CONTROL_RATE_MS) + { + uint8_t tmp = shutdown_voices; + control_rate = 0; + dexed->getNumNotesPlaying(); + + if (tmp != shutdown_voices) + { + Serial.print(F("Active voices [")); + Serial.print(shutdown_voices); + Serial.println(F("]")); + } + } + #ifdef I2C_DISPLAY // UI if (master_timer >= TIMER_UI_HANDLING_MS) @@ -617,7 +634,7 @@ void handleSystemExclusive(byte *sysex, uint len) Serial.print(F(" = ")); Serial.print(sysex[5], DEC); Serial.print(F(", data_index = ")); - Serial.println(data_index,DEC); + Serial.println(data_index, DEC); #endif } #ifdef DEBUG diff --git a/UI.cpp b/UI.cpp index 64cfaca..026c7ee 100644 --- a/UI.cpp +++ b/UI.cpp @@ -235,6 +235,11 @@ void handle_ui(void) case 1: // right encoder moved switch (ui_state) { + case UI_VOLUME: + ui_state = UI_MAIN; + lcd.clear(); + ui_show_main(); + break; case UI_MAIN: switch (ui_main_state) { diff --git a/config.h b/config.h index 77d4b90..b864968 100644 --- a/config.h +++ b/config.h @@ -60,6 +60,7 @@ //* DEXED AND EFECTS SETTINGS //************************************************************************************************* #define DEXED_ENGINE DEXED_ENGINE_MODERN // DEXED_ENGINE_MARKI // DEXED_ENGINE_OPL +#define CONTROL_RATE_MS 200 // EFFECTS #define FILTER_MAX_FREQ 10000 diff --git a/dexed.cpp b/dexed.cpp index 8a0a99e..1e09062 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -63,7 +63,7 @@ Dexed::Dexed(int rate) voices[i].live = false; } - max_notes = 16; + max_notes = MAX_NOTES; currentNote = 0; resetControllers(); controllers.masterTune = 0; @@ -391,6 +391,53 @@ uint8_t Dexed::getMaxNotes(void) return max_notes; } +uint8_t Dexed::getNumNotesPlaying(void) +{ + uint8_t op_carrier = controllers.core->get_carrier_operators(data[134]); // look for carriers + uint8_t i; + uint8_t count_playing_voices=0; + + for (i = 0; i < max_notes; i++) + { + if (voices[i].live == true) + { + uint8_t op_amp = 0; + uint8_t op_carrier_num = 0; + + memset(&voiceStatus, 0, sizeof(VoiceStatus)); + + voices[i].dx7_note->peekVoiceStatus(voiceStatus); + + for (uint8_t op = 0; op < 6; op++) + { + if ((op_carrier & (1 >> op)) == 1) + { + { + // this voice is a carrier! + op_carrier_num++; + + if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) // this voice produces no audio output + op_amp++; + } + } + } + + if (op_amp == op_carrier_num) + { + // all carrier-operators are silent -> disable the voice + voices[i].live = false; + voices[i].sustained = false; + voices[i].keydown = false; + Serial.print(F("Voice shutdown: ")); + Serial.println(i, DEC); + } + else + count_playing_voices++; + } + } + return(count_playing_voices); +} + bool Dexed::loadSysexVoice(uint8_t* new_data) { uint8_t* p_data = data; diff --git a/dexed.h b/dexed.h index 02a7383..de22102 100644 --- a/dexed.h +++ b/dexed.h @@ -160,6 +160,7 @@ class Dexed void keydown(uint8_t pitch, uint8_t velo); void setSustain(bool sustain); bool getSustain(void); + uint8_t getNumNotesPlaying(void); ProcessorVoice voices[MAX_NOTES]; Controllers controllers; @@ -190,6 +191,7 @@ class Dexed bool monoMode; bool refreshVoice; uint8_t engineType; + VoiceStatus voiceStatus; Lfo lfo; FmCore* engineMsfa; EngineMkI* engineMkI; From 09037e4c735bbb01d7ebf8121933da67bf627d88 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Sun, 21 Apr 2019 18:21:56 +0200 Subject: [PATCH 03/13] Fixes for voice auto-shutdown. --- MicroDexed.ino | 14 ++++---------- dexed.cpp | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 49a284e..9ef338f 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -124,7 +124,7 @@ uint8_t effect_delay_volume = 0; bool effect_delay_sync = 0; elapsedMicros fill_audio_buffer; elapsedMillis control_rate; -uint8_t shutdown_voices = 0; +uint8_t active_voices = 0; #ifdef SHOW_CPU_LOAD_MSEC elapsedMillis cpu_mem_millis; @@ -340,16 +340,8 @@ void loop() // Shutdown unused voices if (control_rate > CONTROL_RATE_MS) { - uint8_t tmp = shutdown_voices; control_rate = 0; - dexed->getNumNotesPlaying(); - - if (tmp != shutdown_voices) - { - Serial.print(F("Active voices [")); - Serial.print(shutdown_voices); - Serial.println(F("]")); - } + active_voices = dexed->getNumNotesPlaying(); } #ifdef I2C_DISPLAY @@ -954,6 +946,8 @@ void show_cpu_and_mem_usage(void) Serial.print(peak, DEC); Serial.print(F(" BLOCKSIZE: ")); Serial.print(AUDIO_BLOCK_SAMPLES, DEC); + Serial.print(F(" ACTIVE_VOICES: ")); + Serial.print(active_voices, DEC); Serial.println(); AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); diff --git a/dexed.cpp b/dexed.cpp index 1e09062..04965a2 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -395,7 +395,7 @@ uint8_t Dexed::getNumNotesPlaying(void) { uint8_t op_carrier = controllers.core->get_carrier_operators(data[134]); // look for carriers uint8_t i; - uint8_t count_playing_voices=0; + uint8_t count_playing_voices = 0; for (i = 0; i < max_notes; i++) { @@ -405,19 +405,18 @@ uint8_t Dexed::getNumNotesPlaying(void) uint8_t op_carrier_num = 0; memset(&voiceStatus, 0, sizeof(VoiceStatus)); - voices[i].dx7_note->peekVoiceStatus(voiceStatus); for (uint8_t op = 0; op < 6; op++) { - if ((op_carrier & (1 >> op)) == 1) + if ((op_carrier & (1 << op))) { + // this voice is a carrier! + op_carrier_num++; + if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) { - // this voice is a carrier! - op_carrier_num++; - - if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) // this voice produces no audio output - op_amp++; + // this voice produces no audio output + op_amp++; } } } @@ -428,14 +427,16 @@ uint8_t Dexed::getNumNotesPlaying(void) voices[i].live = false; voices[i].sustained = false; voices[i].keydown = false; - Serial.print(F("Voice shutdown: ")); +#ifdef DEBUG + Serial.print(F("Shutdown voice: ")); Serial.println(i, DEC); +#endif } else count_playing_voices++; } } - return(count_playing_voices); + return (count_playing_voices); } bool Dexed::loadSysexVoice(uint8_t* new_data) From 0ebc87a1576c2d1327f4b16cd258ad53b022e94b Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Mon, 22 Apr 2019 08:19:58 +0200 Subject: [PATCH 04/13] Small fix. --- UI.cpp | 1 + config.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/UI.cpp b/UI.cpp index 026c7ee..1bb0a84 100644 --- a/UI.cpp +++ b/UI.cpp @@ -238,6 +238,7 @@ void handle_ui(void) case UI_VOLUME: ui_state = UI_MAIN; lcd.clear(); + enc[1].write(voice); ui_show_main(); break; case UI_MAIN: diff --git a/config.h b/config.h index b864968..71dbff8 100644 --- a/config.h +++ b/config.h @@ -31,7 +31,7 @@ // ATTENTION! For better latency you have to redefine AUDIO_BLOCK_SAMPLES from // 128 to 64 in /cores/teensy3/AudioStream.h -#define VERSION "0.9.2" +#define VERSION "0.9.3" //************************************************************************************************* //* DEVICE SETTINGS From 1b965c097573795c85a38e658bc805140318fe3d Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Tue, 23 Apr 2019 12:46:19 +0200 Subject: [PATCH 05/13] Added a configuration struct for holding parameters which should be stored in EEPROM. So I dropped most old EEPROM code. Also added storing to EEPROM only when AUTOSTORE_MS is reached and no voices are active. --- EEPROMAnything.h | 53 +++++++++++ MicroDexed.ino | 224 +++++++++++++---------------------------------- UI.cpp | 76 ++++++++-------- UI.h | 8 +- config.h | 26 +++--- 5 files changed, 165 insertions(+), 222 deletions(-) create mode 100644 EEPROMAnything.h diff --git a/EEPROMAnything.h b/EEPROMAnything.h new file mode 100644 index 0000000..b2a7515 --- /dev/null +++ b/EEPROMAnything.h @@ -0,0 +1,53 @@ +/* + MicroDexed + + MicroDexed is a port of the Dexed sound engine + (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6 with audio shield. + Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android + + (c)2018 H. Wirtz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + // Idea from: https://playground.arduino.cc/Code/EEPROMWriteAnything/ + +#include +#include // for type definitions + +uint32_t crc32(uint8_t* calc_start, uint16_t calc_bytes); + +template int EEPROM_writeAnything(int ee, const T& value) +{ + uint8_t* p = (uint8_t*)(const void*)&value; + uint16_t i; + uint32_t checksum=crc32(p+4,sizeof(value)-4); + + *p=checksum; + + for (i = 0; i < sizeof(value); i++) + EEPROM.update(ee++, *p++); + return i; +} + +template int EEPROM_readAnything(int ee, T& value) +{ + uint8_t* p = (uint8_t*)(void*)&value; + unsigned int i; + for (i = 0; i < sizeof(value); i++) + *p++ = EEPROM.read(ee++); + return i; +} diff --git a/MicroDexed.ino b/MicroDexed.ino index 9ef338f..f714d8a 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -29,6 +29,7 @@ #include #include #include +#include "EEPROMAnything.h" #include "midi_devices.hpp" #include #include "dexed.h" @@ -94,16 +95,11 @@ AudioConnection patchCord15(volume_l, 0, pt8211_1, 1); Dexed* dexed = new Dexed(SAMPLE_RATE); bool sd_card_available = false; -uint8_t midi_channel = DEFAULT_MIDI_CHANNEL; uint32_t xrun = 0; uint32_t overload = 0; uint32_t peak = 0; uint16_t render_time_max = 0; -uint8_t bank = 0; uint8_t max_loaded_banks = 0; -uint8_t voice = 0; -float vol = VOLUME; -float pan = 0.5f; char bank_name[BANK_NAME_LEN]; char voice_name[VOICE_NAME_LEN]; char bank_names[MAX_BANKS][BANK_NAME_LEN]; @@ -125,16 +121,10 @@ bool effect_delay_sync = 0; elapsedMicros fill_audio_buffer; elapsedMillis control_rate; uint8_t active_voices = 0; - #ifdef SHOW_CPU_LOAD_MSEC elapsedMillis cpu_mem_millis; #endif - -#ifdef TEST_NOTE -IntervalTimer sched_note_on; -IntervalTimer sched_note_off; -uint8_t _voice_counter = 0; -#endif +config_t configuration = {0xffff, 0, 0, VOLUME, 0.5f, DEFAULT_MIDI_CHANNEL}; void setup() { @@ -194,7 +184,7 @@ void setup() Serial.println(F("PT8211 enabled.")); #endif - set_volume(vol, pan); + set_volume(configuration.vol, configuration.pan); // start SD card SPI.setMOSI(SDCARD_MOSI_PIN); @@ -212,13 +202,13 @@ void setup() // read all bank names max_loaded_banks = get_bank_names(); - strip_extension(bank_names[bank], bank_name); + strip_extension(bank_names[configuration.bank], bank_name); // read all voice name for actual bank - get_voice_names_from_bank(bank); + get_voice_names_from_bank(configuration.bank); #ifdef DEBUG Serial.print(F("Bank [")); - Serial.print(bank_names[bank]); + Serial.print(bank_names[configuration.bank]); Serial.print(F("/")); Serial.print(bank_name); Serial.println(F("]")); @@ -251,13 +241,13 @@ void setup() mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) // load default SYSEX data - load_sysex(bank, voice); + load_sysex(configuration.bank, configuration.voice); } #ifdef I2C_DISPLAY - enc[0].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); + enc[0].write(map(configuration.vol * 100, 0, 100, 0, ENC_VOL_STEPS)); enc_val[0] = enc[0].read(); - enc[1].write(voice); + enc[1].write(configuration.voice); enc_val[1] = enc[1].read(); but[0].update(); but[1].update(); @@ -271,9 +261,9 @@ void setup() #ifdef DEBUG Serial.print(F("Bank/Voice from EEPROM [")); - Serial.print(EEPROM.read(EEPROM_OFFSET + EEPROM_BANK_ADDR), DEC); + Serial.print(configuration.bank, DEC); Serial.print(F("/")); - Serial.print(EEPROM.read(EEPROM_OFFSET + EEPROM_VOICE_ADDR), DEC); + Serial.print(configuration.voice, DEC); Serial.println(F("]")); show_patch(); #endif @@ -322,15 +312,15 @@ void loop() } #ifndef TEENSY_AUDIO_BOARD for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) - audio_buffer[i] *= vol; + audio_buffer[i] *= configuration.vol; #endif queue1.playBuffer(); } // EEPROM update handling - if (eeprom_update_status > 0 && autostore >= autostore_value) + if (autostore >= AUTOSTORE_MS && active_voices == 0) { - autostore = 0; + // only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore eeprom_update(); } @@ -397,7 +387,7 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) case 0: if (inValue < MAX_BANKS) { - bank = inValue; + configuration.bank = inValue; handle_ui(); } break; @@ -414,15 +404,15 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) dexed->controllers.refresh(); break; case 7: // Volume - vol = float(inValue) / 0x7f; - set_volume(vol, pan); + configuration.vol = float(inValue) / 0x7f; + set_volume(configuration.vol, configuration.pan); break; case 10: // Pan - pan = float(inValue) / 128; - set_volume(vol, pan); + configuration.pan = float(inValue) / 128; + set_volume(configuration.vol, configuration.pan); break; case 32: // BankSelect LSB - bank = inValue; + configuration.bank = inValue; break; case 64: dexed->setSustain(inValue > 63); @@ -511,12 +501,12 @@ void handleProgramChange(byte inChannel, byte inProgram) { if (inProgram < MAX_VOICES) { - load_sysex(bank, inProgram); + load_sysex(configuration.bank, inProgram); handle_ui(); } } -void handleSystemExclusive(byte *sysex, uint len) +void handleSystemExclusive(byte * sysex, uint len) { /* SYSEX MESSAGE: Parameter Change @@ -705,23 +695,23 @@ void handleSystemReset(void) } /****************************************************************************** - END OF MIDI MESSAGE HANDLER + MIDI HELPER ******************************************************************************/ bool checkMidiChannel(byte inChannel) { // check for MIDI channel - if (midi_channel == MIDI_CHANNEL_OMNI) + if (configuration.midi_channel == MIDI_CHANNEL_OMNI) { return (true); } - else if (inChannel != midi_channel) + else if (inChannel != configuration.midi_channel) { #ifdef DEBUG Serial.print(F("Ignoring MIDI data on channel ")); Serial.print(inChannel); Serial.print(F("(listening on ")); - Serial.print(midi_channel); + Serial.print(configuration.midi_channel); Serial.println(F(")")); #endif return (false); @@ -729,30 +719,27 @@ bool checkMidiChannel(byte inChannel) return (true); } +/****************************************************************************** + VOLUME HELPER + ******************************************************************************/ + void set_volume(float v, float p) { - vol = v; - pan = p; + configuration.vol = v; + configuration.pan = p; #ifdef DEBUG - uint8_t tmp; Serial.print(F("Setting volume: VOL=")); Serial.print(v, DEC); Serial.print(F("[")); - tmp = EEPROM.read(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR); - Serial.print(tmp, DEC); - Serial.print(F("/")); - Serial.print(float(tmp) / UCHAR_MAX, DEC); + Serial.print(configuration.vol, DEC); Serial.print(F("] PAN=")); Serial.print(F("[")); - tmp = EEPROM.read(EEPROM_OFFSET + EEPROM_PAN_ADDR); - Serial.print(tmp, DEC); - Serial.print(F("/")); - Serial.print(float(tmp) / SCHAR_MAX, DEC); + Serial.print(configuration.pan, DEC); Serial.print(F("] ")); - Serial.print(pow(v * sinf(p * PI / 2), VOLUME_CURVE), 3); + Serial.print(pow(configuration.vol * sinf(configuration.pan * PI / 2), VOLUME_CURVE), 3); Serial.print(F("/")); - Serial.println(pow(v * cosf(p * PI / 2), VOLUME_CURVE), 3); + Serial.println(pow(configuration.vol * cosf( configuration.pan * PI / 2), VOLUME_CURVE), 3); #endif // http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html @@ -771,58 +758,49 @@ inline float logvol(float x) return (0.001 * expf(6.908 * x)); } + +/****************************************************************************** + EEPROM HELPER + ******************************************************************************/ + void initial_values_from_eeprom(void) { - uint32_t crc_eeprom = read_eeprom_checksum(); - uint32_t crc = eeprom_crc32(EEPROM_OFFSET, EEPROM_DATA_LENGTH); + uint32_t checksum; + + EEPROM_readAnything(EEPROM_START_ADDRESS, configuration); + checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); #ifdef DEBUG Serial.print(F("EEPROM checksum: 0x")); - Serial.print(crc_eeprom, HEX); + Serial.print(configuration.checksum, HEX); Serial.print(F(" / 0x")); - Serial.print(crc, HEX); + Serial.print(checksum, HEX); #endif - if (crc_eeprom != crc) + + if (checksum != configuration.checksum) { #ifdef DEBUG Serial.print(F(" - mismatch -> initializing EEPROM!")); #endif - eeprom_write(EEPROM_UPDATE_BANK + EEPROM_UPDATE_VOICE + EEPROM_UPDATE_VOL + EEPROM_UPDATE_PAN + EEPROM_UPDATE_MIDICHANNEL); - } - else - { - bank = EEPROM.read(EEPROM_OFFSET + EEPROM_BANK_ADDR); - voice = EEPROM.read(EEPROM_OFFSET + EEPROM_VOICE_ADDR); - vol = float(EEPROM.read(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR)) / UCHAR_MAX; - pan = float(EEPROM.read(EEPROM_OFFSET + EEPROM_PAN_ADDR)) / SCHAR_MAX; - midi_channel = EEPROM.read(EEPROM_OFFSET + EEPROM_MIDICHANNEL_ADDR); - if (midi_channel > 16) - midi_channel = MIDI_CHANNEL_OMNI; + eeprom_update(); } #ifdef DEBUG Serial.println(); #endif } -uint32_t read_eeprom_checksum(void) -{ - return (EEPROM.read(EEPROM_CRC32_ADDR) << 24 | EEPROM.read(EEPROM_CRC32_ADDR + 1) << 16 | EEPROM.read(EEPROM_CRC32_ADDR + 2) << 8 | EEPROM.read(EEPROM_CRC32_ADDR + 3)); -} - -void update_eeprom_checksum(void) +void eeprom_write(void) { - write_eeprom_checksum(eeprom_crc32(EEPROM_OFFSET, EEPROM_DATA_LENGTH)); // recalculate crc and write to eeprom + autostore = 0; } -void write_eeprom_checksum(uint32_t crc) +void eeprom_update(void) { - EEPROM.update(EEPROM_CRC32_ADDR, (crc & 0xff000000) >> 24); - EEPROM.update(EEPROM_CRC32_ADDR + 1, (crc & 0x00ff0000) >> 16); - EEPROM.update(EEPROM_CRC32_ADDR + 2, (crc & 0x0000ff00) >> 8); - EEPROM.update(EEPROM_CRC32_ADDR + 3, crc & 0x000000ff); + autostore = 0; + EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration); } -uint32_t eeprom_crc32(uint16_t calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc +uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc { const uint32_t crc_table[16] = { @@ -833,97 +811,19 @@ uint32_t eeprom_crc32(uint16_t calc_start, uint16_t calc_bytes) // base code fro }; uint32_t crc = ~0L; - if (calc_start + calc_bytes > EEPROM.length()) - calc_bytes = EEPROM.length() - calc_start; - - for (uint16_t index = calc_start ; index < (calc_start + calc_bytes) ; ++index) + for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index) { - crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4); - crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4); crc = ~crc; } return (crc); } -void eeprom_write(uint8_t status) -{ - eeprom_update_status |= status; - if (eeprom_update_status != 0) - autostore = 0; -#ifdef DEBUG - Serial.print(F("Updating EEPROM state to: ")); - Serial.println(eeprom_update_status, DEC); -#endif -} - -void eeprom_update(void) -{ - autostore_value = AUTOSTORE_FAST_MS; - - if (eeprom_update_status & EEPROM_UPDATE_BANK) - { - EEPROM.update(EEPROM_OFFSET + EEPROM_BANK_ADDR, bank); -#ifdef DEBUG - Serial.println(F("Bank written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_BANK; - } - else if (eeprom_update_status & EEPROM_UPDATE_VOICE) - { - EEPROM.update(EEPROM_OFFSET + EEPROM_VOICE_ADDR, voice); -#ifdef DEBUG - Serial.println(F("Voice written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_VOICE; - } - else if (eeprom_update_status & EEPROM_UPDATE_VOL) - { - EEPROM.update(EEPROM_OFFSET + EEPROM_MASTER_VOLUME_ADDR, uint8_t(vol * UCHAR_MAX)); -#ifdef DEBUG - Serial.println(F("Volume written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_VOL; - } - else if (eeprom_update_status & EEPROM_UPDATE_PAN) - { - EEPROM.update(EEPROM_OFFSET + EEPROM_PAN_ADDR, uint8_t(pan * SCHAR_MAX)); -#ifdef DEBUG - Serial.println(F("Panorama written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_PAN; - } - else if (eeprom_update_status & EEPROM_UPDATE_MIDICHANNEL ) - { - EEPROM.update(EEPROM_OFFSET + EEPROM_MIDICHANNEL_ADDR, midi_channel); - update_eeprom_checksum(); -#ifdef DEBUG - Serial.println(F("MIDI channel written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_MIDICHANNEL; - } - else if (eeprom_update_status & EEPROM_UPDATE_CHECKSUM) - { - update_eeprom_checksum(); -#ifdef DEBUG - Serial.println(F("Checksum written to EEPROM")); -#endif - eeprom_update_status &= ~EEPROM_UPDATE_CHECKSUM; - autostore_value = AUTOSTORE_MS; - return; - } - - if (eeprom_update_status == 0) - eeprom_update_status |= EEPROM_UPDATE_CHECKSUM; -} - -void init_eeprom(void) -{ - for (uint8_t i = 0; i < EEPROM_DATA_LENGTH; i++) - { - EEPROM.update(EEPROM_OFFSET + i, 0); - } -} +/****************************************************************************** + DEBUG HELPER + ******************************************************************************/ #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) void show_cpu_and_mem_usage(void) diff --git a/UI.cpp b/UI.cpp index 1bb0a84..2055816 100644 --- a/UI.cpp +++ b/UI.cpp @@ -38,7 +38,7 @@ void handle_ui(void) { if (ui_back_to_main >= UI_AUTO_BACK_MS && (ui_state != UI_MAIN && ui_state != UI_EFFECTS_FILTER && ui_state != UI_EFFECTS_DELAY)) { - enc[0].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); + enc[0].write(map(configuration.vol * 100, 0, 100, 0, ENC_VOL_STEPS)); enc_val[0] = enc[0].read(); ui_show_main(); } @@ -97,7 +97,7 @@ void handle_ui(void) break; case UI_EFFECTS_DELAY: ui_main_state = UI_MAIN_VOICE; - enc[i].write(voice); + enc[i].write(configuration.voice); enc_val[i] = enc[i].read(); ui_show_main(); break; @@ -114,17 +114,17 @@ void handle_ui(void) switch (ui_state) { case UI_MAIN: - enc[i].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); + enc[i].write(map(configuration.vol * 100, 0, 100, 0, ENC_VOL_STEPS)); enc_val[i] = enc[i].read(); ui_show_volume(); break; case UI_VOLUME: - enc[i].write(midi_channel); + enc[i].write(configuration.midi_channel); enc_val[i] = enc[i].read(); ui_show_midichannel(); break; case UI_MIDICHANNEL: - enc[i].write(map(vol * 100, 0, 100, 0, ENC_VOL_STEPS)); + enc[i].write(map(configuration.vol * 100, 0, 100, 0, ENC_VOL_STEPS)); enc_val[i] = enc[i].read(); ui_show_main(); break; @@ -139,13 +139,13 @@ void handle_ui(void) case UI_MAIN_BANK: case UI_MAIN_BANK_SELECTED: ui_main_state = UI_MAIN_VOICE; - enc[i].write(voice); + enc[i].write(configuration.voice); enc_val[i] = enc[i].read(); break; case UI_MAIN_VOICE: case UI_MAIN_VOICE_SELECTED: ui_main_state = UI_MAIN_BANK; - enc[i].write(bank); + enc[i].write(configuration.bank); enc_val[i] = enc[i].read(); break; } @@ -217,8 +217,8 @@ void handle_ui(void) enc[i].write(0); else if (enc[i].read() >= ENC_VOL_STEPS) enc[i].write(ENC_VOL_STEPS); - set_volume(float(map(enc[i].read(), 0, ENC_VOL_STEPS, 0, 100)) / 100, pan); - eeprom_write(EEPROM_UPDATE_VOL); + set_volume(float(map(enc[i].read(), 0, ENC_VOL_STEPS, 0, 100)) / 100, configuration.pan); + eeprom_write(); ui_show_volume(); break; case UI_MIDICHANNEL: @@ -226,8 +226,8 @@ void handle_ui(void) enc[i].write(0); else if (enc[i].read() >= 16) enc[i].write(16); - midi_channel = enc[i].read(); - eeprom_write(EEPROM_UPDATE_MIDICHANNEL); + configuration.midi_channel = enc[i].read(); + eeprom_write(); ui_show_midichannel(); break; } @@ -238,7 +238,7 @@ void handle_ui(void) case UI_VOLUME: ui_state = UI_MAIN; lcd.clear(); - enc[1].write(voice); + enc[1].write(configuration.voice); ui_show_main(); break; case UI_MAIN: @@ -251,39 +251,39 @@ void handle_ui(void) enc[i].write(0); else if (enc[i].read() > max_loaded_banks - 1) enc[i].write(max_loaded_banks - 1); - bank = enc[i].read(); - get_voice_names_from_bank(bank); - load_sysex(bank, voice); - eeprom_write(EEPROM_UPDATE_BANK); + configuration.bank = enc[i].read(); + get_voice_names_from_bank(configuration.bank); + load_sysex(configuration.bank, configuration.voice); + eeprom_write(); break; case UI_MAIN_VOICE: ui_main_state = UI_MAIN_VOICE_SELECTED; case UI_MAIN_VOICE_SELECTED: if (enc[i].read() <= 0) { - if (bank > 0) + if (configuration.bank > 0) { enc[i].write(MAX_VOICES - 1); - bank--; - get_voice_names_from_bank(bank); + configuration.bank--; + get_voice_names_from_bank(configuration.bank); } else enc[i].write(0); } else if (enc[i].read() > MAX_VOICES - 1) { - if (bank < MAX_BANKS - 1) + if (configuration.bank < MAX_BANKS - 1) { enc[i].write(0); - bank++; - get_voice_names_from_bank(bank); + configuration.bank++; + get_voice_names_from_bank(configuration.bank); } else enc[i].write(MAX_VOICES - 1); } - voice = enc[i].read(); - load_sysex(bank, voice); - eeprom_write(EEPROM_UPDATE_VOICE); + configuration.voice = enc[i].read(); + load_sysex(configuration.bank, configuration.voice); + eeprom_write(); break; } ui_show_main(); @@ -411,9 +411,9 @@ void ui_show_main(void) lcd.clear(); } - lcd.show(0, 0, 2, bank); + lcd.show(0, 0, 2, configuration.bank); lcd.show(0, 2, 1, " "); - strip_extension(bank_names[bank], bank_name); + strip_extension(bank_names[configuration.bank], bank_name); if (ui_main_state == UI_MAIN_BANK || ui_main_state == UI_MAIN_BANK_SELECTED) { @@ -428,18 +428,18 @@ void ui_show_main(void) lcd.show(0, 11, 1, " "); } - lcd.show(1, 0, 2, voice + 1); + lcd.show(1, 0, 2, configuration.voice + 1); lcd.show(1, 2, 1, " "); if (ui_main_state == UI_MAIN_VOICE || ui_main_state == UI_MAIN_VOICE_SELECTED) { lcd.show(1, 2, 1, "["); - lcd.show(1, 3, 10, voice_names[voice]); + lcd.show(1, 3, 10, voice_names[configuration.voice]); lcd.show(1, 14, 1, "]"); } else { lcd.show(1, 2, 1, " "); - lcd.show(1, 3, 10, voice_names[voice]); + lcd.show(1, 3, 10, voice_names[configuration.voice]); lcd.show(1, 14, 1, " "); } @@ -456,18 +456,18 @@ void ui_show_volume(void) lcd.show(0, 0, LCD_CHARS, "Volume"); } - lcd.show(0, LCD_CHARS - 3, 3, vol * 100); - if (vol == 0.0) + lcd.show(0, LCD_CHARS - 3, 3, configuration.vol * 100); + if (configuration.vol == 0.0) lcd.show(1, 0, LCD_CHARS , " "); else { - if (vol < (float(LCD_CHARS) / 100)) + if (configuration.vol < (float(LCD_CHARS) / 100)) lcd.show(1, 0, LCD_CHARS, "*"); else { - for (uint8_t i = 0; i < map(vol * 100, 0, 100, 0, LCD_CHARS); i++) + for (uint8_t i = 0; i < map(configuration.vol * 100, 0, 100, 0, LCD_CHARS); i++) lcd.show(1, i, 1, "*"); - for (uint8_t i = map(vol * 100, 0, 100, 0, LCD_CHARS); i < LCD_CHARS; i++) + for (uint8_t i = map(configuration.vol * 100, 0, 100, 0, LCD_CHARS); i < LCD_CHARS; i++) lcd.show(1, i, 1, " "); } } @@ -485,12 +485,12 @@ void ui_show_midichannel(void) lcd.show(0, 0, LCD_CHARS, "MIDI Channel"); } - if (midi_channel == MIDI_CHANNEL_OMNI) + if (configuration.midi_channel == MIDI_CHANNEL_OMNI) lcd.show(1, 0, 4, "OMNI"); else { - lcd.show(1, 0, 2, midi_channel); - if (midi_channel == 1) + lcd.show(1, 0, 2, configuration.midi_channel); + if (configuration.midi_channel == 1) lcd.show(1, 2, 2, " "); } diff --git a/UI.h b/UI.h index c77003f..3d5dd35 100644 --- a/UI.h +++ b/UI.h @@ -36,18 +36,14 @@ extern Encoder4 enc[2]; extern int32_t enc_val[2]; extern Bounce but[2]; -extern float vol; -extern float pan; extern LiquidCrystalPlus_I2C lcd; -extern uint8_t bank; +extern config_t configuration; extern uint8_t max_loaded_banks; -extern uint8_t voice; extern char bank_name[BANK_NAME_LEN]; extern char voice_name[VOICE_NAME_LEN]; extern uint8_t ui_state; extern uint8_t ui_main_state; -extern uint8_t midi_channel; -extern void eeprom_write(uint8_t status); +extern void eeprom_write(void); extern void set_volume(float v, float pan); extern elapsedMillis autostore; extern elapsedMillis long_button_pressed; diff --git a/config.h b/config.h index 71dbff8..b996b29 100644 --- a/config.h +++ b/config.h @@ -145,22 +145,7 @@ #define AUTOSTORE_FAST_MS 50 // EEPROM address -#define EEPROM_OFFSET 0 -#define EEPROM_DATA_LENGTH 5 - -#define EEPROM_CRC32_ADDR EEPROM.length()-sizeof(uint32_t)-33 -#define EEPROM_BANK_ADDR 0 -#define EEPROM_VOICE_ADDR 1 -#define EEPROM_MASTER_VOLUME_ADDR 2 -#define EEPROM_PAN_ADDR 3 -#define EEPROM_MIDICHANNEL_ADDR 4 - -#define EEPROM_UPDATE_BANK (1<<0) -#define EEPROM_UPDATE_VOICE (1<<1) -#define EEPROM_UPDATE_VOL (1<<2) -#define EEPROM_UPDATE_PAN (1<<3) -#define EEPROM_UPDATE_MIDICHANNEL (1<<4) -#define EEPROM_UPDATE_CHECKSUM (1<<7) +#define EEPROM_START_ADDRESS 0 #define MAX_BANKS 100 #define MAX_VOICES 32 // voices per bank @@ -194,4 +179,13 @@ #define USE_TEENSY_DSP 1 #define SUM_UP_AS_INT 1 +// struct for holding the current configuration +struct config_t { + uint32_t checksum; + uint8_t bank; + uint8_t voice; + float vol; + float pan; + uint8_t midi_channel; +}; #endif // CONFIG_H_INCLUDED From 1866ed69a12e505c02602057f19a32e9e473fa75 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Tue, 23 Apr 2019 14:29:07 +0200 Subject: [PATCH 06/13] Added Dexed PluginFx code again - just for testing the 4pole filter. --- MicroDexed.ino | 13 ++- PluginFx.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ PluginFx.h | 72 +++++++++++++++++ config.h | 7 +- dexed.cpp | 11 +++ dexed.h | 2 + 6 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 PluginFx.cpp create mode 100644 PluginFx.h diff --git a/MicroDexed.ino b/MicroDexed.ino index f714d8a..3979a61 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -34,7 +34,7 @@ #include #include "dexed.h" #include "dexed_sysex.h" - +#include "PluginFx.h" #ifdef I2C_DISPLAY // selecting sounds by encoder, button and display #include "UI.h" #include @@ -240,6 +240,11 @@ void setup() mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback) mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) + // just for testing: + dexed->fx.uiReso=0.5; + dexed->fx.uiGain=0.5; + dexed->fx.uiCutoff=0.5; + // load default SYSEX data load_sysex(configuration.bank, configuration.voice); } @@ -327,15 +332,17 @@ void loop() // MIDI input handling check_midi_devices(); - // Shutdown unused voices + // CONTROL-RATE-EVENT-HANDLING if (control_rate > CONTROL_RATE_MS) { control_rate = 0; + + // Shutdown unused voices active_voices = dexed->getNumNotesPlaying(); } #ifdef I2C_DISPLAY - // UI + // UI-HANDLING if (master_timer >= TIMER_UI_HANDLING_MS) { master_timer -= TIMER_UI_HANDLING_MS; diff --git a/PluginFx.cpp b/PluginFx.cpp new file mode 100644 index 0000000..c474565 --- /dev/null +++ b/PluginFx.cpp @@ -0,0 +1,216 @@ +/** + * + * Copyright (c) 2013-2014 Pascal Gauthier. + * Copyright (c) 2013-2014 Filatov Vadim. + * + * Filter taken from the Obxd project : + * https://github.com/2DaT/Obxd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define _USE_MATH_DEFINES +#include +#include "PluginFx.h" + +const float dc = 1e-18; + +inline static float tptpc(float& state,float inp,float cutoff) { + double v = (inp - state) * cutoff / (1 + cutoff); + double res = v + state; + state = res + v; + return res; +} + +inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) { + cutoff = (cutoff * srInv)*M_PI; + double v = (inp - state) * cutoff / (1 + cutoff); + double res = v + state; + state = res + v; + return res; +} + +//static float linsc(float param,const float min,const float max) { +// return (param) * (max - min) + min; +//} + +static float logsc(float param, const float min,const float max,const float rolloff = 19.0f) { + return ((expf(param * logf(rolloff+1)) - 1.0f) / (rolloff)) * (max-min) + min; +} + +PluginFx::PluginFx() { + uiCutoff = 1; + uiReso = 0; + uiGain = 1; +} + +void PluginFx::init(int sr) { + mm=0; + s1=s2=s3=s4=c=d=0; + R24=0; + + mmch = (int)(mm * 3); + mmt = mm*3-mmch; + + sampleRate = sr; + sampleRateInv = 1/sampleRate; + float rcrate =sqrt((44000/sampleRate)); + rcor24 = (970.0 / 44000)*rcrate; + rcor24Inv = 1 / rcor24; + + bright = tan((sampleRate*0.5f-10) * M_PI * sampleRateInv); + + R = 1; + rcor = (480.0 / 44000)*rcrate; + rcorInv = 1 / rcor; + bandPassSw = false; + + pCutoff = -1; + pReso = -1; + + dc_r = 1.0-(126.0/sr); + dc_id = 0; + dc_od = 0; +} + +inline float PluginFx::NR24(float sample,float g,float lpc) { + float ml = 1 / (1+g); + float S = (lpc*(lpc*(lpc*s1 + s2) + s3) +s4)*ml; + float G = lpc*lpc*lpc*lpc; + float y = (sample - R24 * S) / (1 + R24*G); + return y + 1e-8; +}; + +inline float PluginFx::NR(float sample, float g) { + float y = ((sample- R * s1*2 - g*s1 - s2)/(1+ g*(2*R + g))) + dc; + return y; +} + +void PluginFx::process(float *work, int sampleSize) { + // very basic DC filter + float t_fd = work[0]; + work[0] = work[0] - dc_id + dc_r * dc_od; + dc_id = t_fd; + for (int i=1; i #include #ifdef USE_TEENSY_DSP @@ -51,6 +52,7 @@ Dexed::Dexed(int rate) Lfo::init(rate); PitchEnv::init(rate); Env::init_sr(rate); + fx.init(rate); engineMkI = new EngineMkI; engineOpl = new EngineOpl; @@ -188,6 +190,15 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) } #endif } + + float fbuffer[n_samples]; + for (i = 0; i < n_samples; ++i) { + fbuffer[i] = static_cast(buffer[i] / 0x8000); + } + fx.process(fbuffer, n_samples); + for (i = 0; i < n_samples; ++i) { + buffer[i] = static_cast(fbuffer[i] * 0x8000); + } } void Dexed::keydown(uint8_t pitch, uint8_t velo) { diff --git a/dexed.h b/dexed.h index de22102..6188f1e 100644 --- a/dexed.h +++ b/dexed.h @@ -34,6 +34,7 @@ #include "fm_core.h" #include "EngineMkI.h" #include "EngineOpl.h" +#include "PluginFx.h" #include #include "config.h" @@ -164,6 +165,7 @@ class Dexed ProcessorVoice voices[MAX_NOTES]; Controllers controllers; + PluginFx fx; uint8_t data[173] = { 95, 29, 20, 50, 99, 95, 00, 00, 41, 00, 19, 00, 00, 03, 00, 06, 79, 00, 01, 00, 14, // OP6 eg_rate_1-4, level_1-4, kbd_lev_scl_brk_pt, kbd_lev_scl_lft_depth, kbd_lev_scl_rht_depth, kbd_lev_scl_lft_curve, kbd_lev_scl_rht_curve, kbd_rate_scaling, amp_mod_sensitivity, key_vel_sensitivity, operator_output_level, osc_mode, osc_freq_coarse, osc_freq_fine, osc_detune From 0560f84b1279fb725f431716bb44e23db5621732 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Wed, 24 Apr 2019 11:27:27 +0200 Subject: [PATCH 07/13] Fixes for autostoring configuration data to EEPROM. --- MicroDexed.ino | 33 ++++++++++++++++++++------------- config.h | 3 ++- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 3979a61..5c5d87a 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -105,8 +105,6 @@ char voice_name[VOICE_NAME_LEN]; char bank_names[MAX_BANKS][BANK_NAME_LEN]; char voice_names[MAX_VOICES][VOICE_NAME_LEN]; elapsedMillis autostore; -uint8_t eeprom_update_status = 0; -uint16_t autostore_value = AUTOSTORE_MS; uint8_t midi_timing_counter = 0; // 24 per qarter elapsedMillis midi_timing_timestep; uint16_t midi_timing_quarter = 0; @@ -125,6 +123,7 @@ uint8_t active_voices = 0; elapsedMillis cpu_mem_millis; #endif config_t configuration = {0xffff, 0, 0, VOLUME, 0.5f, DEFAULT_MIDI_CHANNEL}; +bool update_flag = false; void setup() { @@ -153,7 +152,6 @@ void setup() Serial.println(F("https://github.com/dcoredump/MicroDexed")); Serial.println(F("")); - //init_eeprom(); initial_values_from_eeprom(); setup_midi_devices(); @@ -241,9 +239,9 @@ void setup() mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) // just for testing: - dexed->fx.uiReso=0.5; - dexed->fx.uiGain=0.5; - dexed->fx.uiCutoff=0.5; + dexed->fx.uiReso = 0.5; + dexed->fx.uiGain = 0.5; + dexed->fx.uiCutoff = 0.5; // load default SYSEX data load_sysex(configuration.bank, configuration.voice); @@ -323,7 +321,7 @@ void loop() } // EEPROM update handling - if (autostore >= AUTOSTORE_MS && active_voices == 0) + if (autostore >= AUTOSTORE_MS && active_voices == 0 && update_flag == true) { // only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore eeprom_update(); @@ -336,7 +334,7 @@ void loop() if (control_rate > CONTROL_RATE_MS) { control_rate = 0; - + // Shutdown unused voices active_voices = dexed->getNumNotesPlaying(); } @@ -773,24 +771,30 @@ inline float logvol(float x) void initial_values_from_eeprom(void) { uint32_t checksum; + config_t tmp_conf; - EEPROM_readAnything(EEPROM_START_ADDRESS, configuration); - checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); + EEPROM_readAnything(EEPROM_START_ADDRESS, tmp_conf); + checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4); #ifdef DEBUG Serial.print(F("EEPROM checksum: 0x")); - Serial.print(configuration.checksum, HEX); + Serial.print(tmp_conf.checksum, HEX); Serial.print(F(" / 0x")); Serial.print(checksum, HEX); #endif - if (checksum != configuration.checksum) + if (checksum != tmp_conf.checksum) { #ifdef DEBUG Serial.print(F(" - mismatch -> initializing EEPROM!")); #endif eeprom_update(); } + else + { + EEPROM_readAnything(EEPROM_START_ADDRESS, configuration); + Serial.print(F(" - OK, loading!")); + } #ifdef DEBUG Serial.println(); #endif @@ -799,12 +803,15 @@ void initial_values_from_eeprom(void) void eeprom_write(void) { autostore = 0; + update_flag = true; } void eeprom_update(void) { - autostore = 0; + update_flag = false; + configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration); + Serial.println(F("Updating EEPROM with configuration data")); } uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc diff --git a/config.h b/config.h index 64fcc7a..a257a5c 100644 --- a/config.h +++ b/config.h @@ -31,7 +31,7 @@ // ATTENTION! For better latency you have to redefine AUDIO_BLOCK_SAMPLES from // 128 to 64 in /cores/teensy3/AudioStream.h -#define VERSION "0.9.3" +#define VERSION "0.9.4" //************************************************************************************************* //* DEVICE SETTINGS @@ -41,6 +41,7 @@ #define MIDI_DEVICE_DIN Serial1 #define MIDI_DEVICE_USB 1 #define MIDI_DEVICE_USB_HOST 1 +#define MIDI_DEVICE_NUMBER 0 // AUDIO // If nothing is defined PT8211 is used as audio output device! From 1147068fbe9f3eb61023e5f9fafa97df36a2d847 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Wed, 24 Apr 2019 15:49:43 +0200 Subject: [PATCH 08/13] Small fixes. --- MicroDexed.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 5c5d87a..deedcd4 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -123,7 +123,7 @@ uint8_t active_voices = 0; elapsedMillis cpu_mem_millis; #endif config_t configuration = {0xffff, 0, 0, VOLUME, 0.5f, DEFAULT_MIDI_CHANNEL}; -bool update_flag = false; +bool eeprom_update_flag = false; void setup() { @@ -150,6 +150,8 @@ void setup() Serial.println(F("MicroDexed based on https://github.com/asb2m10/dexed")); Serial.println(F("(c)2018,2019 H. Wirtz ")); Serial.println(F("https://github.com/dcoredump/MicroDexed")); + Serial.print(F("Version: ")); + Serial.println(VERSION); Serial.println(F("")); initial_values_from_eeprom(); @@ -321,7 +323,7 @@ void loop() } // EEPROM update handling - if (autostore >= AUTOSTORE_MS && active_voices == 0 && update_flag == true) + if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true) { // only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore eeprom_update(); @@ -803,12 +805,12 @@ void initial_values_from_eeprom(void) void eeprom_write(void) { autostore = 0; - update_flag = true; + eeprom_update_flag = true; } void eeprom_update(void) { - update_flag = false; + eeprom_update_flag = false; configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration); Serial.println(F("Updating EEPROM with configuration data")); From 5c164ccf273cb7d2baf68780456b48e07c08967a Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 25 Apr 2019 14:04:25 +0200 Subject: [PATCH 09/13] Fixing integration of 4pole filter. --- dexed.cpp | 81 +++++++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/dexed.cpp b/dexed.cpp index cdd9e06..7634fce 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -109,41 +109,41 @@ void Dexed::deactivate(void) void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) { uint16_t i; + float sumbuf[n_samples]; - if (refreshVoice) { - for (i = 0; i < max_notes; i++) { + if (refreshVoice) + { + for (i = 0; i < max_notes; i++) + { if ( voices[i].live ) voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity); } + lfo.reset(data + 137); refreshVoice = false; } - for (i = 0; i < n_samples; i += _N_) { + for (i = 0; i < n_samples; i += _N_) + { AlignedBuf audiobuf; -#ifndef SUM_UP_AS_INT - float sumbuf[_N_]; -#endif - for (uint8_t j = 0; j < _N_; ++j) { + for (uint8_t j = 0; j < _N_; ++j) + { audiobuf.get()[j] = 0; -#ifndef SUM_UP_AS_INT - sumbuf[j] = 0.0; -#else - buffer[i + j] = 0; -#endif + sumbuf[i + j] = 0.0; } int32_t lfovalue = lfo.getsample(); int32_t lfodelay = lfo.getdelay(); -#ifdef SUM_UP_AS_INT - int32_t sum; -#endif - for (uint8_t note = 0; note < max_notes; ++note) { - if (voices[note].live) { + for (uint8_t note = 0; note < max_notes; ++note) + { + if (voices[note].live) + { voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); - for (uint8_t j = 0; j < _N_; ++j) { + + for (uint8_t j = 0; j < _N_; ++j) + { int32_t val = audiobuf.get()[j]; val = val >> 4; #ifdef USE_TEENSY_DSP @@ -151,54 +151,29 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) #else int32_t clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; #endif -#ifdef SUM_UP_AS_INT - //sum = buffer[i + j] + (clip_val >> REDUCE_LOUDNESS)*(float(data[DEXED_GLOBAL_PARAMETER_OFFSET+DEXED_VOICE_VOLUME])/255); - sum = buffer[i + j] + (clip_val >> REDUCE_LOUDNESS); - if (buffer[i + j] > 0 && clip_val > 0 && sum < 0) - { - sum = INT_MAX; - overload++; - } - else if (buffer[i + j] < 0 && clip_val < 0 && sum > 0) - { - sum = INT_MIN; - overload++; - } - buffer[i + j] = sum; - audiobuf.get()[j] = 0; -#else + float f = static_cast(clip_val >> REDUCE_LOUDNESS) / 0x8000; - if (f > 1) + if (f > 1.0) { - f = 1; + f = 1.0; overload++; } - else if (f < -1) + else if (f < -1.0) { - f = -1; + f = -1.0; overload++; } - sumbuf[j] += f; + sumbuf[i + j] += f; audiobuf.get()[j] = 0; -#endif } } } -#ifndef SUM_UP_AS_INT - for (uint8_t j = 0; j < _N_; ++j) { - buffer[i + j] = static_cast(sumbuf[j] * 0x8000); - } -#endif } - float fbuffer[n_samples]; - for (i = 0; i < n_samples; ++i) { - fbuffer[i] = static_cast(buffer[i] / 0x8000); - } - fx.process(fbuffer, n_samples); - for (i = 0; i < n_samples; ++i) { - buffer[i] = static_cast(fbuffer[i] * 0x8000); - } + fx.process(sumbuf, n_samples); + + for (i = 0; i < n_samples; ++i) + buffer[i] = static_cast(sumbuf[i] * 0x8000); } void Dexed::keydown(uint8_t pitch, uint8_t velo) { From ba84fbc9d61a9529e25be0c788630ab842242845 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 25 Apr 2019 14:52:27 +0200 Subject: [PATCH 10/13] Exchanged double to float data types in PluginFX. Removed Teensy filter (is replaced by the Dexed internal filter) and antialias filter. --- MicroDexed.ino | 34 ++--- PluginFx.cpp | 358 ++++++++++++++++++++++++------------------------- PluginFx.h | 6 +- UI.cpp | 9 +- UI.h | 1 - 5 files changed, 198 insertions(+), 210 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index deedcd4..6ebf1cd 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -51,21 +51,14 @@ uint8_t ui_main_state = UI_MAIN_VOICE; AudioPlayQueue queue1; AudioAnalyzePeak peak1; -AudioFilterStateVariable filter1; AudioEffectDelay delay1; AudioMixer4 mixer1; AudioMixer4 mixer2; -AudioFilterBiquad antialias; AudioConnection patchCord0(queue1, peak1); -AudioConnection patchCord1(queue1, antialias); -AudioConnection patchCord2(antialias, 0, filter1, 0); -AudioConnection patchCord3(filter1, 0, delay1, 0); -AudioConnection patchCord4(filter1, 0, mixer1, 0); -AudioConnection patchCord5(filter1, 0, mixer2, 0); +AudioConnection patchCord9(queue1, 0, mixer1, 0); AudioConnection patchCord6(delay1, 0, mixer1, 1); AudioConnection patchCord7(delay1, 0, mixer2, 2); AudioConnection patchCord8(mixer1, delay1); -AudioConnection patchCord9(queue1, 0, mixer1, 3); // for disabling the filter AudioConnection patchCord10(mixer1, 0, mixer2, 1); #if defined(TEENSY_AUDIO_BOARD) AudioOutputI2S i2s1; @@ -225,25 +218,18 @@ void setup() #endif // Init effects - antialias.setLowpass(0, 6000, 0.707); - filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); - //filter1.resonance(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)); - filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); - filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME)); // mixer1 is the feedback-adding mixer, mixer2 the whole delay (with/without feedback) mixer mixer1.gain(0, 1.0); // original signal mixer1.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback - mixer1.gain(0, 0.0); // filtered signal off - mixer1.gain(3, 1.0); // original signal on mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback) mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) // just for testing: - dexed->fx.uiReso = 0.5; - dexed->fx.uiGain = 0.5; - dexed->fx.uiCutoff = 0.5; + dexed->fx.Reso = 0.5; + dexed->fx.Gain = 0.5; + dexed->fx.Cutoff = 0.5; // load default SYSEX data load_sysex(configuration.bank, configuration.voice); @@ -433,7 +419,7 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) } break; case 102: // CC 102: filter frequency - effect_filter_frq = map(inValue, 0, 127, 0, ENC_FILTER_FRQ_STEPS); +/* effect_filter_frq = map(inValue, 0, 127, 0, ENC_FILTER_FRQ_STEPS); if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) { // turn "off" filter @@ -447,17 +433,17 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) mixer1.gain(3, 0.0); // original signal off } filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); - handle_ui(); + handle_ui(); */ break; case 103: // CC 103: filter resonance - effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS); +/* effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS); filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); - handle_ui(); + handle_ui(); */ break; case 104: // CC 104: filter octave - effect_filter_octave = map(inValue, 0, 127, 0, ENC_FILTER_OCT_STEPS); +/* effect_filter_octave = map(inValue, 0, 127, 0, ENC_FILTER_OCT_STEPS); filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); - handle_ui(); + handle_ui(); */ break; case 105: // CC 105: delay time effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS); diff --git a/PluginFx.cpp b/PluginFx.cpp index c474565..2616ffd 100644 --- a/PluginFx.cpp +++ b/PluginFx.cpp @@ -1,26 +1,26 @@ /** - * - * Copyright (c) 2013-2014 Pascal Gauthier. - * Copyright (c) 2013-2014 Filatov Vadim. - * - * Filter taken from the Obxd project : - * https://github.com/2DaT/Obxd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ + + Copyright (c) 2013-2014 Pascal Gauthier. + Copyright (c) 2013-2014 Filatov Vadim. + + Filter taken from the Obxd project : + https://github.com/2DaT/Obxd + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ #define _USE_MATH_DEFINES #include @@ -28,189 +28,189 @@ const float dc = 1e-18; -inline static float tptpc(float& state,float inp,float cutoff) { - double v = (inp - state) * cutoff / (1 + cutoff); - double res = v + state; - state = res + v; - return res; +inline static float tptpc(float& state, float inp, float cutoff) { + float v = (inp - state) * cutoff / (1 + cutoff); + float res = v + state; + state = res + v; + return res; } inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) { - cutoff = (cutoff * srInv)*M_PI; - double v = (inp - state) * cutoff / (1 + cutoff); - double res = v + state; - state = res + v; - return res; + cutoff = (cutoff * srInv) * M_PI; + float v = (inp - state) * cutoff / (1 + cutoff); + float res = v + state; + state = res + v; + return res; } //static float linsc(float param,const float min,const float max) { // return (param) * (max - min) + min; //} -static float logsc(float param, const float min,const float max,const float rolloff = 19.0f) { - return ((expf(param * logf(rolloff+1)) - 1.0f) / (rolloff)) * (max-min) + min; +static float logsc(float param, const float min, const float max, const float rolloff = 19.0f) { + return ((expf(param * logf(rolloff + 1)) - 1.0f) / (rolloff)) * (max - min) + min; } PluginFx::PluginFx() { - uiCutoff = 1; - uiReso = 0; - uiGain = 1; + Cutoff = 1; + Reso = 0; + Gain = 1; } void PluginFx::init(int sr) { - mm=0; - s1=s2=s3=s4=c=d=0; - R24=0; - - mmch = (int)(mm * 3); - mmt = mm*3-mmch; - - sampleRate = sr; - sampleRateInv = 1/sampleRate; - float rcrate =sqrt((44000/sampleRate)); - rcor24 = (970.0 / 44000)*rcrate; - rcor24Inv = 1 / rcor24; - - bright = tan((sampleRate*0.5f-10) * M_PI * sampleRateInv); - - R = 1; - rcor = (480.0 / 44000)*rcrate; - rcorInv = 1 / rcor; - bandPassSw = false; - - pCutoff = -1; - pReso = -1; - - dc_r = 1.0-(126.0/sr); - dc_id = 0; - dc_od = 0; + mm = 0; + s1 = s2 = s3 = s4 = c = d = 0; + R24 = 0; + + mmch = (int)(mm * 3); + mmt = mm * 3 - mmch; + + sampleRate = sr; + sampleRateInv = 1 / sampleRate; + float rcrate = sqrt((44000 / sampleRate)); + rcor24 = (970.0 / 44000) * rcrate; + rcor24Inv = 1 / rcor24; + + bright = tanf((sampleRate * 0.5f - 10) * M_PI * sampleRateInv); + + R = 1; + rcor = (480.0 / 44000) * rcrate; + rcorInv = 1 / rcor; + bandPassSw = false; + + pCutoff = -1; + pReso = -1; + + dc_r = 1.0 - (126.0 / sr); + dc_id = 0; + dc_od = 0; } -inline float PluginFx::NR24(float sample,float g,float lpc) { - float ml = 1 / (1+g); - float S = (lpc*(lpc*(lpc*s1 + s2) + s3) +s4)*ml; - float G = lpc*lpc*lpc*lpc; - float y = (sample - R24 * S) / (1 + R24*G); - return y + 1e-8; +inline float PluginFx::NR24(float sample, float g, float lpc) { + float ml = 1 / (1 + g); + float S = (lpc * (lpc * (lpc * s1 + s2) + s3) + s4) * ml; + float G = lpc * lpc * lpc * lpc; + float y = (sample - R24 * S) / (1 + R24 * G); + return y + 1e-8; }; inline float PluginFx::NR(float sample, float g) { - float y = ((sample- R * s1*2 - g*s1 - s2)/(1+ g*(2*R + g))) + dc; - return y; + float y = ((sample - R * s1 * 2 - g * s1 - s2) / (1 + g * (2 * R + g))) + dc; + return y; } void PluginFx::process(float *work, int sampleSize) { - // very basic DC filter - float t_fd = work[0]; - work[0] = work[0] - dc_id + dc_r * dc_od; + // very basic DC filter + float t_fd = work[0]; + work[0] = work[0] - dc_id + dc_r * dc_od; + dc_id = t_fd; + for (int i = 1; i < sampleSize; i++) { + t_fd = work[i]; + work[i] = work[i] - dc_id + dc_r * work[i - 1]; dc_id = t_fd; - for (int i=1; i ENC_FILTER_FRQ_STEPS) enc[i].write(ENC_FILTER_FRQ_STEPS); @@ -314,9 +314,10 @@ void handle_ui(void) Serial.print(F("Setting filter frequency to: ")); Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC); #endif +*/ break; case UI_MAIN_FILTER_RES: - if (enc[i].read() <= 0) +/* if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_RES_STEPS) enc[i].write(ENC_FILTER_RES_STEPS); @@ -328,9 +329,10 @@ void handle_ui(void) Serial.print(F("Setting filter resonance to: ")); Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2); #endif +*/ break; case UI_MAIN_FILTER_OCT: - if (enc[i].read() <= 0) +/* if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_OCT_STEPS) enc[i].write(ENC_FILTER_OCT_STEPS); @@ -340,6 +342,7 @@ void handle_ui(void) Serial.print(F("Setting filter octave control to: ")); Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2); #endif +*/ break; } ui_show_effects_filter(); diff --git a/UI.h b/UI.h index 3d5dd35..47fcc9e 100644 --- a/UI.h +++ b/UI.h @@ -54,7 +54,6 @@ extern uint8_t effect_delay_time; extern uint8_t effect_delay_feedback; extern uint8_t effect_delay_volume; extern bool effect_delay_sync; -extern AudioFilterStateVariable filter1; extern AudioEffectDelay delay1; extern AudioMixer4 mixer1; extern AudioMixer4 mixer2; From b7240fec2ebc1a723c72596cb292c8b664de60b2 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Fri, 26 Apr 2019 12:57:13 +0200 Subject: [PATCH 11/13] Small fixes. --- UI.cpp | 61 +++++++++++++++++++++++++++++-------------------------- dexed.cpp | 4 ++-- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/UI.cpp b/UI.cpp index a1bfd2d..b5a10d0 100644 --- a/UI.cpp +++ b/UI.cpp @@ -292,57 +292,60 @@ void handle_ui(void) switch (ui_main_state) { case UI_MAIN_FILTER_FRQ: -/* if (enc[i].read() <= 0) + if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_FRQ_STEPS) enc[i].write(ENC_FILTER_FRQ_STEPS); effect_filter_frq = enc[i].read(); - if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) - { + /* + if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) + { // turn "off" filter mixer1.gain(0, 0.0); // filtered signal off mixer1.gain(3, 1.0); // original signal on - } - else - { + } + else + { // turn "on" filter mixer1.gain(0, 1.0); // filtered signal on mixer1.gain(3, 0.0); // original signal off - } - filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); -#ifdef DEBUG - Serial.print(F("Setting filter frequency to: ")); - Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC); -#endif -*/ + } + filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); + #ifdef DEBUG + Serial.print(F("Setting filter frequency to: ")); + Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC); + #endif + */ break; case UI_MAIN_FILTER_RES: -/* if (enc[i].read() <= 0) + if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_RES_STEPS) enc[i].write(ENC_FILTER_RES_STEPS); effect_filter_resonance = enc[i].read(); - //filter1.resonance(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)); - filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); - -#ifdef DEBUG - Serial.print(F("Setting filter resonance to: ")); - Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2); -#endif -*/ + /* + //filter1.resonance(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)); + filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); + + #ifdef DEBUG + Serial.print(F("Setting filter resonance to: ")); + Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2); + #endif + */ break; case UI_MAIN_FILTER_OCT: -/* if (enc[i].read() <= 0) + if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_OCT_STEPS) enc[i].write(ENC_FILTER_OCT_STEPS); effect_filter_octave = enc[i].read(); - filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); -#ifdef DEBUG - Serial.print(F("Setting filter octave control to: ")); - Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2); -#endif -*/ + /* + filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); + #ifdef DEBUG + Serial.print(F("Setting filter octave control to: ")); + Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2); + #endif + */ break; } ui_show_effects_filter(); diff --git a/dexed.cpp b/dexed.cpp index 7634fce..16a830d 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -152,7 +152,7 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) int32_t clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; #endif - float f = static_cast(clip_val >> REDUCE_LOUDNESS) / 0x8000; + float f = static_cast(clip_val >> REDUCE_LOUDNESS) / 0x7fff; if (f > 1.0) { f = 1.0; @@ -173,7 +173,7 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) fx.process(sumbuf, n_samples); for (i = 0; i < n_samples; ++i) - buffer[i] = static_cast(sumbuf[i] * 0x8000); + buffer[i] = static_cast(sumbuf[i] * 0x7fff); } void Dexed::keydown(uint8_t pitch, uint8_t velo) { From cd53e9ee1cc82300a801f5282d9e4cca150219a9 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Fri, 26 Apr 2019 13:28:14 +0200 Subject: [PATCH 12/13] Fix... forgot to add a connection for queue1(). --- MicroDexed.ino | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 6ebf1cd..71717ca 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -55,35 +55,36 @@ AudioEffectDelay delay1; AudioMixer4 mixer1; AudioMixer4 mixer2; AudioConnection patchCord0(queue1, peak1); -AudioConnection patchCord9(queue1, 0, mixer1, 0); -AudioConnection patchCord6(delay1, 0, mixer1, 1); -AudioConnection patchCord7(delay1, 0, mixer2, 2); -AudioConnection patchCord8(mixer1, delay1); -AudioConnection patchCord10(mixer1, 0, mixer2, 1); +AudioConnection patchCord1(queue1, 0, mixer1, 0); +AudioConnection patchCord2(queue1, 0, mixer2, 0); +AudioConnection patchCord3(delay1, 0, mixer1, 1); +AudioConnection patchCord4(delay1, 0, mixer2, 2); +AudioConnection patchCord5(mixer1, delay1); +AudioConnection patchCord6(mixer1, 0, mixer2, 1); #if defined(TEENSY_AUDIO_BOARD) AudioOutputI2S i2s1; -AudioConnection patchCord111(mixer2, 0, i2s1, 0); -AudioConnection patchCord112(mixer2, 0, i2s1, 1); +AudioConnection patchCord7(mixer2, 0, i2s1, 0); +AudioConnection patchCord8(mixer2, 0, i2s1, 1); AudioControlSGTL5000 sgtl5000_1; #elif defined(TGA_AUDIO_BOARD) AudioOutputI2S i2s1; AudioAmplifier volume_r; AudioAmplifier volume_l; -AudioConnection patchCord11(mixer2, volume_r); -AudioConnection patchCord12(mixer2, volume_l); -AudioConnection patchCord13(volume_r, 0, i2s1, 1); -AudioConnection patchCord14(volume_l, 0, i2s1, 0); +AudioConnection patchCord7(mixer2, volume_r); +AudioConnection patchCord8(mixer2, volume_l); +AudioConnection patchCord9(volume_r, 0, i2s1, 1); +AudioConnection patchCord10(volume_l, 0, i2s1, 0); AudioControlWM8731master wm8731_1; #else AudioOutputPT8211 pt8211_1; AudioAmplifier volume_master; AudioAmplifier volume_r; AudioAmplifier volume_l; -AudioConnection patchCord11(mixer2, 0, volume_master, 0); -AudioConnection patchCord12(volume_master, volume_r); -AudioConnection patchCord13(volume_master, volume_l); -AudioConnection patchCord14(volume_r, 0, pt8211_1, 0); -AudioConnection patchCord15(volume_l, 0, pt8211_1, 1); +AudioConnection patchCord7(mixer2, 0, volume_master, 0); +AudioConnection patchCord8(volume_master, volume_r); +AudioConnection patchCord9(volume_master, volume_l); +AudioConnection patchCord10(volume_r, 0, pt8211_1, 0); +AudioConnection patchCord11(volume_l, 0, pt8211_1, 1); #endif Dexed* dexed = new Dexed(SAMPLE_RATE); From afd318b96b4136b4b07554c7fd8298b84bb8e176 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Sat, 27 Apr 2019 11:40:13 +0200 Subject: [PATCH 13/13] Added UI handling for 4pole resonant filter. --- MicroDexed.ino | 42 +++++--------------- UI.cpp | 106 +++++++++++-------------------------------------- UI.h | 5 +-- config.h | 5 +-- 4 files changed, 39 insertions(+), 119 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 71717ca..64d633c 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -103,9 +103,8 @@ uint8_t midi_timing_counter = 0; // 24 per qarter elapsedMillis midi_timing_timestep; uint16_t midi_timing_quarter = 0; elapsedMillis long_button_pressed; -uint8_t effect_filter_frq = ENC_FILTER_FRQ_STEPS; +uint8_t effect_filter_cutoff = 0; uint8_t effect_filter_resonance = 0; -uint8_t effect_filter_octave = (1.0 * ENC_FILTER_RES_STEPS / 8.0) + 0.5; uint8_t effect_delay_time = 0; uint8_t effect_delay_feedback = 0; uint8_t effect_delay_volume = 0; @@ -226,11 +225,9 @@ void setup() mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback) mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) - - // just for testing: - dexed->fx.Reso = 0.5; - dexed->fx.Gain = 0.5; - dexed->fx.Cutoff = 0.5; + dexed->fx.Gain = 1.0; + dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS; + dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS; // load default SYSEX data load_sysex(configuration.bank, configuration.voice); @@ -419,32 +416,15 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) } } break; - case 102: // CC 102: filter frequency -/* effect_filter_frq = map(inValue, 0, 127, 0, ENC_FILTER_FRQ_STEPS); - if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) - { - // turn "off" filter - mixer1.gain(0, 0.0); // filtered signal off - mixer1.gain(3, 1.0); // original signal on - } - else - { - // turn "on" filter - mixer1.gain(0, 1.0); // filtered signal on - mixer1.gain(3, 0.0); // original signal off - } - filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); - handle_ui(); */ - break; case 103: // CC 103: filter resonance -/* effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS); - filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); - handle_ui(); */ + effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS); + dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS; + handle_ui(); break; - case 104: // CC 104: filter octave -/* effect_filter_octave = map(inValue, 0, 127, 0, ENC_FILTER_OCT_STEPS); - filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); - handle_ui(); */ + case 104: // CC 104: filter cutoff + effect_filter_cutoff = map(inValue, 0, 127, 0, ENC_FILTER_CUT_STEPS); + dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS; + handle_ui(); break; case 105: // CC 105: delay time effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS); diff --git a/UI.cpp b/UI.cpp index b5a10d0..da81939 100644 --- a/UI.cpp +++ b/UI.cpp @@ -84,8 +84,8 @@ void handle_ui(void) switch (ui_state) { case UI_MAIN: - ui_main_state = UI_MAIN_FILTER_FRQ; - enc[i].write(effect_filter_frq); + ui_main_state = UI_MAIN_FILTER_RES; + enc[i].write(effect_filter_resonance); enc_val[i] = enc[i].read(); ui_show_effects_filter(); break; @@ -155,21 +155,15 @@ void handle_ui(void) case UI_EFFECTS_DELAY: switch (ui_main_state) { - case UI_MAIN_FILTER_FRQ: - ui_main_state = UI_MAIN_FILTER_RES; - enc[i].write(effect_filter_resonance); - enc_val[i] = enc[i].read(); - ui_show_effects_filter(); - break; case UI_MAIN_FILTER_RES: - ui_main_state = UI_MAIN_FILTER_OCT; - enc[i].write(effect_filter_octave); + ui_main_state = UI_MAIN_FILTER_CUT; + enc[i].write(effect_filter_cutoff); enc_val[i] = enc[i].read(); ui_show_effects_filter(); break; - case UI_MAIN_FILTER_OCT: - ui_main_state = UI_MAIN_FILTER_FRQ; - enc[i].write(effect_filter_frq); + case UI_MAIN_FILTER_CUT: + ui_main_state = UI_MAIN_FILTER_RES; + enc[i].write(effect_filter_resonance); enc_val[i] = enc[i].read(); ui_show_effects_filter(); break; @@ -291,61 +285,29 @@ void handle_ui(void) case UI_EFFECTS_FILTER: switch (ui_main_state) { - case UI_MAIN_FILTER_FRQ: - if (enc[i].read() <= 0) - enc[i].write(0); - else if (enc[i].read() > ENC_FILTER_FRQ_STEPS) - enc[i].write(ENC_FILTER_FRQ_STEPS); - effect_filter_frq = enc[i].read(); - /* - if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) - { - // turn "off" filter - mixer1.gain(0, 0.0); // filtered signal off - mixer1.gain(3, 1.0); // original signal on - } - else - { - // turn "on" filter - mixer1.gain(0, 1.0); // filtered signal on - mixer1.gain(3, 0.0); // original signal off - } - filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); - #ifdef DEBUG - Serial.print(F("Setting filter frequency to: ")); - Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC); - #endif - */ - break; case UI_MAIN_FILTER_RES: if (enc[i].read() <= 0) enc[i].write(0); else if (enc[i].read() > ENC_FILTER_RES_STEPS) enc[i].write(ENC_FILTER_RES_STEPS); effect_filter_resonance = enc[i].read(); - /* - //filter1.resonance(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)); - filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); - - #ifdef DEBUG - Serial.print(F("Setting filter resonance to: ")); - Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2); - #endif - */ + dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS; +#ifdef DEBUG + Serial.print(F("Setting filter resonance to: ")); + Serial.println(1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS, 5); +#endif break; - case UI_MAIN_FILTER_OCT: + case UI_MAIN_FILTER_CUT: if (enc[i].read() <= 0) enc[i].write(0); - else if (enc[i].read() > ENC_FILTER_OCT_STEPS) - enc[i].write(ENC_FILTER_OCT_STEPS); - effect_filter_octave = enc[i].read(); - /* - filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); - #ifdef DEBUG - Serial.print(F("Setting filter octave control to: ")); - Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2); - #endif - */ + else if (enc[i].read() > ENC_FILTER_CUT_STEPS) + enc[i].write(ENC_FILTER_CUT_STEPS); + effect_filter_cutoff = enc[i].read(); + dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS; +#ifdef DEBUG + Serial.print(F("Setting filter cutoff to: ")); + Serial.println(1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS, 5); +#endif break; } ui_show_effects_filter(); @@ -509,32 +471,12 @@ void ui_show_effects_filter(void) { lcd.clear(); lcd.show(0, 0, LCD_CHARS, "Filter"); - lcd.show(0, 7, 2, "F:"); lcd.show(1, 0, 4, "Res:"); - lcd.show(1, 8, 4, "Oct:"); + lcd.show(1, 8, 4, "Cut:"); } - if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) - { - lcd.show(0, 10, 4, "OFF "); - } - else - { - lcd.show(0, 10, 4, uint16_t(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.5)); - } lcd.show(1, 5, 2, map(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0, 99)); - lcd.show(1, 13, 2, map(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0, 80)); - - if (ui_main_state == UI_MAIN_FILTER_FRQ) - { - lcd.show(0, 9, 1, "["); - lcd.show(0, 14, 1, "]"); - } - else - { - lcd.show(0, 9, 1, " "); - lcd.show(0, 14, 1, " "); - } + lcd.show(1, 13, 2, map(effect_filter_cutoff, 0, ENC_FILTER_CUT_STEPS, 0, 99)); if (ui_main_state == UI_MAIN_FILTER_RES) { @@ -547,7 +489,7 @@ void ui_show_effects_filter(void) lcd.show(1, 7, 1, " "); } - if (ui_main_state == UI_MAIN_FILTER_OCT) + if (ui_main_state == UI_MAIN_FILTER_CUT) { lcd.show(1, 12, 1, "["); lcd.show(1, 15, 1, "]"); diff --git a/UI.h b/UI.h index 47fcc9e..c720677 100644 --- a/UI.h +++ b/UI.h @@ -47,9 +47,8 @@ extern void eeprom_write(void); extern void set_volume(float v, float pan); extern elapsedMillis autostore; extern elapsedMillis long_button_pressed; -extern uint8_t effect_filter_frq; +extern uint8_t effect_filter_cutoff; extern uint8_t effect_filter_resonance; -extern uint8_t effect_filter_octave; extern uint8_t effect_delay_time; extern uint8_t effect_delay_feedback; extern uint8_t effect_delay_volume; @@ -67,7 +66,7 @@ void ui_show_effects_delay(void); float mapfloat(float val, float in_min, float in_max, float out_min, float out_max); enum ui_states {UI_MAIN, UI_VOLUME, UI_MIDICHANNEL, UI_EFFECTS_FILTER, UI_EFFECTS_DELAY}; -enum ui_main_states {UI_MAIN_BANK, UI_MAIN_VOICE, UI_MAIN_BANK_SELECTED, UI_MAIN_VOICE_SELECTED, UI_MAIN_FILTER_FRQ, UI_MAIN_FILTER_RES, UI_MAIN_FILTER_OCT, UI_MAIN_DELAY_TIME, UI_MAIN_DELAY_FEEDBACK, UI_MAIN_DELAY_VOLUME}; +enum ui_main_states {UI_MAIN_BANK, UI_MAIN_VOICE, UI_MAIN_BANK_SELECTED, UI_MAIN_VOICE_SELECTED, UI_MAIN_FILTER_RES, UI_MAIN_FILTER_CUT, UI_MAIN_DELAY_TIME, UI_MAIN_DELAY_FEEDBACK, UI_MAIN_DELAY_VOLUME}; class MyEncoder : public Encoder { diff --git a/config.h b/config.h index a257a5c..0fd77d3 100644 --- a/config.h +++ b/config.h @@ -120,9 +120,8 @@ // Encoder with button #define ENC_VOL_STEPS 43 -#define ENC_FILTER_FRQ_STEPS 50 -#define ENC_FILTER_RES_STEPS 35 -#define ENC_FILTER_OCT_STEPS 27 +#define ENC_FILTER_RES_STEPS 100 +#define ENC_FILTER_CUT_STEPS 100 #define ENC_DELAY_TIME_STEPS 50 #define ENC_DELAY_FB_STEPS 35 #define ENC_DELAY_VOLUME_STEPS 50