Merge pull request 'Added custom/user MIDI Note & CC Mappings with MIDI learn' (#112) from positionhigh/MicroDexed:dev into dev

Reviewed-on: https://codeberg.org/dcoredump/MicroDexed/pulls/112
dev
Holger Wirtz 3 years ago
commit a2c442b12b
  1. 726
      MicroDexed.ino
  2. 229
      UI.hpp
  3. 2
      config.h
  4. 149
      dexed_sd.cpp
  5. 12
      drums.h
  6. 1
      sequencer.h

@ -416,6 +416,7 @@ uint8_t drum_counter;
uint8_t drum_type[NUM_DRUMS];
extern void sequencer(void);
uint8_t drum_midi_channel = DRUM_MIDI_CHANNEL;
custom_midi_map_t custom_midi_map[NUM_CUSTOM_MIDI_MAPPINGS];
#endif
#ifdef ENABLE_LCD_UI
@ -933,158 +934,267 @@ void loop()
#endif
}
void learn_key(byte inChannel, byte inNumber)
{
uint8_t found = 199;
if (inChannel == DRUM_MIDI_CHANNEL)
{
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (inNumber == custom_midi_map[c].in && custom_midi_map[c].type == 1)
{
found = c;
break;
}
}
if (found != 199) //remap to new destination if it was already mapped before
{
custom_midi_map[found].in = inNumber;
custom_midi_map[found].out = drum_config[activesample].midinote;
custom_midi_map[found].type = 1;
custom_midi_map[found].channel = DRUM_MIDI_CHANNEL;
}
else
{
found = 199;
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (custom_midi_map[c].in == 0)
{
found = c;
break;
}
}
if (found != 199) // else map to next empty slot if it was not mapped before
{
custom_midi_map[found].in = inNumber;
custom_midi_map[found].out = drum_config[activesample].midinote;
custom_midi_map[found].type = 1;
custom_midi_map[found].channel = DRUM_MIDI_CHANNEL;
}
else
; // can not be mapped, no empty slot left
}
}
seq.midi_learn_active = false;
//update_midi_learn_button();
print_custom_mappings();
}
void learn_cc(byte inChannel, byte inNumber)
{
uint8_t found = 199;
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (inNumber == custom_midi_map[c].in && custom_midi_map[c].type == 2)
{
found = c;
break;
}
}
if (found != 199) //remap to new destination if it was already mapped before
{
custom_midi_map[found].in = inNumber;
custom_midi_map[found].out = cc_dest_values[seq.temp_select_menu];
custom_midi_map[found].type = 2;
custom_midi_map[found].channel = configuration.dexed[selected_instance_id].midi_channel;
}
else
{
found = 199;
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (custom_midi_map[c].in == 0)
{
found = c;
break;
}
}
if (found != 199) // else map to next empty slot if it was not mapped before
{
custom_midi_map[found].in = inNumber;
custom_midi_map[found].out = cc_dest_values[seq.temp_select_menu];
custom_midi_map[found].type = 2;
custom_midi_map[found].channel = configuration.dexed[selected_instance_id].midi_channel;
}
else
; // can not be mapped, no empty slot left
}
seq.midi_learn_active = false;
//update_midi_learn_button();
print_custom_mappings();
}
/******************************************************************************
MIDI MESSAGE HANDLER
******************************************************************************/
void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity)
{
//
// Drum Sampler
//
#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
if (seq.midi_learn_active && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_custom_mappings) )
learn_key(inChannel, inNumber);
else
{
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);
//
// Drum Sampler
//
#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
{
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));
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)
{
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);
if (drum_config[activesample].drum_data != NULL && drum_config[activesample].len > 0)
{
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
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++)
//Ignore the note when playing & recording the same note into the sequencer
if (seq.recording == false || (seq.recording && inNumber != seq.note_in ))
{
if (checkMidiChannel(inChannel, instance_id))
// 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 || drum_midi_channel == MIDI_CHANNEL_OMNI)
{
if (drum_counter >= NUM_DRUMS)
drum_counter = 0;
// Check for Drum
if (inChannel == drum_midi_channel || drum_midi_channel == MIDI_CHANNEL_OMNI)
{
if (drum_counter >= NUM_DRUMS)
drum_counter = 0;
//check custom midi mapping
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (inNumber == custom_midi_map[c].in && custom_midi_map[c].type == 1)
{
inNumber = custom_midi_map[c].out;
break;
}
}
#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);
#endif
break;
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;
}
}
}
}
#endif
}
}
//
// E-Piano
//
//
// E-Piano
//
#if defined(USE_EPIANO)
if (configuration.epiano.midi_channel == MIDI_CHANNEL_OMNI || configuration.epiano.midi_channel == inChannel)
{
if (inNumber >= configuration.epiano.lowest_note && inNumber <= configuration.epiano.highest_note)
if (configuration.epiano.midi_channel == MIDI_CHANNEL_OMNI || configuration.epiano.midi_channel == inChannel)
{
ep.noteOn(inNumber + configuration.epiano.transpose - 24, inVelocity);
if (inNumber >= configuration.epiano.lowest_note && inNumber <= configuration.epiano.highest_note)
{
ep.noteOn(inNumber + configuration.epiano.transpose - 24, inVelocity);
#ifdef DEBUG
char note_name[4];
getNoteName(note_name, inNumber);
Serial.print(F("KeyDown "));
Serial.print(note_name);
Serial.print(F(" EPIANO "));
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(" EPIANO "));
Serial.print(F(" MIDI-channel "));
Serial.print(inChannel, DEC);
Serial.println();
#endif
}
}
}
#endif
}
}
#if NUM_DRUMS > 0
@ -1177,216 +1287,252 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
inCtrl = constrain(inCtrl, 0, 127);
inValue = constrain(inValue, 0, 127);
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++)
if (seq.midi_learn_active && LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_cc_mappings) )
learn_cc(inChannel, inCtrl);
else
{
if (checkMidiChannel(inChannel, instance_id))
//check custom midi mapping
for (uint8_t c = 0; c < NUM_CUSTOM_MIDI_MAPPINGS; c++)
{
if (inCtrl == custom_midi_map[c].in && custom_midi_map[c].type == 2)
{
inCtrl = custom_midi_map[c].out;
inChannel = custom_midi_map[c].channel;
break;
}
}
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++)
{
if (checkMidiChannel(inChannel, instance_id))
{
#ifdef DEBUG
Serial.print(F("INSTANCE "));
Serial.print(instance_id, DEC);
Serial.print(F(": CC#"));
Serial.print(inCtrl, DEC);
Serial.print(F(":"));
Serial.println(inValue, DEC);
Serial.print(F("INSTANCE "));
Serial.print(instance_id, DEC);
Serial.print(F(": CC#"));
Serial.print(inCtrl, DEC);
Serial.print(F(":"));
Serial.println(inValue, DEC);
#endif
switch (inCtrl) {
case 0: // BankSelect MSB
switch (inCtrl) {
case 0: // BankSelect MSB
#ifdef DEBUG
Serial.println(F("BANK-SELECT MSB CC"));
Serial.println(F("BANK-SELECT MSB CC"));
#endif
configuration.dexed[instance_id].bank = constrain((inValue << 7)&configuration.dexed[instance_id].bank, 0, MAX_BANKS - 1);
/* load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
} */
break;
case 1:
configuration.dexed[instance_id].bank = constrain((inValue << 7)&configuration.dexed[instance_id].bank, 0, MAX_BANKS - 1);
/* load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
} */
break;
case 1:
#ifdef DEBUG
Serial.println(F("MODWHEEL CC"));
Serial.println(F("MODWHEEL CC"));
#endif
MicroDexed[instance_id]->setModWheel(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 2:
MicroDexed[instance_id]->setModWheel(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 2:
#ifdef DEBUG
Serial.println(F("BREATH CC"));
Serial.println(F("BREATH CC"));
#endif
MicroDexed[instance_id]->setBreathController(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 4:
MicroDexed[instance_id]->setBreathController(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 4:
#ifdef DEBUG
Serial.println(F("FOOT CC"));
Serial.println(F("FOOT CC"));
#endif
MicroDexed[instance_id]->setFootController(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 5: // Portamento time
configuration.dexed[instance_id].portamento_time = inValue;
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
break;
case 7: // Instance Volume
MicroDexed[instance_id]->setFootController(inValue);
MicroDexed[instance_id]->ControllersRefresh();
break;
case 5: // Portamento time
configuration.dexed[instance_id].portamento_time = inValue;
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
break;
case 7: // Instance Volume
#ifdef DEBUG
Serial.println(F("VOLUME CC"));
Serial.println(F("VOLUME CC"));
#endif
configuration.dexed[instance_id].sound_intensity = map(inValue, 0, 127, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX);
MicroDexed[instance_id]->setGain(midi_volume_transform(map(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0, 127)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sound_intensity))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 10: // Pan
configuration.dexed[instance_id].sound_intensity = map(inValue, 0, 127, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX);
MicroDexed[instance_id]->setGain(midi_volume_transform(map(configuration.dexed[instance_id].sound_intensity, SOUND_INTENSITY_MIN, SOUND_INTENSITY_MAX, 0, 127)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_sound_intensity))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 10: // Pan
#ifdef DEBUG
Serial.println(F("PANORAMA CC"));
Serial.println(F("PANORAMA CC"));
#endif
configuration.dexed[instance_id].pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX);
mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_panorama))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 32: // BankSelect LSB
configuration.dexed[instance_id].pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX);
mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_panorama))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 32: // BankSelect LSB
#ifdef DEBUG
Serial.println(F("BANK-SELECT LSB CC"));
Serial.println(F("BANK-SELECT LSB CC"));
#endif
configuration.dexed[instance_id].bank = constrain(inValue, 0, MAX_BANKS - 1);
/*load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}*/
break;
case 64:
MicroDexed[instance_id]->setSustain(inValue > 63);
if (!MicroDexed[instance_id]->getSustain())
{
for (uint8_t note = 0; note < MicroDexed[instance_id]->getMaxNotes(); note++)
configuration.dexed[instance_id].bank = constrain(inValue, 0, MAX_BANKS - 1);
/*load_sd_voice(configuration.dexed[instance_id].bank, configuration.dexed[instance_id].voice, instance_id);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}*/
break;
case 64:
MicroDexed[instance_id]->setSustain(inValue > 63);
if (!MicroDexed[instance_id]->getSustain())
{
if (MicroDexed[instance_id]->voices[note].sustained && !MicroDexed[instance_id]->voices[note].keydown)
for (uint8_t note = 0; note < MicroDexed[instance_id]->getMaxNotes(); note++)
{
MicroDexed[instance_id]->voices[note].dx7_note->keyup();
MicroDexed[instance_id]->voices[note].sustained = false;
if (MicroDexed[instance_id]->voices[note].sustained && !MicroDexed[instance_id]->voices[note].keydown)
{
MicroDexed[instance_id]->voices[note].dx7_note->keyup();
MicroDexed[instance_id]->voices[note].sustained = false;
}
}
}
}
break;
case 65:
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 94: // CC 94: (de)tune
configuration.dexed[selected_instance_id].tune = map(inValue, 0, 0x7f, TUNE_MIN, TUNE_MAX);
MicroDexed[selected_instance_id]->setMasterTune((int((configuration.dexed[selected_instance_id].tune - 100) / 100.0 * 0x4000) << 11) * (1.0 / 12));
MicroDexed[selected_instance_id]->doRefreshVoice();
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_tune))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
break;
case 65:
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_portamento_mode))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 94: // CC 94: (de)tune
configuration.dexed[selected_instance_id].tune = map(inValue, 0, 0x7f, TUNE_MIN, TUNE_MAX);
MicroDexed[selected_instance_id]->setMasterTune((int((configuration.dexed[selected_instance_id].tune - 100) / 100.0 * 0x4000) << 11) * (1.0 / 12));
MicroDexed[selected_instance_id]->doRefreshVoice();
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_tune))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
#if defined(USE_FX)
case 91: // CC 91: reverb send
configuration.fx.reverb_send[selected_instance_id] = map(inValue, 0, 0x7f, REVERB_SEND_MIN, REVERB_SEND_MAX);
reverb_mixer_r.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT)));
reverb_mixer_l.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_reverb_send))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 93: // CC 93: chorus level
configuration.fx.chorus_level[selected_instance_id] = map(inValue, 0, 0x7f, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX);
chorus_mixer[selected_instance_id]->gain(1, volume_transform(mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_chorus_level))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 103: // CC 103: filter resonance
configuration.fx.filter_resonance[instance_id] = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX);
MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_resonance))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 104: // CC 104: filter cutoff
configuration.fx.filter_cutoff[instance_id] = map(inValue, 0, 0x7f, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX);
MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0));;
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_cutoff))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 105: // CC 105: delay time
configuration.fx.delay_time[instance_id] = map(inValue, 0, 0x7f, DELAY_TIME_MIN, DELAY_TIME_MAX);
delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id] * 10, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_time))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 106: // CC 106: delay feedback
configuration.fx.delay_feedback[instance_id] = map(inValue, 0, 0x7f, DELAY_FEEDBACK_MIN , DELAY_FEEDBACK_MAX);
delay_fb_mixer[instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0, 127))); // amount of feedback
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_feedback))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 107: // CC 107: delay volume
configuration.fx.delay_level[instance_id] = map(inValue, 0, 0x7f, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX);
delay_mixer[instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0, 127)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_level))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 91: // CC 91: reverb send
configuration.fx.reverb_send[selected_instance_id] = map(inValue, 0, 0x7f, REVERB_SEND_MIN, REVERB_SEND_MAX);
reverb_mixer_r.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT)));
reverb_mixer_l.gain(selected_instance_id, volume_transform(mapfloat(configuration.fx.reverb_send[selected_instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX, 0.0, VOL_MAX_FLOAT)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_reverb_send))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 93: // CC 93: chorus level
configuration.fx.chorus_level[selected_instance_id] = map(inValue, 0, 0x7f, CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX);
chorus_mixer[selected_instance_id]->gain(1, volume_transform(mapfloat(configuration.fx.chorus_level[selected_instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_chorus_level))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 103: // CC 103: filter resonance
configuration.fx.filter_resonance[instance_id] = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX);
MicroDexed[instance_id]->setFilterResonance(mapfloat(configuration.fx.filter_resonance[instance_id], FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_resonance))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 104: // CC 104: filter cutoff
configuration.fx.filter_cutoff[instance_id] = map(inValue, 0, 0x7f, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX);
MicroDexed[instance_id]->setFilterCutoff(mapfloat(configuration.fx.filter_cutoff[instance_id], FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX, 1.0, 0.0));;
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_filter_cutoff))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 105: // CC 105: delay time
configuration.fx.delay_time[instance_id] = map(inValue, 0, 0x7f, DELAY_TIME_MIN, DELAY_TIME_MAX);
delay_fx[instance_id]->delay(0, constrain(configuration.fx.delay_time[instance_id] * 10, DELAY_TIME_MIN * 10, DELAY_TIME_MAX * 10));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_time))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 106: // CC 106: delay feedback
configuration.fx.delay_feedback[instance_id] = map(inValue, 0, 0x7f, DELAY_FEEDBACK_MIN , DELAY_FEEDBACK_MAX);
delay_fb_mixer[instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0, 127))); // amount of feedback
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_feedback))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
case 107: // CC 107: delay volume
configuration.fx.delay_level[instance_id] = map(inValue, 0, 0x7f, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX);
delay_mixer[instance_id]->gain(1, midi_volume_transform(map(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0, 127)));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_delay_level))
{
LCDML.OTHER_updateFunc();
LCDML.loop_menu();
}
break;
#endif
case 120:
MicroDexed[instance_id]->panic();
break;
case 121:
MicroDexed[instance_id]->resetControllers();
break;
case 123:
MicroDexed[instance_id]->notesOff();
break;
case 126:
if (inValue > 0)
MicroDexed[instance_id]->setMonoMode(true);
else
MicroDexed[instance_id]->setMonoMode(false);
break;
case 127:
if (inValue > 0)
MicroDexed[instance_id]->setMonoMode(true);
else
MicroDexed[instance_id]->setMonoMode(false);
break;
case 120:
MicroDexed[instance_id]->panic();
break;
case 121:
MicroDexed[instance_id]->resetControllers();
break;
case 123:
MicroDexed[instance_id]->notesOff();
break;
case 126:
if (inValue > 0)
MicroDexed[instance_id]->setMonoMode(true);
else
MicroDexed[instance_id]->setMonoMode(false);
break;
case 127:
if (inValue > 0)
MicroDexed[instance_id]->setMonoMode(true);
else
MicroDexed[instance_id]->setMonoMode(false);
break;
case 200: // CC 200: seq start/stop
if (!seq.running)
handleStart();
else
handleStop();
break;
case 201: // CC 201: seq stop
if (seq.running)
handleStop();
break;
case 202: // CC 202: seq record
if (seq.running)
seq.running = true;
seq.recording = true;
seq.note_in = 0;
break;
case 203: // CC 203: dexed panic
MicroDexed[0]->panic();
#if NUM_DEXED > 1
MicroDexed[1]->panic();
#endif
}
}
}
}
#if defined(USE_EPIANO)
if (configuration.epiano.midi_channel == MIDI_CHANNEL_OMNI || configuration.epiano.midi_channel == inChannel)
ep.processMidiController(inCtrl, inValue);

229
UI.hpp

@ -85,6 +85,7 @@ extern drum_config_t drum_config[NUM_DRUMSET_CONFIG];
extern sequencer_t seq;
uint8_t seq_active_function = 99;
uint8_t activesample;
extern custom_midi_map_t custom_midi_map[NUM_CUSTOM_MIDI_MAPPINGS];
#endif
#ifdef SGTL5000_AUDIO_ENHANCE
@ -175,6 +176,18 @@ int temp_int;
bool menu_select_toggle;
float temp_float;
const char cc_names[8][12] = { "Volume ",
"Panorama ",
"Bank Select",
"Reverb Send",
"Seq. Start ",
"Seq. Stop ",
"Seq. RECORD",
"Panic Dexed"
};
const uint8_t cc_dest_values[8] = { 7, 10, 32, 91, 200, 201, 202, 203 };
#ifdef I2C_DISPLAY
#include <LiquidCrystal_I2C.h>
Disp_Plus<LiquidCrystal_I2C> display(LCD_I2C_ADDRESS, _LCDML_DISP_cols, _LCDML_DISP_rows);
@ -4788,6 +4801,222 @@ void UI_func_drum_pitch(uint8_t param)
encoderDir[ENC_R].reset();
}
}
void print_custom_mappings()
{
// display.setTextSize(2);
// display.setTextColor(WHITE, BLACK);
//
// for (uint8_t y = 0; y < 10; y++)
// {
// display.setCursor_textGrid(1, y + 8);
// display.setTextColor(WHITE, BLACK);
// seq_print_formatted_number(y + 1, 2); //entry no.
//
// if (custom_midi_map[y].type == 0)
// {
// display.setTextColor(GREY1, BLACK);
// display.show(y + 8, 4, 5, "NONE" );
// }
// else if (custom_midi_map[y].type == 1)
// {
// display.setTextColor(DX_CYAN, BLACK);
// display.show(y + 8, 4, 7, "KEY/PAD" );
// }
// else if (custom_midi_map[y].type == 2)
// {
// display.setTextColor(DX_CYAN, BLACK);
// display.show(y + 8, 4, 7, "MIDI CC" );
// }
// display.setTextColor(DX_ORANGE, BLACK);
// display.show(y + 8, 12, 3, custom_midi_map[y].in );
//
// display.setTextColor(DX_MAGENTA, BLACK);
// display.show(y + 8, 16, 3, custom_midi_map[y].out );
//
// display.setTextColor(LIGHTBLUE, BLACK);
// display.show(y + 8, 20, 3, custom_midi_map[y].channel );
//
//
// display.setTextColor(DX_PURPLE, BLACK);
// if (custom_midi_map[y].in == 0)
// display.show(y + 8, 24, 12, "EMPTY SLOT");
// else if (custom_midi_map[y].type == 1)
// {
// display.setTextColor(PINK, BLACK);
// display.show(y + 8, 24, 13, find_long_drum_name_from_note(custom_midi_map[y].out) );
// }
// else if (custom_midi_map[y].type == 2)
// {
// display.setTextColor(LIGHTBLUE, BLACK);
// for (uint8_t i = 0; i < sizeof(cc_dest_values); i++)
// {
// if (custom_midi_map[y].out == cc_dest_values[i])
// display.show(y + 8, 24, 13, cc_names[i] );
// }
// }
// }
;
}
void UI_func_custom_mappings(uint8_t param)
{
//char displayname[8] = {0, 0, 0, 0, 0, 0, 0};
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
// display.fillScreen(BLACK);
// display.setTextColor(WHITE, BLACK);
// display.setTextSize(2);
// border1();
// border2();
// border3_large();
// display.setCursor_textGrid(1, 1);
// display.print(F("CUSTOM MAPPINGS"));
//
// display.setTextColor(WHITE, BLUE);
// display.setTextSize(2);
// display.fillRect (240 + CHAR_width, CHAR_height, 8 * CHAR_width, 4 * CHAR_height, BLUE);
// display.setCursor(240 + CHAR_width * 2 + 5, 2 * CHAR_height );
// display.print(F("TOUCH"));
//
// display.drawBitmap(240 + CHAR_width * 2 + 4, CHAR_height * 4 - 12, special_chars[19], 8, 8, GREEN);
// display.setCursor(240 + CHAR_width * 3 + 10, CHAR_height * 4 - 12 );
// display.setTextSize(1);
// display.print(F("PREVIEW"));
//
// display.fillRect (240 + CHAR_width + CHAR_width * 10 - 2, CHAR_height, 8 * CHAR_width, 4 * CHAR_height, BLUE);
// display.setCursor(240 + CHAR_width * 12 + 4, 2 * CHAR_height);
// display.setTextSize(2);
// display.print(F("TOUCH"));
// display.setCursor(240 + CHAR_width * 12 + 3, CHAR_height * 4 - 12 );
// display.setTextSize(1);
// display.print(F("MIDI LEARN"));
//
// //scrollbar
// display.fillRect (480 - 28, 8 * CHAR_height, 14, 10 * CHAR_height, WHITE);
// display.fillRect (480 - 27, 8 * CHAR_height + 1, 12, 4 * CHAR_height, GREY1);
//
// display.setTextSize(2);
// display.setTextColor(WHITE, BLACK);
// display.setCursor_textGrid(1, 7);
// display.print(F("NO TYPE IN OUT CH. NAME"));
print_custom_mappings();
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
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())
{
smart_filter(1);
}
else if (LCDML.BT_checkUp())
{
smart_filter(0);
}
}
if (LCDML.BT_checkEnter())
{
;
}
// display.setTextColor(WHITE, BLACK);
// display.setTextSize(2);
// display.setCursor_textGrid(1, 2);
// display.print("[");
// display.setCursor_textGrid(4, 2);
// display.print("]");
// display.setCursor_textGrid(2, 2);
//
// sprintf(displayname, "%02d", activesample);
// display.print(displayname);
// display.setTextColor(DX_CYAN, BLACK);
// display.show(2, 5, 13, basename(drum_config[activesample].name));
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
seq.midi_learn_active = false;
encoderDir[ENC_R].reset();
}
}
void UI_func_cc_mappings(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
// display.fillScreen(BLACK);
// display.setTextColor(WHITE, BLACK);
// display.setTextSize(2);
// border1();
// border2();
// border3_large();
UI_update_instance_icons();
// display.setCursor_textGrid(1, 1);
// display.print("CUSTOM DEXED CC");
//
// display.setTextColor(WHITE, BLUE);
// display.setTextSize(2);
//
// display.fillRect (240 + CHAR_width + CHAR_width * 10 - 2, CHAR_height, 8 * CHAR_width, 4 * CHAR_height, BLUE);
// display.setCursor(240 + CHAR_width * 12 + 4, 2 * CHAR_height);
// display.setTextSize(2);
// display.print(F("TOUCH"));
// display.setCursor(240 + CHAR_width * 12 + 3, CHAR_height * 4 - 12 );
// display.setTextSize(1);
// display.print(F("MIDI LEARN"));
//
// //scrollbar
// display.fillRect (480 - 28, 8 * CHAR_height, 14, 10 * CHAR_height, WHITE);
// display.fillRect (480 - 27, 8 * CHAR_height + 1, 12, 4 * CHAR_height, GREY1);
//
// display.setTextSize(2);
// display.setTextColor(WHITE, BLACK);
// display.setCursor_textGrid(1, 7);
// display.print(F("NO TYPE IN OUT CH. NAME"));
print_custom_mappings();
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
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())
{
seq.temp_select_menu = constrain(seq.temp_select_menu + ENCODER[ENC_R].speed(), 0, 7);
}
else if (LCDML.BT_checkUp())
{
seq.temp_select_menu = constrain(seq.temp_select_menu - ENCODER[ENC_R].speed(), 0, 7);
}
}
if (LCDML.BT_checkEnter())
{
selected_instance_id = !selected_instance_id;
UI_update_instance_icons();
}
// display.setTextSize(2);
// display.setTextColor(DX_CYAN, BLACK);
// display.show(2, 1, 13, cc_names[seq.temp_select_menu] );
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
seq.midi_learn_active = false;
encoderDir[ENC_R].reset();
}
}
void UI_func_drum_volume(uint8_t param)
{
char displayname[8] = {0, 0, 0, 0, 0, 0, 0};

@ -119,6 +119,7 @@
#endif
// DEFAULT MIDI CHANNEL FOR DRUMSAMPLER
#define DRUM_MIDI_CHANNEL 10
#define NUM_CUSTOM_MIDI_MAPPINGS 20 //Number of Custom Key, CC and Button Mappings
// NUMBER OF SAMPLES IN DRUMSET
#if defined(ARDUINO_TEENSY41)
@ -335,6 +336,7 @@
#define PERFORMANCE_CONFIG_PATH "PERFORMANCE"
#define SEQUENCER_CONFIG_NAME "sequencer"
#define DRUMS_CONFIG_NAME "drums"
#define DRUMS_MAPPING_NAME "drmmap"
#define PATTERN_CONFIG_NAME "patterns"
#define VELOCITY_CONFIG_NAME "velocity"
#define FX_CONFIG_NAME "fx"

@ -38,6 +38,7 @@ using namespace TeensyTimerTool;
#include "drums.h"
extern void set_drums_volume(float vol);
extern drum_config_t drum_config[];
extern custom_midi_map_t custom_midi_map[NUM_CUSTOM_MIDI_MAPPINGS];
#endif
extern void init_MIDI_send_CC(void);
@ -434,6 +435,148 @@ bool save_sd_bank(const char* bank_filename, uint8_t* data)
return (true);
}
/******************************************************************************
SD DRUM CUSTOM MAPPINGS
******************************************************************************/
bool load_sd_drummappings_json(uint8_t number)
{
if (number < 0)
return (false);
number = constrain(number, PERFORMANCE_NUM_MIN, PERFORMANCE_NUM_MAX);
if (sd_card > 0)
{
File json;
StaticJsonDocument<JSON_BUFFER_SIZE> data_json;
char filename[CONFIG_FILENAME_LEN];
sprintf(filename, "/%s/%d/%s.json", PERFORMANCE_CONFIG_PATH, number, DRUMS_MAPPING_NAME);
// first check if file exists...
AudioNoInterrupts();
if (SD.exists(filename))
{
// ... and if: load
#ifdef DEBUG
Serial.print(F("Found drum mapping ["));
Serial.print(filename);
Serial.println(F("]... loading..."));
#endif
json = SD.open(filename);
if (json)
{
deserializeJson(data_json, json);
json.close();
AudioInterrupts();
#ifdef DEBUG
Serial.println(F("Read JSON data:"));
serializeJsonPretty(data_json, Serial);
Serial.println();
#endif
for (uint8_t i = 0; i < NUM_CUSTOM_MIDI_MAPPINGS - 1; i++)
{
custom_midi_map[i].type = data_json["type"][i];
custom_midi_map[i].in = data_json["in"][i];
custom_midi_map[i].out = data_json["out"][i];
custom_midi_map[i].channel = data_json["channel"][i];
}
return (true);
}
#ifdef DEBUG
else
{
Serial.print(F("E : Cannot open "));
Serial.print(filename);
Serial.println(F(" on SD."));
}
}
else
{
Serial.print(F("No "));
Serial.print(filename);
Serial.println(F(" available."));
#endif
}
}
return (false);
}
bool save_sd_drummappings_json(uint8_t number)
{
char filename[CONFIG_FILENAME_LEN];
number = constrain(number, 0, 99);
if (sd_card > 0)
{
File json;
StaticJsonDocument<JSON_BUFFER_SIZE> data_json;
if (check_performance_directory(number))
{
sprintf(filename, "/%s/%d/%s.json", PERFORMANCE_CONFIG_PATH, number, DRUMS_MAPPING_NAME);
#ifdef DEBUG
Serial.print(F("Saving drum mapping "));
Serial.print(number);
Serial.print(F(" to "));
Serial.println(filename);
#endif
AudioNoInterrupts();
if (SD.exists(filename)) {
Serial.println("remove old drum mapping file");
SD.begin();
SD.remove(filename);
}
json = SD.open(filename, FILE_WRITE);
if (json)
{
for (uint8_t i = 0; i < NUM_CUSTOM_MIDI_MAPPINGS - 1; i++)
{
data_json["type"][i] = custom_midi_map[i].type;
data_json["in"][i] = custom_midi_map[i].in;
data_json["out"][i] = custom_midi_map[i].out;
data_json["channel"][i] = custom_midi_map[i].channel;
}
#ifdef DEBUG
Serial.println(F("Write JSON data:"));
serializeJsonPretty(data_json, Serial);
Serial.println();
#endif
serializeJsonPretty(data_json, json);
json.close();
AudioInterrupts();
return (true);
}
else
{
#ifdef DEBUG
Serial.print(F("E : Cannot open "));
Serial.print(filename);
Serial.println(F(" on SD."));
#endif
AudioInterrupts();
return (false);
}
}
else
{
AudioInterrupts();
return (false);
}
}
#ifdef DEBUG
else
{
Serial.println(F("E: SD card not available"));
}
#endif
return (false);
}
/******************************************************************************
SD DRUMSETTINGS
******************************************************************************/
@ -532,7 +675,9 @@ bool save_sd_drumsettings_json(uint8_t number)
#endif
AudioNoInterrupts();
if (SD.exists(filename)) {
#ifdef DEBUG
Serial.println("remove old drumsettings file");
#endif
SD.begin();
SD.remove(filename);
}
@ -1371,6 +1516,7 @@ bool save_sd_performance_json(uint8_t number)
save_sd_seq_sub_vel_json(number);
save_sd_seq_sub_patterns_json(number);
save_sd_drummappings_json(number);
save_sd_fx_json(number);
save_sd_epiano_json(number);
@ -1456,6 +1602,7 @@ bool save_sd_performance_json(uint8_t number)
return (true);
}
json.close();
AudioInterrupts();
}
#ifdef DEBUG
else
@ -1463,6 +1610,7 @@ bool save_sd_performance_json(uint8_t number)
Serial.print(F("E : Cannot open "));
Serial.print(filename);
Serial.println(F(" on SD."));
AudioInterrupts();
}
#endif
@ -1718,6 +1866,7 @@ bool load_sd_performance_json(uint8_t number)
load_sd_seq_sub_vel_json(number);
load_sd_fx_json(number);
load_sd_epiano_json(number);
load_sd_drummappings_json(number);
if (sd_card > 0)
{

@ -38,7 +38,7 @@ typedef struct drum_config_s {
const uint8_t* drum_data;
char shortname[2]; // 1 char name for sequencer
uint32_t len; // number of elements in drum_data
float32_t pitch; // variable pitch per note for sequencer
float32_t pitch; // variable pitch per note for sequencer
float32_t p_offset; // "static" pitch offset to correct root note to root of other samples
float32_t pan; // Panorama (-1.0 - +1.0)
float32_t vol_max; // max. Volume (0.0 - 1.0)
@ -46,6 +46,14 @@ 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,DRUM_POLY};
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};
typedef struct custom_midi_map_s {
uint8_t type; // 0 = empty, 1 = Key/Pad, 2 = CC / Values, 3 = Button push on/off
uint8_t channel; // Midi Channel
uint8_t in; // Midi Input Key/Pad / Value
uint8_t out; // Destination Key / Value
} custom_midi_map_t;
#endif

@ -27,6 +27,7 @@
typedef struct sequencer_s
{
bool midi_learn_active = false;
float drums_volume;
uint8_t active_track = 0;
uint8_t menu;

Loading…
Cancel
Save