Merge branch 'dev-portamento' into dev

pull/17/head
Holger Wirtz 5 years ago
commit 86b1cebbb0
  1. 90
      MicroDexed.ino
  2. 189
      UI.hpp
  3. 11
      config.h
  4. 3
      controllers.h
  5. 29
      dexed.cpp
  6. 14
      dexed.h
  7. 37
      dx7note.cpp
  8. 57
      dx7note.h
  9. 35
      porta.cpp
  10. 28
      porta.h

@ -610,6 +610,10 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
MicroDexed[instance_id]->controllers.foot_cc = inValue; MicroDexed[instance_id]->controllers.foot_cc = inValue;
MicroDexed[instance_id]->controllers.refresh(); MicroDexed[instance_id]->controllers.refresh();
break; 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: // Volume case 7: // Volume
#ifdef DEBUG #ifdef DEBUG
Serial.println(F("VOLUME CC")); Serial.println(F("VOLUME CC"));
@ -644,6 +648,9 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
} }
} }
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);
break;
case 103: // CC 103: filter resonance case 103: // CC 103: filter resonance
configuration.dexed[instance_id].filter_resonance = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); configuration.dexed[instance_id].filter_resonance = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX);
MicroDexed[instance_id]->fx.Reso = mapfloat(configuration.dexed[instance_id].filter_resonance, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0); MicroDexed[instance_id]->fx.Reso = mapfloat(configuration.dexed[instance_id].filter_resonance, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX, 1.0, 0.0);
@ -832,6 +839,7 @@ void handleSystemExclusive(byte * sysex, uint len)
MicroDexed[instance_id]->controllers.at.setRange(MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_RANGE]); MicroDexed[instance_id]->controllers.at.setRange(MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_RANGE]);
MicroDexed[instance_id]->controllers.at.setTarget(MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_ASSIGN]); MicroDexed[instance_id]->controllers.at.setTarget(MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_ASSIGN]);
MicroDexed[instance_id]->controllers.masterTune = (MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MASTER_TUNE] / 10 * 0x4000 << 11) * (1.0 / 12); MicroDexed[instance_id]->controllers.masterTune = (MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MASTER_TUNE] / 10 * 0x4000 << 11) * (1.0 / 12);
MicroDexed[instance_id]->setPortamentoMode(MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_MODE], MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_GLISSANDO], MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_TIME]);
MicroDexed[instance_id]->controllers.refresh(); MicroDexed[instance_id]->controllers.refresh();
data_index = DEXED_GLOBAL_PARAMETER_OFFSET - 63 + sysex[4]; data_index = DEXED_GLOBAL_PARAMETER_OFFSET - 63 + sysex[4];
} }
@ -1182,20 +1190,23 @@ void check_configuration(void)
configuration.dexed[instance_id].filter_resonance = constrain(configuration.dexed[instance_id].filter_resonance, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX); configuration.dexed[instance_id].filter_resonance = constrain(configuration.dexed[instance_id].filter_resonance, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX);
configuration.dexed[instance_id].loudness = constrain(configuration.dexed[instance_id].loudness, LOUDNESS_MIN, LOUDNESS_MAX); configuration.dexed[instance_id].loudness = constrain(configuration.dexed[instance_id].loudness, LOUDNESS_MIN, LOUDNESS_MAX);
configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose, TRANSPOSE_MIN, TRANSPOSE_MAX); configuration.dexed[instance_id].transpose = constrain(configuration.dexed[instance_id].transpose, TRANSPOSE_MIN, TRANSPOSE_MAX);
configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune, TUNE_MIN, TUNE_MAX); configuration.dexed[instance_id].tune = constrain(configuration.dexed[instance_id].tune, TUNE_MIN, TUNE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MASTER_TUNE] = configuration.dexed[instance_id].tune;
configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony, POLYPHONY_MIN, POLYPHONY_MAX); configuration.dexed[instance_id].polyphony = constrain(configuration.dexed[instance_id].polyphony, POLYPHONY_MIN, POLYPHONY_MAX);
configuration.dexed[instance_id].engine = constrain(configuration.dexed[instance_id].engine, ENGINE_MIN, ENGINE_MAX); configuration.dexed[instance_id].engine = constrain(configuration.dexed[instance_id].engine, ENGINE_MIN, ENGINE_MAX);
configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly, MONOPOLY_MIN, MONOPOLY_MAX); configuration.dexed[instance_id].monopoly = constrain(configuration.dexed[instance_id].monopoly, MONOPOLY_MIN, MONOPOLY_MAX);
configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range, PB_RANGE_MIN, PB_RANGE_MAX); configuration.dexed[instance_id].pb_range = constrain(configuration.dexed[instance_id].pb_range, PB_RANGE_MIN, PB_RANGE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_RANGE] = configuration.dexed[instance_id].pb_range;
configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step, PB_STEP_MIN, PB_STEP_MAX); configuration.dexed[instance_id].pb_step = constrain(configuration.dexed[instance_id].pb_step, PB_STEP_MIN, PB_STEP_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_STEP] = configuration.dexed[instance_id].pb_step;
configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range, MW_RANGE_MIN, MW_RANGE_MAX); configuration.dexed[instance_id].mw_range = constrain(configuration.dexed[instance_id].mw_range, MW_RANGE_MIN, MW_RANGE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_RANGE] = configuration.dexed[instance_id].mw_range;
configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign, MW_ASSIGN_MIN, MW_ASSIGN_MAX); configuration.dexed[instance_id].mw_assign = constrain(configuration.dexed[instance_id].mw_assign, MW_ASSIGN_MIN, MW_ASSIGN_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_ASSIGN] = configuration.dexed[instance_id].mw_assign;
configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range, FC_RANGE_MIN, FC_RANGE_MAX); configuration.dexed[instance_id].fc_range = constrain(configuration.dexed[instance_id].fc_range, FC_RANGE_MIN, FC_RANGE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_RANGE] = configuration.dexed[instance_id].fc_range;
configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign, FC_ASSIGN_MIN, FC_ASSIGN_MAX); configuration.dexed[instance_id].fc_assign = constrain(configuration.dexed[instance_id].fc_assign, FC_ASSIGN_MIN, FC_ASSIGN_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_ASSIGN] = configuration.dexed[instance_id].fc_assign;
configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range, BC_RANGE_MIN, BC_RANGE_MAX); configuration.dexed[instance_id].bc_range = constrain(configuration.dexed[instance_id].bc_range, BC_RANGE_MIN, BC_RANGE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_RANGE] = configuration.dexed[instance_id].bc_range;
configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign, BC_ASSIGN_MIN, BC_ASSIGN_MAX); configuration.dexed[instance_id].bc_assign = constrain(configuration.dexed[instance_id].bc_assign, BC_ASSIGN_MIN, BC_ASSIGN_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_ASSIGN] = configuration.dexed[instance_id].bc_assign;
configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range, AT_RANGE_MIN, AT_RANGE_MAX); configuration.dexed[instance_id].at_range = constrain(configuration.dexed[instance_id].at_range, AT_RANGE_MIN, AT_RANGE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_RANGE] = configuration.dexed[instance_id].at_range;
configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign, AT_ASSIGN_MIN, AT_ASSIGN_MAX); configuration.dexed[instance_id].at_assign = constrain(configuration.dexed[instance_id].at_assign, AT_ASSIGN_MIN, AT_ASSIGN_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_ASSIGN] = configuration.dexed[instance_id].at_assign;
configuration.dexed[instance_id].portamento_mode = constrain(configuration.dexed[instance_id].portamento_mode, PORTAMENTO_MODE_MIN, PORTAMENTO_MODE_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_MODE] = configuration.dexed[instance_id].portamento_mode;
configuration.dexed[instance_id].portamento_glissando = constrain(configuration.dexed[instance_id].portamento_glissando, PORTAMENTO_GLISSANDO_MIN, PORTAMENTO_GLISSANDO_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_GLISSANDO] = configuration.dexed[instance_id].portamento_glissando;
configuration.dexed[instance_id].portamento_time = constrain(configuration.dexed[instance_id].portamento_time, PORTAMENTO_TIME_MIN, PORTAMENTO_TIME_MAX); MicroDexed[instance_id]->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_TIME] = configuration.dexed[instance_id].portamento_time;
configuration.dexed[instance_id].op_enabled = constrain(configuration.dexed[instance_id].op_enabled, OP_ENABLED_MIN, OP_ENABLED_MAX); configuration.dexed[instance_id].op_enabled = constrain(configuration.dexed[instance_id].op_enabled, OP_ENABLED_MIN, OP_ENABLED_MAX);
} }
} }
@ -1246,6 +1257,9 @@ void init_configuration(void)
configuration.dexed[instance_id].bc_assign = BC_ASSIGN_DEFAULT; configuration.dexed[instance_id].bc_assign = BC_ASSIGN_DEFAULT;
configuration.dexed[instance_id].at_range = AT_RANGE_DEFAULT; configuration.dexed[instance_id].at_range = AT_RANGE_DEFAULT;
configuration.dexed[instance_id].at_assign = AT_ASSIGN_DEFAULT; configuration.dexed[instance_id].at_assign = AT_ASSIGN_DEFAULT;
configuration.dexed[instance_id].portamento_mode = PORTAMENTO_MODE_DEFAULT;
configuration.dexed[instance_id].portamento_glissando = PORTAMENTO_GLISSANDO_DEFAULT;
configuration.dexed[instance_id].portamento_time = PORTAMENTO_TIME_DEFAULT;
configuration.dexed[instance_id].op_enabled = OP_ENABLED_DEFAULT; configuration.dexed[instance_id].op_enabled = OP_ENABLED_DEFAULT;
} }
eeprom_update(); eeprom_update();
@ -1359,31 +1373,33 @@ void show_configuration(void)
Serial.print(F("=== DEXED INSTANCE ")); Serial.print(F("=== DEXED INSTANCE "));
Serial.print(instance_id, DEC); Serial.print(instance_id, DEC);
Serial.println(" ==="); Serial.println(" ===");
Serial.print(F(" MIDI-Channel ")); Serial.println(configuration.dexed[instance_id].midi_channel, DEC); Serial.print(F(" MIDI-Channel ")); Serial.println(configuration.dexed[instance_id].midi_channel, DEC);
Serial.print(F(" Bank ")); Serial.println(configuration.dexed[instance_id].bank, DEC); Serial.print(F(" Bank ")); Serial.println(configuration.dexed[instance_id].bank, DEC);
Serial.print(F(" Voice ")); Serial.println(configuration.dexed[instance_id].voice, DEC); Serial.print(F(" Voice ")); Serial.println(configuration.dexed[instance_id].voice, DEC);
Serial.print(F(" Reverb Send ")); Serial.println(configuration.dexed[instance_id].reverb_send, DEC); Serial.print(F(" Reverb Send ")); Serial.println(configuration.dexed[instance_id].reverb_send, DEC);
Serial.print(F(" Chorus Send ")); Serial.println(configuration.dexed[instance_id].chorus_send, DEC); Serial.print(F(" Chorus Send ")); Serial.println(configuration.dexed[instance_id].chorus_send, DEC);
Serial.print(F(" Delay Send ")); Serial.println(configuration.dexed[instance_id].delay_send, DEC); Serial.print(F(" Delay Send ")); Serial.println(configuration.dexed[instance_id].delay_send, DEC);
Serial.print(F(" Filter Cutoff ")); Serial.println(configuration.dexed[instance_id].filter_cutoff, DEC); Serial.print(F(" Filter Cutoff ")); Serial.println(configuration.dexed[instance_id].filter_cutoff, DEC);
Serial.print(F(" Filter Resonance ")); Serial.println(configuration.dexed[instance_id].filter_resonance, DEC); Serial.print(F(" Filter Resonance ")); Serial.println(configuration.dexed[instance_id].filter_resonance, DEC);
Serial.print(F(" Loudness ")); Serial.println(configuration.dexed[instance_id].loudness, DEC); Serial.print(F(" Loudness ")); Serial.println(configuration.dexed[instance_id].loudness, DEC);
Serial.print(F(" Transpose ")); Serial.println(configuration.dexed[instance_id].transpose, DEC); Serial.print(F(" Transpose ")); Serial.println(configuration.dexed[instance_id].transpose, DEC);
Serial.print(F(" Tune ")); Serial.println(configuration.dexed[instance_id].tune, DEC); Serial.print(F(" Tune ")); Serial.println(configuration.dexed[instance_id].tune, DEC);
Serial.print(F(" Polyphony ")); Serial.println(configuration.dexed[instance_id].polyphony, DEC); Serial.print(F(" Polyphony ")); Serial.println(configuration.dexed[instance_id].polyphony, DEC);
Serial.print(F(" Engine ")); Serial.println(configuration.dexed[instance_id].engine, DEC); Serial.print(F(" Engine ")); Serial.println(configuration.dexed[instance_id].engine, DEC);
Serial.print(F(" Mono/Poly ")); Serial.println(configuration.dexed[instance_id].monopoly, DEC); Serial.print(F(" Mono/Poly ")); Serial.println(configuration.dexed[instance_id].monopoly, DEC);
Serial.print(F(" Pitchbend Range ")); Serial.println(configuration.dexed[instance_id].pb_range, DEC); Serial.print(F(" Pitchbend Range ")); Serial.println(configuration.dexed[instance_id].pb_range, DEC);
Serial.print(F(" Pitchbend Step ")); Serial.println(configuration.dexed[instance_id].pb_step, DEC); Serial.print(F(" Pitchbend Step ")); Serial.println(configuration.dexed[instance_id].pb_step, DEC);
Serial.print(F(" Modwheel Range ")); Serial.println(configuration.dexed[instance_id].mw_range, DEC); Serial.print(F(" Modwheel Range ")); Serial.println(configuration.dexed[instance_id].mw_range, DEC);
Serial.print(F(" Modwheel Assign ")); Serial.println(configuration.dexed[instance_id].mw_assign, DEC); Serial.print(F(" Modwheel Assign ")); Serial.println(configuration.dexed[instance_id].mw_assign, DEC);
Serial.print(F(" Footctrl Range ")); Serial.println(configuration.dexed[instance_id].fc_range, DEC); Serial.print(F(" Footctrl Range ")); Serial.println(configuration.dexed[instance_id].fc_range, DEC);
Serial.print(F(" Footctrl Assign ")); Serial.println(configuration.dexed[instance_id].fc_assign, DEC); Serial.print(F(" Footctrl Assign ")); Serial.println(configuration.dexed[instance_id].fc_assign, DEC);
Serial.print(F(" BreathCtrl Range ")); Serial.println(configuration.dexed[instance_id].bc_range, DEC); Serial.print(F(" BreathCtrl Range ")); Serial.println(configuration.dexed[instance_id].bc_range, DEC);
Serial.print(F(" Breathctrl Assign ")); Serial.println(configuration.dexed[instance_id].bc_assign, DEC); Serial.print(F(" Breathctrl Assign ")); Serial.println(configuration.dexed[instance_id].bc_assign, DEC);
Serial.print(F(" Aftertouch Range ")); Serial.println(configuration.dexed[instance_id].at_range, DEC); Serial.print(F(" Aftertouch Range ")); Serial.println(configuration.dexed[instance_id].at_range, DEC);
Serial.print(F(" Aftertouch Assign ")); Serial.println(configuration.dexed[instance_id].at_assign, DEC); Serial.print(F(" Portamento Mode ")); Serial.println(configuration.dexed[instance_id].portamento_mode, DEC);
Serial.print(F(" OP Enabled ")); Serial.println(configuration.dexed[instance_id].op_enabled, DEC); Serial.print(F(" Portamento Glissando ")); Serial.println(configuration.dexed[instance_id].portamento_glissando, DEC);
Serial.print(F(" Portamento Time ")); Serial.println(configuration.dexed[instance_id].portamento_time, DEC);
Serial.print(F(" OP Enabled ")); Serial.println(configuration.dexed[instance_id].op_enabled, DEC);
Serial.flush(); Serial.flush();
} }
Serial.println(); Serial.println();
@ -1484,7 +1500,7 @@ void show_patch(uint8_t instance_id)
Serial.print(voicename); Serial.print(voicename);
Serial.println(F("]")); Serial.println(F("]"));
Serial.flush(); Serial.flush();
for (i = DEXED_GLOBAL_PARAMETER_OFFSET; i <= DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MAX_NOTES; i++) for (i = DEXED_GLOBAL_PARAMETER_OFFSET; i <= DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_TIME; i++)
{ {
Serial.print(i, DEC); Serial.print(i, DEC);
Serial.print(F(": ")); Serial.print(F(": "));

189
UI.hpp

@ -158,6 +158,9 @@ void UI_func_bc_range(uint8_t param);
void UI_func_bc_assign(uint8_t param); void UI_func_bc_assign(uint8_t param);
void UI_func_at_range(uint8_t param); void UI_func_at_range(uint8_t param);
void UI_func_at_assign(uint8_t param); void UI_func_at_assign(uint8_t param);
void UI_func_portamento_mode(uint8_t param);
void UI_func_portamento_glissando(uint8_t param);
void UI_func_portamento_time(uint8_t param);
void UI_func_OP1(uint8_t param); void UI_func_OP1(uint8_t param);
void UI_func_OP2(uint8_t param); void UI_func_OP2(uint8_t param);
void UI_func_OP3(uint8_t param); void UI_func_OP3(uint8_t param);
@ -211,9 +214,9 @@ LCDML_add(28, LCDML_0_1_1, 17, "Aftertouch 1", NULL);
LCDML_add(29, LCDML_0_1_1_17, 1, "AT Range 1", UI_func_at_range); LCDML_add(29, LCDML_0_1_1_17, 1, "AT Range 1", UI_func_at_range);
LCDML_add(30, LCDML_0_1_1_17, 2, "AT Assign 1", UI_func_at_assign); LCDML_add(30, LCDML_0_1_1_17, 2, "AT Assign 1", UI_func_at_assign);
LCDML_add(31, LCDML_0_1_1, 18, "Portamento 1", NULL); LCDML_add(31, LCDML_0_1_1, 18, "Portamento 1", NULL);
LCDML_add(32, LCDML_0_1_1_18, 1, "Port. Mode 1", UI_function_not_enabled); LCDML_add(32, LCDML_0_1_1_18, 1, "Port. Mode 1", UI_func_portamento_mode);
LCDML_add(33, LCDML_0_1_1_18, 2, "Port. Gliss 1", UI_function_not_enabled); LCDML_add(33, LCDML_0_1_1_18, 2, "Port. Gliss 1", UI_func_portamento_glissando);
LCDML_add(34, LCDML_0_1_1_18, 3, "Port. Time 1", UI_function_not_enabled); LCDML_add(34, LCDML_0_1_1_18, 3, "Port. Time 1", UI_func_portamento_time);
LCDML_add(35, LCDML_0_1_1, 19, "Operator 1", NULL); LCDML_add(35, LCDML_0_1_1, 19, "Operator 1", NULL);
LCDML_add(36, LCDML_0_1_1_19, 1, "OP1 1", UI_func_OP1); LCDML_add(36, LCDML_0_1_1_19, 1, "OP1 1", UI_func_OP1);
LCDML_add(37, LCDML_0_1_1_19, 2, "OP2 1", UI_func_OP2); LCDML_add(37, LCDML_0_1_1_19, 2, "OP2 1", UI_func_OP2);
@ -252,9 +255,9 @@ LCDML_add(69, LCDML_0_1_2, 17, "Aftertouch 2", NULL);
LCDML_add(70, LCDML_0_1_2_17, 1, "AT Range 2", UI_func_at_range); LCDML_add(70, LCDML_0_1_2_17, 1, "AT Range 2", UI_func_at_range);
LCDML_add(71, LCDML_0_1_2_17, 2, "AT Assign 2", UI_func_at_assign); LCDML_add(71, LCDML_0_1_2_17, 2, "AT Assign 2", UI_func_at_assign);
LCDML_add(72, LCDML_0_1_2, 18, "Portamento 2", NULL); LCDML_add(72, LCDML_0_1_2, 18, "Portamento 2", NULL);
LCDML_add(73, LCDML_0_1_2_18, 1, "Port. Mode 2", UI_function_not_enabled); LCDML_add(73, LCDML_0_1_2_18, 1, "Port. Mode 2", UI_func_portamento_mode);
LCDML_add(74, LCDML_0_1_2_18, 2, "Port. Gliss 2", UI_function_not_enabled); LCDML_add(74, LCDML_0_1_2_18, 2, "Port. Gliss 2", UI_func_portamento_glissando);
LCDML_add(75, LCDML_0_1_2_18, 3, "Port. Time 2", UI_function_not_enabled); LCDML_add(75, LCDML_0_1_2_18, 3, "Port. Time 2", UI_func_portamento_time);
LCDML_add(76, LCDML_0_1_2, 19, "Operator 2", NULL); LCDML_add(76, LCDML_0_1_2, 19, "Operator 2", NULL);
LCDML_add(77, LCDML_0_1_2_19, 1, "OP1 2", UI_func_OP1); LCDML_add(77, LCDML_0_1_2_19, 1, "OP1 2", UI_func_OP1);
LCDML_add(78, LCDML_0_1_2_19, 2, "OP2 2", UI_func_OP2); LCDML_add(78, LCDML_0_1_2_19, 2, "OP2 2", UI_func_OP2);
@ -311,9 +314,9 @@ LCDML_add(27, LCDML_0_1, 17, "Aftertouch", NULL);
LCDML_add(28, LCDML_0_1_17, 1, "AT Range", UI_func_at_range); LCDML_add(28, LCDML_0_1_17, 1, "AT Range", UI_func_at_range);
LCDML_add(29, LCDML_0_1_17, 2, "AT Assign", UI_func_at_assign); LCDML_add(29, LCDML_0_1_17, 2, "AT Assign", UI_func_at_assign);
LCDML_add(30, LCDML_0_1, 18, "Portamento", NULL); LCDML_add(30, LCDML_0_1, 18, "Portamento", NULL);
LCDML_add(31, LCDML_0_1_18, 1, "Port. Mode", UI_function_not_implemented); LCDML_add(31, LCDML_0_1_18, 1, "Port. Mode", UI_func_portamento_mode);
LCDML_add(32, LCDML_0_1_18, 2, "Port. Gliss", UI_function_not_implemented); LCDML_add(32, LCDML_0_1_18, 2, "Port. Gliss", UI_func_portamento_glissando);
LCDML_add(33, LCDML_0_1_18, 3, "Port. Time", UI_function_not_implemented); LCDML_add(33, LCDML_0_1_18, 3, "Port. Time", UI_func_portamento_time);
LCDML_add(34, LCDML_0_1, 19, "Operator", NULL); LCDML_add(34, LCDML_0_1, 19, "Operator", NULL);
LCDML_add(35, LCDML_0_1_19, 1, "OP1", UI_func_OP1); LCDML_add(35, LCDML_0_1_19, 1, "OP1", UI_func_OP1);
LCDML_add(36, LCDML_0_1_19, 2, "OP2", UI_func_OP2); LCDML_add(36, LCDML_0_1_19, 2, "OP2", UI_func_OP2);
@ -2663,7 +2666,175 @@ void UI_func_at_assign(uint8_t param)
lcd.print(F("[PTCH AMP EG-BS]")); lcd.print(F("[PTCH AMP EG-BS]"));
break; break;
} }
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
eeprom_write();
}
}
void UI_func_portamento_mode(uint8_t param)
{
uint8_t instance_id = 0;
if (LCDML.FUNC_getID() > MENU_ID_OF_INSTANCE_2)
instance_id = 1;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Portamento Mode"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown() || LCDML.BT_checkUp())
{
if (LCDML.BT_checkDown())
{
if (configuration.dexed[instance_id].portamento_mode < PORTAMENTO_MODE_MAX)
{
configuration.dexed[instance_id].portamento_mode++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.dexed[instance_id].portamento_mode > PORTAMENTO_MODE_MIN)
{
configuration.dexed[instance_id].portamento_mode--;
}
}
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
}
lcd.setCursor(0, 1);
switch (configuration.dexed[instance_id].portamento_mode)
{
case 0:
lcd.print(F("[RETAIN ]"));
break;
case 1:
lcd.print(F("[FOLLOW ]"));
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
eeprom_write();
}
}
void UI_func_portamento_glissando(uint8_t param)
{
uint8_t instance_id = 0;
if (LCDML.FUNC_getID() > MENU_ID_OF_INSTANCE_2)
instance_id = 1;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Portam. Gliss."));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown() || LCDML.BT_checkUp())
{
if (LCDML.BT_checkDown())
{
if (configuration.dexed[instance_id].portamento_glissando < PORTAMENTO_GLISSANDO_MAX)
{
configuration.dexed[instance_id].portamento_glissando++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.dexed[instance_id].portamento_glissando > PORTAMENTO_GLISSANDO_MIN)
{
configuration.dexed[instance_id].portamento_glissando--;
}
}
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
}
lcd.setCursor(0, 1);
switch (configuration.dexed[instance_id].portamento_glissando)
{
case 0:
lcd.print(F("[OFF ]"));
break;
case 1:
lcd.print(F("[ON ]"));
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
eeprom_write();
}
}
void UI_func_portamento_time(uint8_t param)
{
uint8_t instance_id = 0;
if (LCDML.FUNC_getID() > MENU_ID_OF_INSTANCE_2)
instance_id = 1;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Portam. Time"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown() || LCDML.BT_checkUp())
{
if (LCDML.BT_checkDown())
{
if (configuration.dexed[instance_id].portamento_time < PORTAMENTO_TIME_MAX)
{
configuration.dexed[instance_id].portamento_time++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.dexed[instance_id].portamento_time > PORTAMENTO_TIME_MIN)
{
configuration.dexed[instance_id].portamento_time--;
}
}
MicroDexed[instance_id]->setPortamentoMode(configuration.dexed[instance_id].portamento_mode, configuration.dexed[instance_id].portamento_glissando, configuration.dexed[instance_id].portamento_time);
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.dexed[instance_id].portamento_time, 2, false, true, false);
} }
if (LCDML.FUNC_close()) // ****** STABLE END ********* if (LCDML.FUNC_close()) // ****** STABLE END *********

@ -403,13 +403,13 @@ enum { DEXED, REVERB, DELAY, CHORUS };
#define PORTAMENTO_MODE_MAX 1 #define PORTAMENTO_MODE_MAX 1
#define PORTAMENTO_MODE_DEFAULT 0 // 0: Retain, 1: Follow #define PORTAMENTO_MODE_DEFAULT 0 // 0: Retain, 1: Follow
#define PORTAMENTO_GLISS_MIN 0 #define PORTAMENTO_GLISSANDO_MIN 0
#define PORTAMENTO_GLISS_MAX 1 #define PORTAMENTO_GLISSANDO_MAX 1
#define PORTAMENTO_GLISS_DEFAULT 0 #define PORTAMENTO_GLISSANDO_DEFAULT 0
#define PORTAMENTO_TIME_MIN 0 #define PORTAMENTO_TIME_MIN 0
#define PORTAMENTO_TIME_MAX 99 #define PORTAMENTO_TIME_MAX 99
#define PORTAMENTO_TIME_DEFAULT 50 #define PORTAMENTO_TIME_DEFAULT 0
#define INSTANCES_MIN 1 #define INSTANCES_MIN 1
#define INSTANCES_MAX NUM_DEXED #define INSTANCES_MAX NUM_DEXED
@ -449,6 +449,9 @@ typedef struct {
uint8_t bc_assign; uint8_t bc_assign;
uint8_t at_range; uint8_t at_range;
uint8_t at_assign; uint8_t at_assign;
uint8_t portamento_mode;
uint8_t portamento_glissando;
uint8_t portamento_time;
uint8_t op_enabled; uint8_t op_enabled;
} dexed_t; } dexed_t;

@ -21,6 +21,7 @@
#include "synth.h" #include "synth.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h>
// State of MIDI controllers // State of MIDI controllers
const int kControllerPitch = 0; const int kControllerPitch = 0;
@ -79,6 +80,8 @@ class Controllers {
uint8_t breath_cc; uint8_t breath_cc;
uint8_t foot_cc; uint8_t foot_cc;
uint8_t modwheel_cc; uint8_t modwheel_cc;
bool portamento_enable_cc;
int portamento_cc;
int masterTune; int masterTune;

@ -36,6 +36,7 @@
#include "PluginFx.h" #include "PluginFx.h"
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include "porta.h"
#ifdef USE_TEENSY_DSP #ifdef USE_TEENSY_DSP
#include <Audio.h> #include <Audio.h>
#endif #endif
@ -52,6 +53,7 @@ Dexed::Dexed(int rate)
Lfo::init(rate); Lfo::init(rate);
PitchEnv::init(rate); PitchEnv::init(rate);
Env::init_sr(rate); Env::init_sr(rate);
Porta::init_sr(rate);
fx.init(rate); fx.init(rate);
engineMkI = new EngineMkI; engineMkI = new EngineMkI;
@ -71,6 +73,7 @@ Dexed::Dexed(int rate)
controllers.masterTune = 0; controllers.masterTune = 0;
controllers.opSwitch = 0x3f; // enable all operators controllers.opSwitch = 0x3f; // enable all operators
//controllers.opSwitch=0x00; //controllers.opSwitch=0x00;
lastKeyDown = -1;
lfo.reset(data + 137); lfo.reset(data + 137);
@ -188,6 +191,13 @@ void Dexed::keydown(uint8_t pitch, uint8_t velo) {
pitch += data[144] - TRANSPOSE_FIX; pitch += data[144] - TRANSPOSE_FIX;
int previousKeyDown = lastKeyDown;
lastKeyDown = pitch;
int porta = -1;
if ( controllers.portamento_enable_cc && previousKeyDown >= 0 )
porta = controllers.portamento_cc;
uint8_t note = currentNote; uint8_t note = currentNote;
uint8_t keydown_counter = 0; uint8_t keydown_counter = 0;
@ -198,7 +208,7 @@ void Dexed::keydown(uint8_t pitch, uint8_t velo) {
voices[note].velocity = velo; voices[note].velocity = velo;
voices[note].sustained = sustain; voices[note].sustained = sustain;
voices[note].keydown = true; voices[note].keydown = true;
voices[note].dx7_note->init(data, (int)pitch, (int)velo); voices[note].dx7_note->init(data, pitch, velo, previousKeyDown, porta);
if ( data[136] ) if ( data[136] )
voices[note].dx7_note->oscSync(); voices[note].dx7_note->oscSync();
break; break;
@ -355,6 +365,8 @@ void Dexed::resetControllers(void)
controllers.foot_cc = 0; controllers.foot_cc = 0;
controllers.breath_cc = 0; controllers.breath_cc = 0;
controllers.aftertouch_cc = 0; controllers.aftertouch_cc = 0;
controllers.portamento_enable_cc = false;
controllers.portamento_cc = 0;
controllers.refresh(); controllers.refresh();
} }
@ -718,3 +730,18 @@ void Dexed::setATController(uint8_t at_range, uint8_t at_assign)
controllers.refresh(); controllers.refresh();
} }
void Dexed::setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissando, uint8_t portamento_time)
{
data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_MODE] = portamento_mode;
data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_GLISSANDO] = portamento_glissando;
data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PORTAMENTO_TIME] = portamento_time;
controllers.portamento_cc = portamento_time;
if (portamento_time > 0)
controllers.portamento_enable_cc = true;
else
controllers.portamento_enable_cc = false;
controllers.refresh();
}

@ -56,8 +56,8 @@ struct ProcessorVoice {
enum DexedEngineResolution { enum DexedEngineResolution {
DEXED_ENGINE_MODERN, // 0 DEXED_ENGINE_MODERN, // 0
DEXED_ENGINE_MARKI, // 1 DEXED_ENGINE_MARKI, // 1
DEXED_ENGINE_OPL // 2 DEXED_ENGINE_OPL // 2
}; };
enum DexedVoiceOPParameters { enum DexedVoiceOPParameters {
@ -128,7 +128,9 @@ enum DexedGlobalParameters {
DEXED_OP5_ENABLE, // 15 DEXED_OP5_ENABLE, // 15
DEXED_OP6_ENABLE, // 16 DEXED_OP6_ENABLE, // 16
DEXED_MAX_NOTES, // 17 DEXED_MAX_NOTES, // 17
DEXED_VOICE_VOLUME // 18 DEXED_PORTAMENTO_MODE, // 18
DEXED_PORTAMENTO_GLISSANDO, // 19
DEXED_PORTAMENTO_TIME, // 20
}; };
// GLOBALS // GLOBALS
@ -168,12 +170,13 @@ class Dexed
void setFCController(uint8_t fc_range, uint8_t fc_assign); void setFCController(uint8_t fc_range, uint8_t fc_assign);
void setBCController(uint8_t bc_range, uint8_t bc_assign); void setBCController(uint8_t bc_range, uint8_t bc_assign);
void setATController(uint8_t at_range, uint8_t pb_assign); void setATController(uint8_t at_range, uint8_t pb_assign);
void setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissando, uint8_t portamento_time);
ProcessorVoice voices[MAX_NOTES]; ProcessorVoice voices[MAX_NOTES];
Controllers controllers; Controllers controllers;
PluginFx fx; PluginFx fx;
uint8_t data[173] = { uint8_t data[176] = {
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 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
95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 00, 99, 00, 01, 00, 00, // OP5 95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 00, 99, 00, 01, 00, 00, // OP5
95, 29, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 06, 89, 00, 01, 00, 07, // OP4 95, 29, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 06, 89, 00, 01, 00, 07, // OP4
@ -188,10 +191,13 @@ class Dexed
01, 00, 99, 00, 99, 00, 99, 00, 99, 00, // pitch_bend_range, pitch_bend_step, mod_wheel_range, mod_wheel_assign, foot_ctrl_range, foot_ctrl_assign, breath_ctrl_range, breath_ctrl_assign, aftertouch_range, aftertouch_assign 01, 00, 99, 00, 99, 00, 99, 00, 99, 00, // pitch_bend_range, pitch_bend_step, mod_wheel_range, mod_wheel_assign, foot_ctrl_range, foot_ctrl_assign, breath_ctrl_range, breath_ctrl_assign, aftertouch_range, aftertouch_assign
00, // master tune 00, // master tune
01, 01, 01, 01, 01, 01, // OP1-6 enable 01, 01, 01, 01, 01, 01, // OP1-6 enable
00, 00, 00, // portamento_mode, portamento_glissando, portamento_time
MAX_NOTES // number of voices MAX_NOTES // number of voices
}; // FM-Piano }; // FM-Piano
uint32_t overload = 0; uint32_t overload = 0;
int lastKeyDown;
protected: protected:
static const uint8_t MAX_ACTIVE_NOTES = MAX_NOTES; static const uint8_t MAX_ACTIVE_NOTES = MAX_NOTES;
uint8_t max_notes = MAX_ACTIVE_NOTES; uint8_t max_notes = MAX_ACTIVE_NOTES;

@ -19,6 +19,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "synth.h" #include "synth.h"
#include "freqlut.h" #include "freqlut.h"
#include "porta.h"
#include "exp2.h" #include "exp2.h"
#include "controllers.h" #include "controllers.h"
#include "dx7note.h" #include "dx7note.h"
@ -147,7 +148,7 @@ Dx7Note::Dx7Note() {
} }
//void Dx7Note::init(const uint8_t patch[156], int midinote, int velocity) { //void Dx7Note::init(const uint8_t patch[156], int midinote, int velocity) {
void Dx7Note::init(const uint8_t patch[173], int midinote, int velocity) { void Dx7Note::init(const uint8_t patch[173], int midinote, int velocity, int srcnote, int porta) {
int rates[4]; int rates[4];
int levels[4]; int levels[4];
for (int op = 0; op < 6; op++) { for (int op = 0; op < 6; op++) {
@ -176,6 +177,9 @@ void Dx7Note::init(const uint8_t patch[173], int midinote, int velocity) {
opMode[op] = mode; opMode[op] = mode;
basepitch_[op] = freq; basepitch_[op] = freq;
ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3];
if (porta >= 0)
porta_curpitch_[op] = osc_freq(srcnote, mode, coarse, fine, detune);
} }
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
rates[i] = patch[126 + i]; rates[i] = patch[126 + i];
@ -188,6 +192,7 @@ void Dx7Note::init(const uint8_t patch[173], int midinote, int velocity) {
pitchmoddepth_ = (patch[139] * 165) >> 6; pitchmoddepth_ = (patch[139] * 165) >> 6;
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; pitchmodsens_ = pitchmodsenstab[patch[143] & 7];
ampmoddepth_ = (patch[140] * 165) >> 6; ampmoddepth_ = (patch[140] * 165) >> 6;
porta_rateindex_ = (porta < 128) ? porta : 127;
} }
void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Controllers *ctrls) { void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Controllers *ctrls) {
@ -236,10 +241,15 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
} else { } else {
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24))); //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
int32_t basepitch = basepitch_[op];
if ( opMode[op] ) if ( opMode[op] )
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_base); params_[op].freq = Freqlut::lookup(basepitch + pitch_base);
else else {
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_mod); if ( porta_rateindex_ >= 0 )
basepitch = porta_curpitch_[op];
params_[op].freq = Freqlut::lookup(basepitch + pitch_mod);
}
int32_t level = env_[op].getsample(); int32_t level = env_[op].getsample();
if (ampmodsens_[op] != 0) { if (ampmodsens_[op] != 0) {
@ -254,6 +264,25 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
params_[op].level_in = level; params_[op].level_in = level;
} }
} }
// ==== PORTAMENTO ====
int porta = porta_rateindex_;
if ( porta >= 0 ) {
int32_t rate = Porta::rates[porta];
for (int op = 0; op < 6; op++) {
int32_t cur = porta_curpitch_[op];
int32_t dst = basepitch_[op];
bool going_up = cur < dst;
int32_t newpitch = cur + (going_up ? +rate : -rate);
if ( going_up ? (cur > dst) : (cur < dst) )
newpitch = dst;
porta_curpitch_[op] = newpitch;
}
}
ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_); ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_);
} }

@ -1,19 +1,19 @@
/* /*
* Copyright 2016-2017 Pascal Gauthier. Copyright 2016-2017 Pascal Gauthier.
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef SYNTH_DX7NOTE_H_ #ifndef SYNTH_DX7NOTE_H_
#define SYNTH_DX7NOTE_H_ #define SYNTH_DX7NOTE_H_
@ -30,36 +30,36 @@
#include "fm_core.h" #include "fm_core.h"
struct VoiceStatus { struct VoiceStatus {
uint32_t amp[6]; uint32_t amp[6];
char ampStep[6]; char ampStep[6];
char pitchStep; char pitchStep;
}; };
class Dx7Note { class Dx7Note {
public: public:
Dx7Note(); Dx7Note();
void init(const uint8_t patch[156], int midinote, int velocity); void init(const uint8_t patch[156], int midinote, int velocity, int srcnote, int porta);
// Note: this _adds_ to the buffer. Interesting question whether it's // Note: this _adds_ to the buffer. Interesting question whether it's
// worth it... // worth it...
void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay,
const Controllers *ctrls); const Controllers *ctrls);
void keyup(); void keyup();
// TODO: some way of indicating end-of-note. Maybe should be a return // TODO: some way of indicating end-of-note. Maybe should be a return
// value from the compute method? (Having a count return from keyup // value from the compute method? (Having a count return from keyup
// is also tempting, but if there's a dynamic parameter change after // is also tempting, but if there's a dynamic parameter change after
// keyup, that won't work. // keyup, that won't work.
// PG:add the update // PG:add the update
void update(const uint8_t patch[156], int midinote, int velocity); void update(const uint8_t patch[156], int midinote, int velocity);
void peekVoiceStatus(VoiceStatus &status); void peekVoiceStatus(VoiceStatus &status);
void transferState(Dx7Note& src); void transferState(Dx7Note& src);
void transferSignal(Dx7Note &src); void transferSignal(Dx7Note &src);
void oscSync(); void oscSync();
private: private:
Env env_[6]; Env env_[6];
FmOpParams params_[6]; FmOpParams params_[6];
PitchEnv pitchenv_; PitchEnv pitchenv_;
@ -68,11 +68,14 @@ private:
int32_t fb_shift_; int32_t fb_shift_;
int32_t ampmodsens_[6]; int32_t ampmodsens_[6];
int32_t opMode[6]; int32_t opMode[6];
int ampmoddepth_; int ampmoddepth_;
int algorithm_; int algorithm_;
int pitchmoddepth_; int pitchmoddepth_;
int pitchmodsens_; int pitchmodsens_;
int porta_rateindex_;
int32_t porta_curpitch_[6];
}; };
#endif // SYNTH_DX7NOTE_H_ #endif // SYNTH_DX7NOTE_H_

@ -0,0 +1,35 @@
/*
Copyright 2019 Jean Pierre Cimalando.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <math.h>
#include "porta.h"
#include "synth.h"
void Porta::init_sr(double sampleRate)
{
// compute portamento for CC 7-bit range
for (unsigned int i = 0; i < 128; ++i) {
// number of semitones travelled
double sps = 350.0 * pow(2.0, -0.062 * i); // per second
double spf = sps / sampleRate; // per frame
double spp = spf * _N_; // per period
const int step = (1 << 24) / 12;
rates[i] = (int32_t)(0.5f + step * spp); // to pitch units
}
}
int32_t Porta::rates[128];

@ -0,0 +1,28 @@
/*
Copyright 2019 Jean Pierre Cimalando.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef SYNTH_PORTA_H_
#define SYNTH_PORTA_H_
#include <stdint.h>
struct Porta {
public:
static void init_sr(double sampleRate);
static int32_t rates[128];
};
#endif // SYNTH_PORTA_H_
Loading…
Cancel
Save