diff --git a/MicroDexed.ino b/MicroDexed.ino index dffc6b8..508f403 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -525,7 +525,8 @@ void loop() { for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { - if (midi_decay_timer > 100 && midi_decay[instance_id] > 0) +#ifdef TEENSY4 + if (midi_decay_timer > MIDI_DECAY_TIMER && midi_decay[instance_id] > 0) { midi_decay[instance_id]--; lcd.createChar(6 + instance_id, (uint8_t*)special_chars[15 - (7 - midi_decay[instance_id])]); @@ -538,6 +539,21 @@ void loop() lcd.setCursor(14 + instance_id, 1); lcd.write(20); // blank } +#else + static bool midi_playing[NUM_DEXED]; + if (midi_decay_timer > MIDI_DECAY_TIMER && midi_voices[instance_id] > 0 && midi_playing[instance_id] == false) + { + midi_playing[instance_id] = true; + lcd.setCursor(14 + instance_id,1); + lcd.write(6 + instance_id); + } + else if (midi_decay_timer > MIDI_DECAY_TIMER && midi_voices[instance_id] == 0) + { + midi_playing[instance_id] = false; + lcd.setCursor(14 + instance_id, 1); + lcd.write(20); // blank + } +#endif } if (midi_decay_timer > 250) { @@ -580,7 +596,9 @@ void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) { if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) { - MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); + if (MicroDexed[instance_id]->getMaxNotes() > 0) + MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); + midi_voices[instance_id]++; if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) { @@ -611,7 +629,9 @@ void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity) { if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) { - MicroDexed[instance_id]->keyup(inNumber); + if (MicroDexed[instance_id]->getMaxNotes() > 0) + MicroDexed[instance_id]->keyup(inNumber); + midi_voices[instance_id]--; #ifdef DEBUG char note_name[4]; diff --git a/UI.hpp b/UI.hpp index 9b4de6a..963d945 100644 --- a/UI.hpp +++ b/UI.hpp @@ -157,7 +157,7 @@ const uint8_t meter_bar[5][8] = { }; */ -const uint8_t special_chars[16][8] = { +const uint8_t special_chars[17][8] = { {B11111, B11011, B10011, B11011, B11011, B11011, B11011, B11111}, // [0] 1 small invers {B11111, B11011, B10101, B11101, B11011, B10111, B10001, B11111}, // [1] 2 small invers {B11111, B11011, B10011, B11011, B11011, B11011, B11011, B11111}, // [2] 1 OP invers @@ -174,6 +174,7 @@ const uint8_t special_chars[16][8] = { {B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111}, // [13] Level 6 {B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111}, // [14] Level 7 {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111}, // [15] Level 8 + {B00100, B00110, B00101, B00101, B01101, B11101, B11100, B11000} // [16] Note }; enum { SCROLLBAR, BLOCKBAR, METERBAR }; @@ -1111,6 +1112,7 @@ void UI_func_chorus_waveform(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, fx.chorus_waveform[0]), configuration.fx.chorus_waveform[0]); #if NUM_DEXED > 1 @@ -2073,9 +2075,17 @@ void UI_func_polyphony(uint8_t param) if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up()) || (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort())) { if (LCDML.BT_checkDown()) - configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony + ENCODER[ENC_R].speed(), POLYPHONY_MIN, POLYPHONY_MAX); + { + if (configuration.dexed[0].polyphony + configuration.dexed[1].polyphony + 1 <= POLYPHONY_MAX) + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony + 1, POLYPHONY_MIN, POLYPHONY_MAX); + } else if (LCDML.BT_checkUp()) - configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony - ENCODER[ENC_R].speed(), POLYPHONY_MIN, POLYPHONY_MAX); + { + if (configuration.dexed[selected_instance_id].polyphony - 1 < 0) + configuration.dexed[selected_instance_id].polyphony = 0; + else + configuration.dexed[selected_instance_id].polyphony = constrain(configuration.dexed[selected_instance_id].polyphony - 1, POLYPHONY_MIN, POLYPHONY_MAX); + } #if NUM_DEXED > 1 else if (LCDML.BT_checkEnter()) { @@ -2228,6 +2238,8 @@ void UI_func_mono_poly(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].monopoly), configuration.dexed[0].monopoly); #if NUM_DEXED > 1 @@ -2291,6 +2303,8 @@ void UI_func_note_refresh(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); + encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].note_refresh), configuration.dexed[0].note_refresh); #if NUM_DEXED > 1 @@ -2537,6 +2551,7 @@ void UI_func_mw_assign(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].mw_assign), configuration.dexed[0].mw_assign); #if NUM_DEXED > 1 @@ -2604,6 +2619,7 @@ void UI_func_mw_mode(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].mw_mode), configuration.dexed[0].mw_mode); #if NUM_DEXED > 1 @@ -2741,6 +2757,7 @@ void UI_func_fc_assign(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].fc_assign), configuration.dexed[0].fc_assign); #if NUM_DEXED > 1 @@ -2808,6 +2825,7 @@ void UI_func_fc_mode(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].fc_mode), configuration.dexed[0].fc_mode); #if NUM_DEXED > 1 @@ -2944,6 +2962,7 @@ void UI_func_bc_assign(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].bc_assign), configuration.dexed[0].bc_assign); #if NUM_DEXED > 1 @@ -3011,6 +3030,7 @@ void UI_func_bc_mode(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].bc_mode), configuration.dexed[0].bc_mode); #if NUM_DEXED > 1 @@ -3065,6 +3085,7 @@ void UI_func_at_range(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_range), configuration.dexed[0].at_range); @@ -3147,6 +3168,7 @@ void UI_func_at_assign(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_assign), configuration.dexed[0].at_assign); #if NUM_DEXED > 1 @@ -3214,6 +3236,7 @@ void UI_func_at_mode(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].at_mode), configuration.dexed[0].at_mode); #if NUM_DEXED > 1 @@ -3283,6 +3306,7 @@ void UI_func_portamento_mode(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].portamento_mode), configuration.dexed[0].portamento_mode); #if NUM_DEXED > 1 @@ -3346,6 +3370,7 @@ void UI_func_portamento_glissando(uint8_t param) if (LCDML.FUNC_close()) // ****** STABLE END ********* { + lcd_special_chars(SCROLLBAR); encoderDir[ENC_R].reset(); EEPROM.update(EEPROM_START_ADDRESS + offsetof(configuration_s, dexed[0].portamento_glissando), configuration.dexed[0].portamento_glissando); #if NUM_DEXED > 1 @@ -3675,12 +3700,7 @@ void UI_func_voice_select(uint8_t param) strncpy(bank_name, "*ERROR*", sizeof(bank_name)); if (!get_voice_by_bank_name(configuration.performance.bank[selected_instance_id], bank_name, configuration.performance.voice[selected_instance_id], voice_name, sizeof(voice_name))) strncpy(voice_name, "*ERROR*", sizeof(voice_name)); - /* - lcd.show(0, 0, 2, configuration.performance.bank[selected_instance_id]); - lcd.show(1, 0, 2, configuration.performance.voice[selected_instance_id] + 1); - lcd.show(0, 2, 10, bank_name); - lcd.show(1, 2, 10, voice_name); - */ + #if NUM_DEXED > 1 lcd.setCursor(14, 0); lcd.write(0); @@ -3688,23 +3708,9 @@ void UI_func_voice_select(uint8_t param) lcd.write(1); #endif - /* - switch (menu_voice_select) - { - case MENU_VOICE_BANK: - lcd.show(0, 2, 1, "["); - lcd.show(0, 13, 1, "]"); - lcd.show(1, 2, 1, " "); - lcd.show(1, 13, 1, " "); - break; - case MENU_VOICE_SOUND: - lcd.show(0, 2, 2, " "); - lcd.show(0, 13, 1, " "); - lcd.show(1, 2, 2, " ["); - lcd.show(1, 13, 1, "]"); - break; - } - */ +#ifdef TEENSY3 + lcd.createChar(6, (uint8_t*)special_chars[16]); // MIDI activity note symbol +#endif } diff --git a/config.h b/config.h index a2e148a..bd01a91 100644 --- a/config.h +++ b/config.h @@ -181,6 +181,7 @@ #define VOICE_SELECTION_MS 60000 #define BACK_FROM_VOLUME_MS 2000 #define MESSAGE_WAIT_TIME 1000 +#define MIDI_DECAY_TIMER 50 //************************************************************************************************* //* HARDWARE SETTINGS @@ -244,7 +245,7 @@ //************************************************************************************************* //* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!! //************************************************************************************************* -#define NUM_DEXED 2 // 1 or 2 - nothing else! +#define NUM_DEXED 1 // 1 or 2 - nothing else! #define MAX_DEXED 2 // No! - even don't think about increasing this number! IT WILL PRODUCE MASSIVE PROBLEMS! //#define CPU_OVERLOAD_THROTTLE 95.0 // Level (in percent) when throttling should start #define CPU_OVERLOAD_THROTTLE_TIMER 100 // timer (in ms) when next throttling is possible @@ -267,9 +268,17 @@ // Teensy-3.6 settings #define MIDI_DEVICE_USB_HOST 1 #if defined(USE_FX) +#if NUM_DEXED == 1 #define MAX_NOTES 12 #else +#define MAX_NOTES 9 +#endif +#else +#if NUM_DEXED == 1 #define MAX_NOTES 16 +#else +#define MAX_NOTES 13 +#endif #endif #define TEENSY3_6 #endif diff --git a/dexed.cpp b/dexed.cpp index b1725f2..0f26dfe 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -116,6 +116,12 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) uint8_t note; float sumbuf[n_samples]; + if (max_notes == 0) + { + memset(buffer, 0, sizeof(buffer)*AUDIO_BLOCK_SAMPLES); + return; + } + if (refreshVoice) { for (i = 0; i < max_notes; i++) diff --git a/source_microdexed.h b/source_microdexed.h index 2cb23dd..132e449 100644 --- a/source_microdexed.h +++ b/source_microdexed.h @@ -9,26 +9,32 @@ class AudioSourceMicroDexed : public AudioStream, public Dexed { const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES); uint32_t xrun = 0; uint16_t render_time_max = 0; - AudioSourceMicroDexed(int sample_rate) : AudioStream(0, NULL), Dexed(sample_rate) { }; - void update(void) { - if (max_notes == 0) - return; + AudioSourceMicroDexed(int sample_rate) : AudioStream(0, NULL), Dexed(sample_rate) { }; - if (in_update) { + void update(void) + { + if (in_update) + { xrun++; return; } - else in_update = true; + else + in_update = true; elapsedMicros render_time; audio_block_t *lblock; + lblock = allocate(); - if (!lblock) { + + if (!lblock) + { in_update = false; return; } + getSamples(AUDIO_BLOCK_SAMPLES, lblock->data); + if (render_time > audio_block_time_us) // everything greater 2.9ms is a buffer underrun! xrun++; /* if (render_time > audio_block_time_us - (audio_block_time_us / 10)) { @@ -45,8 +51,10 @@ class AudioSourceMicroDexed : public AudioStream, public Dexed { transmit(lblock, 0); release(lblock); + in_update = false; }; + private: volatile bool in_update = false; };