diff --git a/Synth_Dexed b/Synth_Dexed index 8c677ce..c9f5274 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit 8c677ceb4b3fb73f8643e30ff6cf4158dc8b9e53 +Subproject commit c9f52741a802ad9bb01263823650f7cc3b0b5108 diff --git a/circle-stdlib b/circle-stdlib index 61cf3a4..1111eee 160000 --- a/circle-stdlib +++ b/circle-stdlib @@ -1 +1 @@ -Subproject commit 61cf3a47bf93628039078b7c840e44432e52343e +Subproject commit 1111eeedb2e2184d234c864947c8a95d68e32ee5 diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 95427f1..bb8d700 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,108 +323,166 @@ 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); +/* +TX216/TX816 + +Format for TX816/TX216 style performance SysEx messages: + +| Byte | Value | Description | +|------|-------|----------------------------------------------------------| +| 0 | F0 | SysEx start | +| 1 | 43 | Yamaha manufacturer ID | +| 2 | 10 | Channel number (0x10 = ch 1, 0x11 = ch 2, etc.) | +| 3 | 04 | Group (0x04 = performance parameter change) | +| 4 | p | Parameter number (see table below) | +| 5 | val | Value for parameter | +| 6 | F7 | SysEx end | + +| p | Parameter | val | Notes | +|----|-------------------------------|-------|-------------------------------------------------| +| 0 | | | | +| 1 | Source Select | 1–16 | Selects MIDI receive channel 1 to 16 | +| 2 | Poly/Mono | 0–1 | | +| 3 | Pitch Bend Range | 0–12 | | +| 4 | Pitch Bend Step | 0–12 | | +| 5 | Portamento Time | 0–99 | | +| 6 | Portamento/Glissando | 0–1 | | +| 7 | Portamento Mode | 0–1 | Sustain-key pitch 0: retain, 1: follow | +| 8 | | | | +| 9 | Modulation Wheel Sensitivity | 0–15 | | +| 10 | Modulation Wheel Assign | 0–7 | Bit 0: Pitch, bit 1: Amplitude, bit 2: EG bias | +| 11 | Foot Controller Sensitivity | 0–15 | | +| 12 | Foot Controller Assign | 0–7 | Bit 0: Pitch, bit 1: Amplitude, bit 2: EG bias | +| 13 | After Touch Sensitivity | 0–15 | | +| 14 | After Touch Assign | 0–7 | Bit 0: Pitch, bit 1: Amplitude, bit 2: EG bias | +| 15 | Breath Controller Sensitivity | 0–15 | | +| 16 | Breath Controller Assign | 0–7 | Bit 0: Pitch, bit 1: Amplitude, bit 2: EG bias | +| | | | | +| 26 | Audio Output Level Attenuator | 0–7 | | +| | | | | +| 64 | Master Tuning | 0–127 | Concert Pitch at 64 | + +Examples: + + Portamento Time = 0 and 2, MIDI Ch = 1 for Tone Generator 1 (TG1): + f0 43 10 04 05 00 f7 --> p=5, val=0 + f0 43 10 04 05 02 f7 --> p=5, val=2 + + Detune first 4 TGs differently:GetChannel + f0 43 10 04 40 2f f7 --> p=64, val=47 + f0 43 11 04 40 37 f7 --> p=64, val=55 + f0 43 12 04 40 40 f7 --> p=64, val=64 # Concert Pitch + f0 43 13 04 40 48 f7 --> p=64, val=72 + + Set TG4 to Poly and Mono (tested, works) + f0 43 13 04 02 00 f7 --> p=2, val=0 + f0 43 13 04 02 01 f7 --> p=2, val=1 + + ModWheel Sensitivity for TG4: + f0 43 13 04 09 01 f7 --> p=9, val=1 - /* - * Recognize TX216/TX816 style performance sysex messages - * such as, but not limited to, the following. - * Performance data are using group=1 (2 bits shifted, thus 0x04) - * in the 4th byte of the sysex message - - Portamento Time = 0 and 2, MIDI Ch = 1: - out: f0 43 10 04 05 00 f7 - out: f0 43 10 04 05 02 f7 - - Detune first 4 modules, Ch 1..4 (32h is 440 Hz): - out: f0 43 10 04 40 2f f7 - out: f0 43 11 04 40 37 f7 - out: f0 43 12 04 40 40 f7 - out: f0 43 13 04 40 48 f7 - - Set Module 1 to Poly and Mono: - out: f0 43 13 04 02 00 f7 - out: f0 43 13 04 02 01 f7 - - ModWheel Sensivity: - out: f0 43 13 04 02 01 f7 - */ +*/ // Check for TX216/TX816 style performance sysex messages if (pMessage[3] == 0x04) { - LOGNOTE("MIDI-SYSEX: Assuming TX216/TX816 style performance sysex message because 4th byte is 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 0: // MIDI Channel + case 1: // MIDI Channel + LOGNOTE("MIDI-SYSEX: Set MIDI Channel %d to %d", mTG, val & 0x0F); m_pSynthesizer->SetMIDIChannel(val & 0x0F, mTG); break; - case 1: // Poly/Mono + 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 2: // Pitch Bend Range + 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 3: // Pitch Bend Step + 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 4: // Portamento Time + case 5: // Portamento Time + LOGNOTE("MIDI-SYSEX: Set Portamento Time %d to %d", mTG, val & 0x0F); m_pSynthesizer->setPortamentoTime(val, mTG); break; - case 5: // Portamento/Glissando + case 6: // Portamento/Glissando + LOGNOTE("MIDI-SYSEX: Set Portamento/Glissando %d to %d", mTG, val & 0x0F); m_pSynthesizer->setPortamentoGlissando(val, mTG); break; - case 6: // Portamento Mode + 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 - m_pSynthesizer->SetMasterTune(val, mTG); + 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 if (pMessage[3] == 0x10) - { - LOGNOTE("MIDI-SYSEX: Assuming TX216/TX816 style performance sysex message because 4th byte is 0x10"); - - } else { - LOGNOTE("MIDI-SYSEX: Sending to Synth_Dexed for handling"); - } HandleSystemExclusive(pMessage, nLength, nCable, nTG); } } @@ -524,19 +582,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; @@ -552,11 +610,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; @@ -662,10 +721,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; @@ -717,62 +778,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"); @@ -800,6 +805,7 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL LOGDBG("SysEx send voice %u request",sysex_return-500); SendSystemExclusiveVoice(sysex_return-500, nCable, nTG); } + break; } } diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 134d241..cf5d16e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -898,7 +898,7 @@ void CMiniDexed::setSustain(bool sustain, unsigned nTG) assert (m_pTG[nTG]); m_pTG[nTG]->setSustain (sustain); } - +/* void CMiniDexed::setSostenuto(bool sostenuto, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -916,7 +916,7 @@ void CMiniDexed::setHoldMode(bool holdmode, unsigned nTG) assert (m_pTG[nTG]); m_pTG[nTG]->setHold (holdmode); } - +*/ void CMiniDexed::panic(uint8_t value, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators);