From 4e171df081333eac24fe2c6f29fcf64b35be97d0 Mon Sep 17 00:00:00 2001 From: probonopd Date: Wed, 23 Apr 2025 20:21:19 +0200 Subject: [PATCH 01/14] Handle TX216/TX816 style performance sysex messages --- src/mididevice.cpp | 191 ++++++++++++++++++++++++++++----------------- 1 file changed, 120 insertions(+), 71 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 7d3b4a0..55d51bc 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -133,17 +133,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if ( pMessage[0] != MIDI_TIMING_CLOCK && pMessage[0] != MIDI_ACTIVE_SENSING) { - fprintf (stderr, "MIDI%u: %02X\n", nCable, (unsigned) pMessage[0]); + LOGNOTE("MIDI%u: %02X", nCable, (unsigned) pMessage[0]); } break; case 2: - fprintf (stderr, "MIDI%u: %02X %02X\n", nCable, + LOGNOTE("MIDI%u: %02X %02X", nCable, (unsigned) pMessage[0], (unsigned) pMessage[1]); break; case 3: - fprintf (stderr, "MIDI%u: %02X %02X %02X\n", nCable, + LOGNOTE("MIDI%u: %02X %02X %02X", nCable, (unsigned) pMessage[0], (unsigned) pMessage[1], (unsigned) pMessage[2]); break; @@ -152,17 +152,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign switch(pMessage[0]) { case MIDI_SYSTEM_EXCLUSIVE_BEGIN: - fprintf(stderr, "MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength)); + LOGNOTE("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength)); for (uint16_t i = 0; i < nLength; i++) { if((i % 16) == 0) - fprintf(stderr, "\n%04d:",i); - fprintf(stderr, " 0x%02x",pMessage[i]); + LOGNOTE("%04d:",i); + LOGNOTE(" 0x%02x",pMessage[i]); } - fprintf(stderr, "\n"); + LOGNOTE(""); break; default: - fprintf(stderr, "MIDI%u: Unhandled MIDI event type %0x02x\n",nCable,pMessage[0]); + LOGNOTE("MIDI%u: Unhandled MIDI event type %0x02x",nCable,pMessage[0]); } break; } @@ -323,7 +323,109 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode) { LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG); - HandleSystemExclusive(pMessage, nLength, nCable, nTG); + + // Check for TX216/TX816 style performance sysex messages + + if (pMessage[3] == 0x04) + { + // TX816/TX216 Performance SysEx message + uint8_t mTG = pMessage[2] & 0x0F; // mTG = module/tone generator number (0-7) + uint8_t par = pMessage[4]; + uint8_t val = pMessage[5]; + + if (nTG != mTG) continue; + + LOGNOTE("MIDI-SYSEX: Assuming TX216/TX816 style performance sysex message because 4th byte is 0x04"); + + switch (par) + { + case 1: // MIDI Channel + LOGNOTE("MIDI-SYSEX: Set MIDI Channel %d to %d", mTG, val & 0x0F); + m_pSynthesizer->SetMIDIChannel(val & 0x0F, mTG); + break; + case 2: // Poly/Mono + LOGNOTE("MIDI-SYSEX: Set Poly/Mono %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setMonoMode(val ? true : false, mTG); + break; + case 3: // Pitch Bend Range + LOGNOTE("MIDI-SYSEX: Set Pitch Bend Range %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setPitchbendRange(val, mTG); + break; + case 4: // Pitch Bend Step + LOGNOTE("MIDI-SYSEX: Set Pitch Bend Step %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setPitchbendStep(val, mTG); + break; + case 5: // Portamento Time + LOGNOTE("MIDI-SYSEX: Set Portamento Time %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setPortamentoTime(val, mTG); + break; + case 6: // Portamento/Glissando + LOGNOTE("MIDI-SYSEX: Set Portamento/Glissando %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setPortamentoGlissando(val, mTG); + break; + case 7: // Portamento Mode + LOGNOTE("MIDI-SYSEX: Set Portamento Mode %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setPortamentoMode(val, mTG); + break; + case 9: // Mod Wheel Sensitivity + LOGNOTE("MIDI-SYSEX: Set Mod Wheel Sensitivity %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setModWheelRange(val, mTG); + break; + case 10: // Mod Wheel Assign + LOGNOTE("MIDI-SYSEX: Set Mod Wheel Assign %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setModWheelTarget(val, mTG); + break; + case 11: // Foot Controller Sensitivity + LOGNOTE("MIDI-SYSEX: Set Foot Controller Sensitivity %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setFootControllerRange(val, mTG); + break; + case 12: // Foot Controller Assign + LOGNOTE("MIDI-SYSEX: Set Foot Controller Assign %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setFootControllerTarget(val, mTG); + break; + case 13: // Aftertouch Sensitivity + LOGNOTE("MIDI-SYSEX: Set Aftertouch Sensitivity %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setAftertouchRange(val, mTG); + break; + case 14: // Aftertouch Assign + LOGNOTE("MIDI-SYSEX: Set Aftertouch Assign %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setAftertouchTarget(val, mTG); + break; + case 15: // Breath Controller Sensitivity + LOGNOTE("MIDI-SYSEX: Set Breath Controller Sensitivity %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setBreathControllerRange(val, mTG); + break; + case 16: // Breath Controller Assign + LOGNOTE("MIDI-SYSEX: Set Breath Controller Assign %d to %d", mTG, val & 0x0F); + m_pSynthesizer->setBreathControllerTarget(val, mTG); + break; + case 26: // Audio Output Level Attenuator (if supported) + LOGNOTE("MIDI-SYSEX: TODO: Set Audio Output Level Attenuator %d to %d", mTG, val & 0x0F); + // m_pSynthesizer->setOutputAttenuator(val, mTG); // Uncomment if implemented + break; + case 64: // Master Tuning + LOGNOTE("MIDI-SYSEX: Set Master Tuning"); + if (val == 0) + { + // 0 to 127, with 0 being no detune effect applied at all + m_pSynthesizer->SetMasterTune(0, mTG); + } + else + { + // Scale to -99 to +99 cents + m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -99, 99), mTG); + } + break; + default: + // Unknown or unsupported parameter + LOGNOTE("MIDI-SYSEX: Unknown parameter %d for TG %d", par, mTG); + break; + } + } + else + { + HandleSystemExclusive(pMessage, nLength, nCable, nTG); + } } } else @@ -421,19 +523,19 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case MIDI_CC_BANK_SUSTAIN: m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); break; - + /* case MIDI_CC_SOSTENUTO: m_pSynthesizer->setSostenuto (pMessage[2] >= 64, nTG); break; - + */ case MIDI_CC_PORTAMENTO: m_pSynthesizer->setPortamentoMode (pMessage[2] >= 64, nTG); break; - + /* case MIDI_CC_HOLD2: m_pSynthesizer->setHoldMode (pMessage[2] >= 64, nTG); break; - + */ case MIDI_CC_RESONANCE: m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG); break; @@ -449,11 +551,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case MIDI_CC_DETUNE_LEVEL: if (pMessage[2] == 0) { - // "0 to 127, with 0 being no celeste (detune) effect applied at all." + // 0 to 127, with 0 being no detune effect applied at all m_pSynthesizer->SetMasterTune (0, nTG); } else { + // Scale to -99 to +99 cents m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG); } break; @@ -559,10 +662,12 @@ bool CMIDIDevice::HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval) if (ucCC == MIDISystemCCMap[m_nMIDISystemCCDetune][tg]) { if (ucCCval == 0) { + // 0 to 127, with 0 being no detune effect applied at all m_pSynthesizer->SetMasterTune (0, tg); } else { + // Scale to -99 to +99 cents m_pSynthesizer->SetMasterTune (maplong (ucCCval, 1, 127, -99, 99), tg); } return true; @@ -614,62 +719,6 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL case -11: LOGERR("Unknown SysEx message."); break; - case 64: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setMonoMode(pMessage[5],nTG); - break; - case 65: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setPitchbendRange(pMessage[5],nTG); - break; - case 66: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setPitchbendStep(pMessage[5],nTG); - break; - case 67: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setPortamentoMode(pMessage[5],nTG); - break; - case 68: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setPortamentoGlissando(pMessage[5],nTG); - break; - case 69: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setPortamentoTime(pMessage[5],nTG); - break; - case 70: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setModWheelRange(pMessage[5],nTG); - break; - case 71: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setModWheelTarget(pMessage[5],nTG); - break; - case 72: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setFootControllerRange(pMessage[5],nTG); - break; - case 73: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setFootControllerTarget(pMessage[5],nTG); - break; - case 74: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setBreathControllerRange(pMessage[5],nTG); - break; - case 75: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setBreathControllerTarget(pMessage[5],nTG); - break; - case 76: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setAftertouchRange(pMessage[5],nTG); - break; - case 77: - LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); - m_pSynthesizer->setAftertouchTarget(pMessage[5],nTG); - break; case 100: // load sysex-data into voice memory LOGDBG("One Voice bulk upload"); @@ -716,4 +765,4 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t)); // LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str()); } -} +} From e55f23600d8daf463794fc7bcbb46ad451ab2205 Mon Sep 17 00:00:00 2001 From: probonopd Date: Wed, 23 Apr 2025 21:06:24 +0200 Subject: [PATCH 02/14] Do not comment out Sostenuto and Hold2 --- src/mididevice.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 55d51bc..55743b1 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -523,19 +523,19 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case MIDI_CC_BANK_SUSTAIN: m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); break; - /* + case MIDI_CC_SOSTENUTO: m_pSynthesizer->setSostenuto (pMessage[2] >= 64, nTG); break; - */ + case MIDI_CC_PORTAMENTO: m_pSynthesizer->setPortamentoMode (pMessage[2] >= 64, nTG); break; - /* + case MIDI_CC_HOLD2: m_pSynthesizer->setHoldMode (pMessage[2] >= 64, nTG); break; - */ + case MIDI_CC_RESONANCE: m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG); break; From 1b4bb7b320fda1886a01419bd2d05f8d3400ae43 Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 24 Apr 2025 23:42:33 +0200 Subject: [PATCH 03/14] Update mididevice.cpp Adjust Detune TX816 goes +/-75 cent and the value 0 tuning should not jump back to 64 according to @Skerjanc --- src/mididevice.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 6a621ab..22bcc45 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -411,16 +411,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); - if (val == 0) - { - // 0 to 127, with 0 being no detune effect applied at all - m_pSynthesizer->SetMasterTune(0, mTG); - } - else - { - // Scale to -99 to +99 cents - m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -99, 99), mTG); - } + + // Scale to -75 to +75 cents (TX816 range) + m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -75, 75), mTG); + break; default: // Unknown or unsupported parameter From c08ae55ee91ae319f06178bf696f1b6d618173b1 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 26 Apr 2025 00:49:34 +0200 Subject: [PATCH 04/14] Change interpretation of byte 3 Only process Set MIDI Channel for the TG with the number in byte 3, for other messages process the TG listening on the MIDI channel in byte 3 --- src/mididevice.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 22bcc45..5ad9d45 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -339,14 +339,24 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign uint8_t par = pMessage[4]; uint8_t val = pMessage[5]; - if (nTG != mTG) continue; - + // For all parameters except "Set MIDI Channel", only process for the TG matching the MIDI channel. + // For "Set MIDI Channel" message, apply that to the TG with the number in pMessage[2], + // NOT to the TG that is set to the MIDI channel in pMessage[2]. + // This may not entirely be true to the TX216/TX816, but it is more suitable for MiniDexed. + if (par != 1 && nTG != mTG) continue; + if (par == 1) { + // Only process Set MIDI Channel for the TG with the number in pMessage[2] + if (nTG != mTG) continue; + } else { + // For all other parameters, only process for the TG matching the MIDI channel + if (!(m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)) continue; + } LOGNOTE("MIDI-SYSEX: Assuming TX216/TX816 style performance sysex message because 4th byte is 0x04"); switch (par) { case 1: // MIDI Channel - LOGNOTE("MIDI-SYSEX: Set MIDI Channel %d to %d", mTG, val & 0x0F); + LOGNOTE("MIDI-SYSEX: Set TG%d to MIDI Channel %d", mTG, val & 0x0F); m_pSynthesizer->SetMIDIChannel(val & 0x0F, mTG); break; case 2: // Poly/Mono From db1fcab8cd704320ce6e0829cf2ed5b598647b03 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 26 Apr 2025 00:57:04 +0200 Subject: [PATCH 05/14] Try to fix the logic --- src/mididevice.cpp | 77 +++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 5ad9d45..d12c4ec 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -339,17 +339,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign uint8_t par = pMessage[4]; uint8_t val = pMessage[5]; - // For all parameters except "Set MIDI Channel", only process for the TG matching the MIDI channel. - // For "Set MIDI Channel" message, apply that to the TG with the number in pMessage[2], - // NOT to the TG that is set to the MIDI channel in pMessage[2]. - // This may not entirely be true to the TX216/TX816, but it is more suitable for MiniDexed. - if (par != 1 && nTG != mTG) continue; + // For parameter 1 (Set MIDI Channel), only process for the TG with the number in pMessage[2] if (par == 1) { - // Only process Set MIDI Channel for the TG with the number in pMessage[2] if (nTG != mTG) continue; } else { - // For all other parameters, only process for the TG matching the MIDI channel - if (!(m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)) continue; + // For all other parameters, process for all TGs listening on the MIDI channel mTG or OmniMode + if (!(m_ChannelMap[nTG] == mTG || m_ChannelMap[nTG] == OmniMode)) continue; } LOGNOTE("MIDI-SYSEX: Assuming TX216/TX816 style performance sysex message because 4th byte is 0x04"); @@ -360,75 +355,73 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_pSynthesizer->SetMIDIChannel(val & 0x0F, mTG); break; case 2: // Poly/Mono - LOGNOTE("MIDI-SYSEX: Set Poly/Mono %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setMonoMode(val ? true : false, mTG); + LOGNOTE("MIDI-SYSEX: Set Poly/Mono %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setMonoMode(val ? true : false, nTG); break; case 3: // Pitch Bend Range - LOGNOTE("MIDI-SYSEX: Set Pitch Bend Range %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setPitchbendRange(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Pitch Bend Range %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setPitchbendRange(val, nTG); break; case 4: // Pitch Bend Step - LOGNOTE("MIDI-SYSEX: Set Pitch Bend Step %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setPitchbendStep(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Pitch Bend Step %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setPitchbendStep(val, nTG); break; case 5: // Portamento Time - LOGNOTE("MIDI-SYSEX: Set Portamento Time %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setPortamentoTime(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Portamento Time %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setPortamentoTime(val, nTG); break; case 6: // Portamento/Glissando - LOGNOTE("MIDI-SYSEX: Set Portamento/Glissando %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setPortamentoGlissando(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Portamento/Glissando %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setPortamentoGlissando(val, nTG); break; case 7: // Portamento Mode - LOGNOTE("MIDI-SYSEX: Set Portamento Mode %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setPortamentoMode(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Portamento Mode %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setPortamentoMode(val, nTG); break; case 9: // Mod Wheel Sensitivity - LOGNOTE("MIDI-SYSEX: Set Mod Wheel Sensitivity %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setModWheelRange(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Mod Wheel Sensitivity %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setModWheelRange(val, nTG); break; case 10: // Mod Wheel Assign - LOGNOTE("MIDI-SYSEX: Set Mod Wheel Assign %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setModWheelTarget(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Mod Wheel Assign %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setModWheelTarget(val, nTG); break; case 11: // Foot Controller Sensitivity - LOGNOTE("MIDI-SYSEX: Set Foot Controller Sensitivity %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setFootControllerRange(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Foot Controller Sensitivity %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setFootControllerRange(val, nTG); break; case 12: // Foot Controller Assign - LOGNOTE("MIDI-SYSEX: Set Foot Controller Assign %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setFootControllerTarget(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Foot Controller Assign %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setFootControllerTarget(val, nTG); break; case 13: // Aftertouch Sensitivity - LOGNOTE("MIDI-SYSEX: Set Aftertouch Sensitivity %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setAftertouchRange(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Aftertouch Sensitivity %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setAftertouchRange(val, nTG); break; case 14: // Aftertouch Assign - LOGNOTE("MIDI-SYSEX: Set Aftertouch Assign %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setAftertouchTarget(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Aftertouch Assign %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setAftertouchTarget(val, nTG); break; case 15: // Breath Controller Sensitivity - LOGNOTE("MIDI-SYSEX: Set Breath Controller Sensitivity %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setBreathControllerRange(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Breath Controller Sensitivity %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setBreathControllerRange(val, nTG); break; case 16: // Breath Controller Assign - LOGNOTE("MIDI-SYSEX: Set Breath Controller Assign %d to %d", mTG, val & 0x0F); - m_pSynthesizer->setBreathControllerTarget(val, mTG); + LOGNOTE("MIDI-SYSEX: Set Breath Controller Assign %d to %d", nTG, val & 0x0F); + m_pSynthesizer->setBreathControllerTarget(val, nTG); break; case 26: // Audio Output Level Attenuator (if supported) - LOGNOTE("MIDI-SYSEX: TODO: Set Audio Output Level Attenuator %d to %d", mTG, val & 0x0F); - // m_pSynthesizer->setOutputAttenuator(val, mTG); // Uncomment if implemented + LOGNOTE("MIDI-SYSEX: TODO: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); + // m_pSynthesizer->setOutputAttenuator(val, nTG); // Uncomment if implemented break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); - // Scale to -75 to +75 cents (TX816 range) - m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -75, 75), mTG); - + m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -75, 75), nTG); break; default: // Unknown or unsupported parameter - LOGNOTE("MIDI-SYSEX: Unknown parameter %d for TG %d", par, mTG); + LOGNOTE("MIDI-SYSEX: Unknown parameter %d for TG %d", par, nTG); break; } } From da2410b68f2020ebea3a883c9896235182a482a2 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 26 Apr 2025 01:06:46 +0200 Subject: [PATCH 06/14] Scale sensitivity values from 0-15 to 0-99 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TX216/TX816 style performance SysEx messages send Sensitivity parameters (such as Mod Wheel Sensitivity, Foot Controller Sensitivity, Aftertouch Sensitivity, Breath Controller Sensitivity) in the range 0–15, but the DX7 and the Synth_Dexed engine might expect these values in the range 0–99 (or not?) --- src/mididevice.cpp | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index d12c4ec..c523135 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -379,33 +379,45 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_pSynthesizer->setPortamentoMode(val, nTG); break; case 9: // Mod Wheel Sensitivity - LOGNOTE("MIDI-SYSEX: Set Mod Wheel Sensitivity %d to %d", nTG, val & 0x0F); - m_pSynthesizer->setModWheelRange(val, nTG); - break; + { + int scaled = (val * 99) / 15; + LOGNOTE("MIDI-SYSEX: Set Mod Wheel Sensitivity %d to %d (scaled %d)", nTG, val & 0x0F, scaled); + m_pSynthesizer->setModWheelRange(scaled, nTG); + } + break; case 10: // Mod Wheel Assign LOGNOTE("MIDI-SYSEX: Set Mod Wheel Assign %d to %d", nTG, val & 0x0F); m_pSynthesizer->setModWheelTarget(val, nTG); break; case 11: // Foot Controller Sensitivity - LOGNOTE("MIDI-SYSEX: Set Foot Controller Sensitivity %d to %d", nTG, val & 0x0F); - m_pSynthesizer->setFootControllerRange(val, nTG); - break; + { + int scaled = (val * 99) / 15; + LOGNOTE("MIDI-SYSEX: Set Foot Controller Sensitivity %d to %d (scaled %d)", nTG, val & 0x0F, scaled); + m_pSynthesizer->setFootControllerRange(scaled, nTG); + } + break; case 12: // Foot Controller Assign LOGNOTE("MIDI-SYSEX: Set Foot Controller Assign %d to %d", nTG, val & 0x0F); m_pSynthesizer->setFootControllerTarget(val, nTG); break; case 13: // Aftertouch Sensitivity - LOGNOTE("MIDI-SYSEX: Set Aftertouch Sensitivity %d to %d", nTG, val & 0x0F); - m_pSynthesizer->setAftertouchRange(val, nTG); - break; + { + int scaled = (val * 99) / 15; + LOGNOTE("MIDI-SYSEX: Set Aftertouch Sensitivity %d to %d (scaled %d)", nTG, val & 0x0F, scaled); + m_pSynthesizer->setAftertouchRange(scaled, nTG); + } + break; case 14: // Aftertouch Assign LOGNOTE("MIDI-SYSEX: Set Aftertouch Assign %d to %d", nTG, val & 0x0F); m_pSynthesizer->setAftertouchTarget(val, nTG); break; case 15: // Breath Controller Sensitivity - LOGNOTE("MIDI-SYSEX: Set Breath Controller Sensitivity %d to %d", nTG, val & 0x0F); - m_pSynthesizer->setBreathControllerRange(val, nTG); - break; + { + int scaled = (val * 99) / 15; + LOGNOTE("MIDI-SYSEX: Set Breath Controller Sensitivity %d to %d (scaled %d)", nTG, val & 0x0F, scaled); + m_pSynthesizer->setBreathControllerRange(scaled, nTG); + } + break; case 16: // Breath Controller Assign LOGNOTE("MIDI-SYSEX: Set Breath Controller Assign %d to %d", nTG, val & 0x0F); m_pSynthesizer->setBreathControllerTarget(val, nTG); From 72514e9261cac42123ebadfdad7f5740a2f9b8e4 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sun, 27 Apr 2025 14:07:59 +0200 Subject: [PATCH 07/14] Audio Output Level Attenuator; change Master Tuning range --- src/mididevice.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index c523135..afc35a3 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -422,14 +422,15 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign LOGNOTE("MIDI-SYSEX: Set Breath Controller Assign %d to %d", nTG, val & 0x0F); m_pSynthesizer->setBreathControllerTarget(val, nTG); break; - case 26: // Audio Output Level Attenuator (if supported) - LOGNOTE("MIDI-SYSEX: TODO: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); - // m_pSynthesizer->setOutputAttenuator(val, nTG); // Uncomment if implemented + case 26: // Audio Output Level Attenuator + LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); + // Set Master volume (0-99) for the TG. Scale from 0-7 to what Synth_Dexed uses (0-99) + m_pSynthesizer->SetMasterVolume(maplong(val, 0, 7, 0, 1), nTG); break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); - // Scale to -75 to +75 cents (TX816 range) - m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -75, 75), nTG); + // TX812 scales from -75 to +75 cents. + m_pSynthesizer->SetMasterTune(maplong(val, 1, 127, -37, 37), nTG); // Would need 37.5 here, due to wrong constrain on dexed_synth module? break; default: // Unknown or unsupported parameter From f94edb32d3e1340468a1f1d211e16dad2c41ab14 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sun, 27 Apr 2025 14:52:55 +0200 Subject: [PATCH 08/14] setMasterVolume --- src/mididevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index afc35a3..5b54bb7 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -425,7 +425,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case 26: // Audio Output Level Attenuator LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Set Master volume (0-99) for the TG. Scale from 0-7 to what Synth_Dexed uses (0-99) - m_pSynthesizer->SetMasterVolume(maplong(val, 0, 7, 0, 1), nTG); + m_pSynthesizer->setMasterVolume(maplong(val, 0, 7, 0, 1), nTG); break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); From 734f4a2ad370835594fea404919faf781f420539 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sun, 27 Apr 2025 15:07:59 +0200 Subject: [PATCH 09/14] setMasterVolume is global for all TGs --- src/mididevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 5b54bb7..921e1c4 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -425,7 +425,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case 26: // Audio Output Level Attenuator LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Set Master volume (0-99) for the TG. Scale from 0-7 to what Synth_Dexed uses (0-99) - m_pSynthesizer->setMasterVolume(maplong(val, 0, 7, 0, 1), nTG); + m_pSynthesizer->setMasterVolume(maplong(val, 0, 7, 0, 1)); break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); From b82fb73000560d744168ad288cc52011dd3e35db Mon Sep 17 00:00:00 2001 From: probonopd Date: Mon, 28 Apr 2025 18:58:48 +0200 Subject: [PATCH 10/14] Fix Audio Output Level Attenuator Example for TG1: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 --- src/mididevice.cpp | 9 ++++++--- src/uimenu.cpp | 35 +++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 921e1c4..c19c320 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -423,9 +423,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_pSynthesizer->setBreathControllerTarget(val, nTG); break; case 26: // Audio Output Level Attenuator - LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); - // Set Master volume (0-99) for the TG. Scale from 0-7 to what Synth_Dexed uses (0-99) - m_pSynthesizer->setMasterVolume(maplong(val, 0, 7, 0, 1)); + { + LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); + // Example: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 + unsigned newVolume = (unsigned)((val & 0x07) * 127 / 7); + m_pSynthesizer->SetVolume(newVolume, nTG); + } break; case 64: // Master Tuning LOGNOTE("MIDI-SYSEX: Set Master Tuning"); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index dabea87..6c20ed9 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1098,12 +1098,14 @@ string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue) string CUIMenu::ToVolume (int nValue) { - static const size_t MaxChars = CConfig::LCDColumns-2; - char VolumeBar[MaxChars+1]; - memset (VolumeBar, 0xFF, sizeof VolumeBar); // 0xFF is the block character - VolumeBar[nValue * MaxChars / 127] = '\0'; - - return VolumeBar; + constexpr size_t NumSquares = 14; + char VolumeBar[NumSquares + 1]; + size_t filled = (nValue * NumSquares + 63) / 127; + for (size_t i = 0; i < NumSquares; ++i) { + VolumeBar[i] = (i < filled) ? (char)0xFF : '.'; + } + VolumeBar[NumSquares] = '\0'; + return VolumeBar; } string CUIMenu::ToPan (int nValue) @@ -1394,11 +1396,11 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) || voiceName == "----------" || voiceName == "~~~~~~~~~~" ) { - if (Event == MenuEventPgmUp) { - PgmUpDownHandler (MenuEventPgmUp); + if (Event == MenuEventStepUp) { + PgmUpDownHandler (MenuEventStepUp); } - if (Event == MenuEventPgmDown) { - PgmUpDownHandler (MenuEventPgmDown); + if (Event == MenuEventStepDown) { + PgmUpDownHandler (MenuEventStepDown); } } } @@ -2041,6 +2043,15 @@ void CUIMenu::EditMasterVolume(CUIMenu *pUIMenu, TMenuEvent Event) default: return; } - std::string valueStr = ToVolume(pUIMenu->m_pMiniDexed->GetMasterVolume127()); - pUIMenu->m_pUI->DisplayWrite("Master Volume", "", valueStr.c_str(), nValue > rParam.Minimum, nValue < rParam.Maximum); + unsigned lcdCols = pUIMenu->m_pConfig->GetLCDColumns(); + unsigned barLen = (lcdCols > 2) ? lcdCols - 2 : 0; + std::string valueStr(barLen, '.'); + if (barLen > 0) { + size_t filled = (nValue * barLen + 63) / 127; + for (unsigned i = 0; i < barLen; ++i) { + if (i < filled) valueStr[i] = (char)0xFF; + } + } + // Do NOT add < or > here; let DisplayWrite handle it + pUIMenu->m_pUI->DisplayWrite("Master Volume", "", valueStr.c_str(), true, true); } From 8f8db87ba78bf85cf4455cad8fbcee2250509a48 Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 1 May 2025 07:29:12 +0200 Subject: [PATCH 11/14] Logarithmic mapping for Audio Output Level Attenuator --- src/mididevice.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 56c7500..58209d9 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -426,7 +426,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Example: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 - unsigned newVolume = (unsigned)((val & 0x07) * 127 / 7); + // Apply logarithmic scaling for volume + unsigned attenVal = val & 0x07; + unsigned newVolume = (unsigned)(127.0 * pow(attenVal / 7.0, 2.0) + 0.5); // Logarithmic mapping m_pSynthesizer->SetVolume(newVolume, nTG); } break; From af2c8dcee22c4f0394635600e0a95971e3f20faa Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 1 May 2025 07:43:08 +0200 Subject: [PATCH 12/14] Exponential mapping like on the TX816: 7=127, 6=63, 5=31, ... 0=0 --- src/mididevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 58209d9..9e93e8c 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -426,9 +426,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Example: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 - // Apply logarithmic scaling for volume + // Exponential mapping like on the TX816: 7=127, 6=63, 5=31, ... 0=0 unsigned attenVal = val & 0x07; - unsigned newVolume = (unsigned)(127.0 * pow(attenVal / 7.0, 2.0) + 0.5); // Logarithmic mapping + unsigned newVolume = (attenVal == 0) ? 0 : (127 >> (7 - attenVal)); m_pSynthesizer->SetVolume(newVolume, nTG); } break; From 66eb4481aeb9d4bc32058489c29aa8afacdaa623 Mon Sep 17 00:00:00 2001 From: probonopd Date: Thu, 1 May 2025 07:59:54 +0200 Subject: [PATCH 13/14] Logarithmic mapping for volume --- src/mididevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 9e93e8c..a9d81e0 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -426,9 +426,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Example: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 - // Exponential mapping like on the TX816: 7=127, 6=63, 5=31, ... 0=0 + // Logarithmic mapping for volume unsigned attenVal = val & 0x07; - unsigned newVolume = (attenVal == 0) ? 0 : (127 >> (7 - attenVal)); + unsigned newVolume = (unsigned)(127.0 * pow(attenVal / 7.0, 2.0) + 0.5); m_pSynthesizer->SetVolume(newVolume, nTG); } break; From b5072e93c6a0f86a88f538b575efbbe8655f56f9 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sun, 4 May 2025 08:34:12 +0200 Subject: [PATCH 14/14] Exponential with 0 same volume as 1 --- src/mididevice.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index a9d81e0..f387dbc 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -426,9 +426,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { LOGNOTE("MIDI-SYSEX: Set Audio Output Level Attenuator %d to %d", nTG, val & 0x0F); // Example: F0 43 10 04 1A 00 F7 to F0 43 10 04 1A 07 F7 - // Logarithmic mapping for volume unsigned attenVal = val & 0x07; - unsigned newVolume = (unsigned)(127.0 * pow(attenVal / 7.0, 2.0) + 0.5); + // unsigned newVolume = (unsigned)(127.0 * pow(attenVal / 7.0, 2.0) + 0.5); // Logarithmic mapping + // But on the T816, there is an exponential (not logarithmic!) mapping, and 0 results in the same volume as 1: + // 7=127, 6=63, 5=31, 4=15, 3=7, 2=3, 1=1, 0=1 + unsigned newVolume = (attenVal == 0) ? 0 : (127 >> (7 - attenVal)); + if (newVolume == 0) newVolume = 1; // 0 is like 1 to avoid silence m_pSynthesizer->SetVolume(newVolume, nTG); } break;