MiniDexed icon indicating copy to clipboard operation
MiniDexed copied to clipboard

Portamento Mode does not behave like on TX816

Open probonopd opened this issue 6 months ago • 7 comments

@Skerjanc in https://github.com/probonopd/MiniDexed/pull/884#issuecomment-2872484797:

Portamento Memory is implemented wrong: currently it only enables/disables portamento. But on the HW it does the following (only in Monophonic Mode):

  • Off: Portamento is disabled when two notes are played non-legato. Played legato, portamento is enabled
  • On: always portamento

probonopd avatar May 12 '25 16:05 probonopd

What you are describing is the difference between Fingered and Full time porta, not between Portamento on and off. Both available just in Mono mode when Portamento is On (and Glisando is off). In Poly mode, you have Sus-key P Retain and Sus-key P Follow - If you use a Sustain pedal, what should happen with the sustained tone - should it remain on its own frequency, or should it slide to the next pressed key.

BobanSpasic avatar May 12 '25 17:05 BobanSpasic

@Skerjanc, based on the feedback from @BobanSpasic, can you please compare what happens when you change from "Fingered" (default) to "Full time" under TGx -> Portamento -> Mode?

probonopd avatar May 12 '25 18:05 probonopd

Sorry, typo. I meant Portamento Mode, not "Portamento Memory". It is the DX Performance Parameter Change 7 which currently does not switch the mode correctly.

Image

Setting the mode on the DT-DX to Fingered Mode does not work as well. I noticed, that portamento time is reset to 0 each time.

Skerjanc avatar May 14 '25 14:05 Skerjanc

@Skerjanc I understand that the behavior is not correct regardless of whether you use MIDI SysEx or the menu on the DT-DX, right?

Possibly this needs to be addressed in the Synth_Dexed engine along these lines:

void Dexed::keydown(uint8_t pitch, uint8_t velo) {
    if (velo == 0) {
        keyup(pitch);
        return;
    }
    velo = uint8_t((float(velo)/127.0)*velocity_diff+0.5)+velocity_offset;
    pitch += data[144] - TRANSPOSE_FIX;
    int32_t previousKeyDown = lastKeyDown;
    lastKeyDown = pitch;
    int32_t porta = -1;

    if (monoMode) {
        // --- MONO MODE: Only use voices[0] ---
        // Determine portamento mode: 0 = Fingered, 1 = Full Time
        uint8_t portamento_mode = controllers.portamento_enable_cc ? 1 : 0;
        // Count how many notes are currently held (keydown == true)
        int numHeld = 0;
        for (uint8_t i = 0; i < used_notes; ++i) {
            if (voices[i].keydown) numHeld++;
        }
        if (portamento_mode == 0) { // Fingered: only legato
            // Only enable portamento if another note is held (legato)
            if (numHeld > 0) {
                porta = controllers.portamento_cc;
            } else {
                porta = -1;
            }
        } else { // Full Time: always portamento
            porta = controllers.portamento_cc;
        }

        // Always use voices[0] for mono
        ProcessorVoice& v = voices[0];
        bool retrigger = !v.keydown; // retrigger envelope if not legato
        v.midi_note = pitch;
        v.velocity = velo;
        v.sustained = sustain;
        v.sostenuted = false;
        v.held = hold;
        v.keydown = true;
        v.live = true;
        v.key_pressed_timer = millis();
        int32_t srcnote = (previousKeyDown >= 0) ? previousKeyDown : pitch;
        if (retrigger) {
            lfo.keydown();
            v.dx7_note->init(data, pitch, velo, srcnote, porta, &controllers);
            if (data[136]) v.dx7_note->oscSync();
        } else {
            // Legato: update pitch/velocity, but do not retrigger envelope
            v.dx7_note->update(data, pitch, velo, porta, &controllers);
        }
        // Release all other voices
        for (uint8_t i = 1; i < used_notes; ++i) {
            voices[i].keydown = false;
            voices[i].live = false;
            voices[i].sustained = false;
            voices[i].sostenuted = false;
            voices[i].held = false;
            voices[i].key_pressed_timer = 0;
        }
        return;
    }

    velo=uint8_t((float(velo)/127.0)*velocity_diff+0.5)+velocity_offset;

    pitch += data[144] - TRANSPOSE_FIX;

    uint8_t note = currentNote;
    uint8_t keydown_counter = 0;

    if (!monoMode && noteRefreshMode)
    {
      for (uint8_t i = 0; i < used_notes; i++)
      {
        if (voices[i].midi_note == pitch && voices[i].keydown == false && voices[i].live &&
           (voices[i].sustained == true || voices[i].held == true))
        {
          // retrigger or refresh note?
          voices[i].dx7_note->keyup();
          voices[i].midi_note = pitch;
          voices[i].velocity = velo;
          voices[i].keydown = true;
          voices[i].sustained = sustain;
          voices[i].held = hold;
          voices[i].live = true;
          voices[i].dx7_note->init(data, pitch, velo, pitch, porta, &controllers);
          voices[i].key_pressed_timer = millis();
          return;
        }
      }
    }

@dcoredump what do you think?

probonopd avatar May 14 '25 21:05 probonopd

I have to get my DX7 back from studio to check and compare this. I will try after I am back from holidays.

In meantime, perhaps someone can create a PR?

dcoredump avatar May 15 '25 06:05 dcoredump

I don't think the patch is 100% correct yet. Unfortunately I have no DX7 to compare with.

probonopd avatar May 15 '25 16:05 probonopd

@Skerjanc I understand that the behavior is not correct regardless of whether you use MIDI SysEx or the menu on the DT-DX, right?

Yes. Please don't get me wrong, when I say the portamento time is reset to 0. I mean the parameter Portamento Time becomes 0, (thus the portamento effect vanishes) when setting fingered mode.

Skerjanc avatar May 15 '25 17:05 Skerjanc