diff --git a/MicroDexed.ino b/MicroDexed.ino index f7be7a4..8053f5a 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -776,104 +776,126 @@ void loop() ******************************************************************************/ void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) { - //Ignore the note when playing & recording the same note into the sequencer - if (seq_recording == false || (seq_recording && inNumber != seq_note_in )) +#if NUM_DRUMS > 0 + if (activesample < 6 && seq_running == false && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_seq_pattern_editor) ) // live play pitched sample { - // Check for MicroDexed - for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) + if (drum_counter >= NUM_DRUMS) + drum_counter = 0; + uint8_t slot = drum_get_slot(drum_config[activesample].drum_class); + float pan = mapfloat(drum_config[activesample].pan, -1.0, 1.0, 0.0, 1.0); + drum_mixer_r.gain(slot, (1.0 - pan) * drum_config[activesample].vol_max); + drum_mixer_l.gain(slot, pan * drum_config[activesample].vol_max); +#ifdef USE_FX + drum_reverb_send_mixer_r.gain(slot, (1.0 - pan) * volume_transform(drum_config[activesample].reverb_send)); + drum_reverb_send_mixer_l.gain(slot, pan * volume_transform(drum_config[activesample].reverb_send)); +#endif + if (drum_config[activesample].drum_data != NULL && drum_config[activesample].len > 0) { - if (checkMidiChannel(inChannel, instance_id)) + Drum[slot]->enableInterpolation(true); + Drum[slot]->setPlaybackRate( (float)pow (2, (inNumber - 72) / 12.00) * drum_config[activesample].p_offset ); + Drum[slot]->playRaw((int16_t*)drum_config[activesample].drum_data, drum_config[activesample].len, 1); + } + } + else +#endif + //Ignore the note when playing & recording the same note into the sequencer + if (seq_recording == false || (seq_recording && inNumber != seq_note_in )) + { + // Check for MicroDexed + for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { - if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) + if (checkMidiChannel(inChannel, instance_id)) { - if (configuration.dexed[instance_id].polyphony > 0) - MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); + if (inNumber >= configuration.dexed[instance_id].lowest_note && inNumber <= configuration.dexed[instance_id].highest_note) + { + if (configuration.dexed[instance_id].polyphony > 0) + MicroDexed[instance_id]->keydown(inNumber, uint8_t(float(configuration.dexed[instance_id].velocity_level / 127.0)*inVelocity + 0.5)); - midi_voices[instance_id]++; + midi_voices[instance_id]++; #ifdef TEENSY4 - if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) - { - midi_decay_timer = 0; - midi_decay[instance_id] = min(inVelocity / 5, 7); - } + if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + { + midi_decay_timer = 0; + midi_decay[instance_id] = min(inVelocity / 5, 7); + } #endif #ifdef DEBUG - char note_name[4]; - getNoteName(note_name, inNumber); - Serial.print(F("Keydown ")); - Serial.print(note_name); - Serial.print(F(" instance ")); - Serial.print(instance_id, DEC); - Serial.print(F(" MIDI-channel ")); - Serial.print(inChannel, DEC); - Serial.println(); + char note_name[4]; + getNoteName(note_name, inNumber); + Serial.print(F("Keydown ")); + Serial.print(note_name); + Serial.print(F(" instance ")); + Serial.print(instance_id, DEC); + Serial.print(F(" MIDI-channel ")); + Serial.print(inChannel, DEC); + Serial.println(); #endif - return; + return; + } } } - } #if NUM_DRUMS > 0 - // Check for Drum - if (inChannel == drum_midi_channel) - { - if (drum_counter >= NUM_DRUMS) - drum_counter = 0; + // Check for Drum + if (inChannel == drum_midi_channel) + { + if (drum_counter >= NUM_DRUMS) + drum_counter = 0; #ifdef DEBUG - char note_name[4]; - getNoteName(note_name, inNumber); - Serial.print(F("=> Drum[")); - Serial.print(drum_counter, DEC); - Serial.print(F("]: ")); - Serial.println(note_name); + char note_name[4]; + getNoteName(note_name, inNumber); + Serial.print(F("=> Drum[")); + Serial.print(drum_counter, DEC); + Serial.print(F("]: ")); + Serial.println(note_name); #endif - for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG; d++) - { - if (inNumber == drum_config[d].midinote) + for (uint8_t d = 0; d < NUM_DRUMSET_CONFIG; d++) { - uint8_t slot = drum_get_slot(drum_config[d].drum_class); - float pan = mapfloat(drum_config[d].pan, -1.0, 1.0, 0.0, 1.0); + if (inNumber == drum_config[d].midinote) + { + uint8_t slot = drum_get_slot(drum_config[d].drum_class); + float pan = mapfloat(drum_config[d].pan, -1.0, 1.0, 0.0, 1.0); - drum_mixer_r.gain(slot, (1.0 - pan) * volume_transform(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); - drum_mixer_l.gain(slot, pan * volume_transform(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); + drum_mixer_r.gain(slot, (1.0 - pan) * volume_transform(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); + drum_mixer_l.gain(slot, pan * volume_transform(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max))); #ifdef USE_FX - drum_reverb_send_mixer_r.gain(slot, (1.0 - pan) * volume_transform(drum_config[d].reverb_send)); - drum_reverb_send_mixer_l.gain(slot, pan * volume_transform(drum_config[d].reverb_send)); + drum_reverb_send_mixer_r.gain(slot, (1.0 - pan) * volume_transform(drum_config[d].reverb_send)); + drum_reverb_send_mixer_l.gain(slot, pan * volume_transform(drum_config[d].reverb_send)); #endif - if (drum_config[d].drum_data != NULL && drum_config[d].len > 0) - { - //Drum[slot]->play(drum_config[d].drum_data); - if (drum_config[d].pitch != 0.0) + if (drum_config[d].drum_data != NULL && drum_config[d].len > 0) { - Drum[slot]->enableInterpolation(true); - Drum[slot]->setPlaybackRate(drum_config[d].pitch); + //Drum[slot]->play(drum_config[d].drum_data); + if (drum_config[d].pitch != 0.0) + { + Drum[slot]->enableInterpolation(true); + Drum[slot]->setPlaybackRate(drum_config[d].pitch); + } + Drum[slot]->playRaw((int16_t*)drum_config[d].drum_data, drum_config[d].len, 1); } - Drum[slot]->playRaw((int16_t*)drum_config[d].drum_data, drum_config[d].len, 1); - } #ifdef DEBUG - Serial.print(F("Drum ")); - Serial.print(drum_config[d].shortname); - Serial.print(F(" [")); - Serial.print(drum_config[d].name); - Serial.print(F("], Slot ")); - Serial.print(slot); - Serial.print(F(": V")); - Serial.print(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max), 2); - Serial.print(F(" P")); - Serial.print(drum_config[d].pan, 2); - Serial.print(F(" PAN")); - Serial.print(pan, 2); - Serial.print(F(" RS")); - Serial.println(drum_config[d].reverb_send, 2); + Serial.print(F("Drum ")); + Serial.print(drum_config[d].shortname); + Serial.print(F(" [")); + Serial.print(drum_config[d].name); + Serial.print(F("], Slot ")); + Serial.print(slot); + Serial.print(F(": V")); + Serial.print(mapfloat(inVelocity, 0, 127, drum_config[d].vol_min, drum_config[d].vol_max), 2); + Serial.print(F(" P")); + Serial.print(drum_config[d].pan, 2); + Serial.print(F(" PAN")); + Serial.print(pan, 2); + Serial.print(F(" RS")); + Serial.println(drum_config[d].reverb_send, 2); #endif - break; + break; + } } } - } #endif - } + } } #if NUM_DRUMS > 0 @@ -887,29 +909,29 @@ uint8_t drum_get_slot(uint8_t dt) Drum[i]->enableInterpolation(false); Drum[i]->setPlaybackRate(1.0); } - else - { - if (drum_type[i] == dt) - { -#ifdef DEBUG - Serial.print(F("Stopping Drum ")); - Serial.print(i); - Serial.print(F(" type ")); - Serial.println(dt); -#endif - Drum[i]->stop(); - - return (i); - } - } + // else + // { + // if (drum_type[i] == dt) + // { + //#ifdef DEBUG + // Serial.print(F("Stopping Drum ")); + // Serial.print(i); + // Serial.print(F(" type ")); + // Serial.println(dt); + //#endif + // Drum[i]->stop(); + // + // return (i); + // } + // } } #ifdef DEBUG Serial.print(F("Using next free Drum slot ")); - Serial.println(drum_counter % 4); + Serial.println(drum_counter % NUM_DRUMS); #endif - drum_type[drum_counter % 4] = dt; + drum_type[drum_counter % NUM_DRUMS] = dt; drum_counter++; - return (drum_counter - 1 % 4); + return (drum_counter - 1 % NUM_DRUMS); } #endif diff --git a/UI.hpp b/UI.hpp index 572d048..28a34c9 100644 --- a/UI.hpp +++ b/UI.hpp @@ -110,10 +110,11 @@ extern int seq_oct_shift; extern char arp_style_names[4][3]; extern char seq_chord_names[7][4]; extern uint8_t seq_data_buffer[16]; +extern uint8_t seq_data[NUM_SEQ_PATTERN][16]; extern float drums_volume; extern uint8_t drum_midi_channel; uint8_t seq_active_function = 99; -uint8_t activesample; extern uint8_t seq_data[10][16]; +uint8_t activesample; #endif #ifdef DISPLAY_LCD_SPI @@ -646,6 +647,18 @@ void setup_debug_message(void) } #endif +void toggle_sequencer_play_status() +{ + if (seq_running == false && seq_recording == false) + { + handleStart(); + } + else if (seq_running == true && seq_recording == false) + { + handleStop(); + } +} + /*********************************************************************** MENU CONTROL ***********************************************************************/ @@ -923,8 +936,12 @@ void lcdml_menu_control(void) Serial.println(F("ENC-L long recognized")); #endif + // when in Voice select Menu, long left-press sets/unsets favorite if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) save_favorite(configuration.performance.bank[selected_instance_id], configuration.performance.voice[selected_instance_id], selected_instance_id); + // when not in Voice select Menu, long left-press starts/stops sequencer + else if (LCDML.FUNC_getID() != LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) + toggle_sequencer_play_status(); //for (uint8_t i = 0; i < NUM_DEXED; i++) // MicroDexed[i]->panic(); @@ -4837,7 +4854,7 @@ void seq_clear_active_pattern() } void seq_clear_all_patterns() { - for (uint8_t i = 0; i < 10; i++) + for (uint8_t i = 0; i < NUM_SEQ_PATTERN - 1; i++) { memset(seq_data[i], 0, sizeof(seq_data[i])); memset(seq_vel[i], 0, sizeof(seq_vel[i])); @@ -4903,10 +4920,19 @@ void seq_print_current_note() lcd.print( (seq_data[seq_active_track][seq_menu - 3] / 12) - 1); lcd.print(" "); } +void check_variable_samples_basespeed() +{ + for (uint8_t i = 0; i < 6; i++) + { + if (drum_config[i].p_offset == 0) + drum_config[i].p_offset=1; + } +} void UI_func_seq_pattern_editor(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { + check_variable_samples_basespeed(); lcd.createChar(0, (uint8_t*)special_chars[19]); //play symbol + record symbol switching #ifdef TESTDISPLAY20x4 lcd.createChar(1, (uint8_t*)special_chars[9]); //bar graph diff --git a/drums.h b/drums.h index baeb98a..d1793b4 100644 --- a/drums.h +++ b/drums.h @@ -44,6 +44,6 @@ typedef struct drum_config_s { float32_t reverb_send; // how much signal to send to the reverb (0.0 - 1.0) } drum_config_t; -enum {DRUM_NONE, DRUM_BASS, DRUM_SNARE, DRUM_HIHAT, DRUM_HANDCLAP, DRUM_RIDE, DRUM_CRASH, DRUM_LOWTOM, DRUM_MIDTOM, DRUM_HIGHTOM, DRUM_PERCUSSION}; +enum {DRUM_NONE, DRUM_BASS, DRUM_SNARE, DRUM_HIHAT, DRUM_HANDCLAP, DRUM_RIDE, DRUM_CRASH, DRUM_LOWTOM, DRUM_MIDTOM, DRUM_HIGHTOM, DRUM_PERCUSSION,DRUM_POLY}; #endif diff --git a/drumset.h b/drumset.h index 8c86456..95ef25c 100644 --- a/drumset.h +++ b/drumset.h @@ -276210,7 +276210,7 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = { #ifdef TEENSY4 { - DRUM_HIHAT, + DRUM_POLY, 210, "SQBass", DRUM_SQBass, @@ -276224,7 +276224,7 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = 0.0 }, { - DRUM_MIDTOM, + DRUM_POLY, 211, "CALLIOP", DRUM_CALLIOP, @@ -276238,7 +276238,7 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = 0.0 }, { - DRUM_CRASH, + DRUM_POLY, 212, "ssaw", DRUM_ssaw, @@ -276247,12 +276247,12 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = 0.0, 0.0, 0.0, - 0.8, + 0.7, 0.0, 0.0 }, { - DRUM_RIDE, + DRUM_POLY, 213, "ARR1", DRUM_ARR1, @@ -276261,12 +276261,12 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = 0.0, 0.0, 0.0, - 0.8, + 0.7, 0.0, 0.0 }, { - DRUM_BASS, + DRUM_POLY, 214, "FVoice", DRUM_FVoice, @@ -276275,12 +276275,12 @@ drum_config_t drum_config[NUM_DRUMSET_CONFIG] = 0.0, 0.0, 0.0, - 0.8, + 0.7, 0.0, 0.0 }, { - DRUM_BASS, + DRUM_POLY, 215, "SlapB-M1", DRUM_SlapB_M1, diff --git a/sequencer.cpp b/sequencer.cpp index 4b5f01f..5952da7 100644 --- a/sequencer.cpp +++ b/sequencer.cpp @@ -8,6 +8,8 @@ extern LCDMenuLib2 LCDML; extern LiquidCrystal_I2C lcd; extern config_t configuration; extern uint8_t drum_midi_channel; +extern uint8_t activesample; +extern uint8_t get_sample_note(uint8_t sample); extern void handleNoteOn(byte , byte , byte ); extern void handleNoteOff(byte , byte , byte ); extern void UI_func_seq_pattern_editor(uint8_t); @@ -18,6 +20,24 @@ extern float get_sample_vol_max(uint8_t); extern float get_sample_p_offset(uint8_t); boolean interrupt_swapper = false; + +void seq_live_recording(void) +{ + //record to sequencer if sequencer menu is active and recording is active + if (seq_note_in > 0 && seq_recording == true && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_seq_pattern_editor)) + { + seq_data[seq_active_track][seq_step] = seq_note_in; + if ( get_sample_note(activesample) > 209 ) // pitched sample + { + seq_vel[seq_active_track][seq_step] = get_sample_note(activesample); + } + else + seq_vel[seq_active_track][seq_step] = seq_note_in_velocity; + + seq_note_in = 0; + seq_note_in_velocity = 0; + } +} void sequencer_part1(void) { //if (seq_note_in > 0 && seq_note_in < 62 && seq_recording == false ) { @@ -29,14 +49,7 @@ void sequencer_part1(void) //seq_note_in = 0; //} - //record to sequencer if sequencer menu is active and recording is active - if (seq_note_in > 0 && seq_recording == true && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_seq_pattern_editor)) { - seq_data[seq_active_track][seq_step] = seq_note_in; - seq_vel[seq_active_track][seq_step] = seq_note_in_velocity; - seq_note_in = 0; - seq_note_in_velocity = 0; - } - + seq_live_recording(); for (uint8_t d = 0; d < NUM_SEQ_TRACKS; d++) { if (seq_patternchain[seq_chain_active_step][d] < NUM_SEQ_PATTERN ) // sequence not empty or muted @@ -175,6 +188,7 @@ void sequencer_part1(void) void sequencer_part2(void) { + seq_live_recording(); for (uint8_t d = 0; d < NUM_SEQ_TRACKS; d++) { if (seq_noteoffsent[d] == false) {