Skip to content

Commit a3dbc3d

Browse files
committed
implement NPRN protocl for controlling TGs with a MIDI controller
1 parent 753c205 commit a3dbc3d

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

src/mididevice.cpp

+183
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ LOGMODULE ("mididevice");
5050
#define MIDI_CC_DETUNE_LEVEL 94
5151
#define MIDI_CC_ALL_SOUND_OFF 120
5252
#define MIDI_CC_ALL_NOTES_OFF 123
53+
#define MIDI_CC_NRPN_PARAM_MSB 99
54+
#define MIDI_CC_NRPN_PARAM_LSB 98
55+
#define MIDI_CC_NRPN_DATA_LSB 38
5356
#define MIDI_PROGRAM_CHANGE 0b1100
5457
#define MIDI_PITCH_BEND 0b1110
5558

@@ -58,6 +61,12 @@ LOGMODULE ("mididevice");
5861
#define MIDI_TIMING_CLOCK 0xF8
5962
#define MIDI_ACTIVE_SENSING 0xFE
6063

64+
#define MIDI_NRPN_PROGRAM_CHANGE 21
65+
66+
uint8_t scale(uint8_t max, uint8_t value) {
67+
return (uint8_t)((((unsigned)value) * max) / 127);
68+
}
69+
6170
CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap;
6271

6372
CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI)
@@ -68,6 +77,8 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInter
6877
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
6978
{
7079
m_ChannelMap[nTG] = Disabled;
80+
m_NRPNoffset[nTG] = 0;
81+
m_NRPNop[nTG] = 0;
7182
}
7283
}
7384

@@ -347,6 +358,178 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
347358
m_pSynthesizer->notesOff (pMessage[2], nTG);
348359
}
349360
break;
361+
362+
case MIDI_CC_NRPN_PARAM_MSB:
363+
if(pMessage[2] <= 6) {
364+
m_NRPNop[nTG] = pMessage[2];
365+
}
366+
break;
367+
368+
case MIDI_CC_NRPN_PARAM_LSB:
369+
m_NRPNoffset[nTG] = pMessage[2];
370+
break;
371+
372+
case MIDI_CC_NRPN_DATA_LSB:
373+
switch(m_NRPNoffset[nTG])
374+
{
375+
case MIDI_NRPN_PROGRAM_CHANGE:
376+
m_pSynthesizer->ProgramChange(pMessage[2], nTG);
377+
break;
378+
default:
379+
if(m_NRPNop[nTG] < 6)
380+
{
381+
switch(m_NRPNoffset[nTG]) {
382+
case DEXED_OP_EG_R1:
383+
m_pSynthesizer->m_pTG[nTG]->setOPRate(m_NRPNop[nTG], 0, scale(99, pMessage[2]));
384+
break;
385+
case DEXED_OP_EG_R2:
386+
m_pSynthesizer->m_pTG[nTG]->setOPRate(m_NRPNop[nTG], 1, scale(99, pMessage[2]));
387+
break;
388+
case DEXED_OP_EG_R3:
389+
m_pSynthesizer->m_pTG[nTG]->setOPRate(m_NRPNop[nTG], 2, scale(99, pMessage[2]));
390+
break;
391+
case DEXED_OP_EG_R4:
392+
m_pSynthesizer->m_pTG[nTG]->setOPRate(m_NRPNop[nTG], 3, scale(99, pMessage[2]));
393+
break;
394+
case DEXED_OP_EG_L1:
395+
m_pSynthesizer->m_pTG[nTG]->setOPLevel(m_NRPNop[nTG], 0, scale(99, pMessage[2]));
396+
break;
397+
case DEXED_OP_EG_L2:
398+
m_pSynthesizer->m_pTG[nTG]->setOPLevel(m_NRPNop[nTG], 1, scale(99, pMessage[2]));
399+
break;
400+
case DEXED_OP_EG_L3:
401+
m_pSynthesizer->m_pTG[nTG]->setOPLevel(m_NRPNop[nTG], 2, scale(99, pMessage[2]));
402+
break;
403+
case DEXED_OP_EG_L4:
404+
m_pSynthesizer->m_pTG[nTG]->setOPLevel(m_NRPNop[nTG], 3, scale(99, pMessage[2]));
405+
break;
406+
case DEXED_OP_LEV_SCL_BRK_PT:
407+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardLevelScalingBreakPoint(m_NRPNop[nTG], scale(99, pMessage[2]));
408+
break;
409+
case DEXED_OP_SCL_LEFT_DEPTH:
410+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardLevelScalingDepthLeft(m_NRPNop[nTG], scale(99, pMessage[2]));
411+
break;
412+
case DEXED_OP_SCL_RGHT_DEPTH:
413+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardLevelScalingDepthRight(m_NRPNop[nTG], scale(99, pMessage[2]));
414+
break;
415+
case DEXED_OP_SCL_LEFT_CURVE:
416+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardLevelScalingCurveLeft(m_NRPNop[nTG], scale(3, pMessage[2]));
417+
break;
418+
case DEXED_OP_SCL_RGHT_CURVE:
419+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardLevelScalingCurveRight(m_NRPNop[nTG], scale(3, pMessage[2]));
420+
break;
421+
case DEXED_OP_OSC_RATE_SCALE:
422+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardRateScale(m_NRPNop[nTG], scale(7, pMessage[2]));
423+
break;
424+
case DEXED_OP_AMP_MOD_SENS:
425+
m_pSynthesizer->m_pTG[nTG]->setOPAmpModulationSensity(m_NRPNop[nTG], scale(3, pMessage[2]));
426+
break;
427+
case DEXED_OP_KEY_VEL_SENS:
428+
m_pSynthesizer->m_pTG[nTG]->setOPKeyboardVelocitySensity(m_NRPNop[nTG], scale(7, pMessage[2]));
429+
break;
430+
case DEXED_OP_OUTPUT_LEV:
431+
m_pSynthesizer->m_pTG[nTG]->setOPOutputLevel(m_NRPNop[nTG], scale(99, pMessage[2]));
432+
break;
433+
case DEXED_OP_OSC_MODE:
434+
m_pSynthesizer->m_pTG[nTG]->setOPMode(m_NRPNop[nTG], scale(1, pMessage[2]));
435+
break;
436+
case DEXED_OP_FREQ_COARSE:
437+
m_pSynthesizer->m_pTG[nTG]->setOPFrequencyCoarse(m_NRPNop[nTG], scale(31, pMessage[2]));
438+
break;
439+
case DEXED_OP_FREQ_FINE:
440+
m_pSynthesizer->m_pTG[nTG]->setOPFrequencyFine(m_NRPNop[nTG], scale(99, pMessage[2]));
441+
break;
442+
case DEXED_OP_OSC_DETUNE:
443+
m_pSynthesizer->m_pTG[nTG]->setOPDetune(m_NRPNop[nTG], scale(14, pMessage[2]));
444+
break;
445+
}
446+
// TODO: send partial update, but this will do for now
447+
SendSystemExclusiveVoice(0, 0, nTG);
448+
}
449+
if(m_NRPNop[nTG] == 6) {
450+
switch(m_NRPNoffset[nTG]) {
451+
case DEXED_PITCH_EG_R1:
452+
m_pSynthesizer->m_pTG[nTG]->setPitchRate(0, scale(99, pMessage[2]));
453+
break;
454+
case DEXED_PITCH_EG_R2:
455+
m_pSynthesizer->m_pTG[nTG]->setPitchRate(1, scale(99, pMessage[2]));
456+
457+
break;
458+
case DEXED_PITCH_EG_R3:
459+
m_pSynthesizer->m_pTG[nTG]->setPitchRate(2, scale(99, pMessage[2]));
460+
461+
break;
462+
case DEXED_PITCH_EG_R4:
463+
m_pSynthesizer->m_pTG[nTG]->setPitchRate(3, scale(99, pMessage[2]));
464+
465+
break;
466+
case DEXED_PITCH_EG_L1:
467+
m_pSynthesizer->m_pTG[nTG]->setPitchLevel(0, scale(99, pMessage[2]));
468+
469+
break;
470+
case DEXED_PITCH_EG_L2:
471+
m_pSynthesizer->m_pTG[nTG]->setPitchLevel(1, scale(99, pMessage[2]));
472+
473+
break;
474+
case DEXED_PITCH_EG_L3:
475+
m_pSynthesizer->m_pTG[nTG]->setPitchLevel(2, scale(99, pMessage[2]));
476+
477+
break;
478+
case DEXED_PITCH_EG_L4:
479+
m_pSynthesizer->m_pTG[nTG]->setPitchLevel(3, scale(99, pMessage[2]));
480+
481+
break;
482+
case DEXED_ALGORITHM:
483+
m_pSynthesizer->m_pTG[nTG]->setAlgorithm(scale(31, pMessage[2]));
484+
485+
break;
486+
case DEXED_FEEDBACK:
487+
m_pSynthesizer->m_pTG[nTG]->setFeedback(scale(7, pMessage[2]));
488+
489+
break;
490+
case DEXED_OSC_KEY_SYNC:
491+
m_pSynthesizer->m_pTG[nTG]->setOscillatorSync(scale(1, pMessage[2]));
492+
493+
break;
494+
case DEXED_LFO_SPEED:
495+
m_pSynthesizer->m_pTG[nTG]->setLFOSpeed(scale(99, pMessage[2]));
496+
497+
break;
498+
case DEXED_LFO_DELAY:
499+
m_pSynthesizer->m_pTG[nTG]->setLFODelay(scale(99, pMessage[2]));
500+
501+
break;
502+
case DEXED_LFO_PITCH_MOD_DEP:
503+
m_pSynthesizer->m_pTG[nTG]->setLFOPitchModulationDepth(scale(99, pMessage[2]));
504+
505+
break;
506+
case DEXED_LFO_AMP_MOD_DEP:
507+
m_pSynthesizer->m_pTG[nTG]->setLFOAmpModulationDepth(scale(99, pMessage[2]));
508+
509+
break;
510+
case DEXED_LFO_SYNC:
511+
m_pSynthesizer->m_pTG[nTG]->setLFOSync(scale(1, pMessage[2]));
512+
513+
break;
514+
case DEXED_LFO_WAVE:
515+
m_pSynthesizer->m_pTG[nTG]->setLFOWaveform(scale(4, pMessage[2]));
516+
517+
break;
518+
case DEXED_LFO_PITCH_MOD_SENS:
519+
m_pSynthesizer->m_pTG[nTG]->setLFOPitchModulationSensitivity(scale(7, pMessage[2]));
520+
521+
break;
522+
case DEXED_TRANSPOSE:
523+
m_pSynthesizer->m_pTG[nTG]->setTranspose(scale(48, pMessage[2]));
524+
525+
break;
526+
}
527+
// TODO: send partial update, but this will do for now
528+
SendSystemExclusiveVoice(0, 0, nTG);
529+
}
530+
}
531+
break;
532+
350533
}
351534
break;
352535

src/mididevice.h

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class CMIDIDevice
6363
CUserInterface *m_pUI;
6464

6565
u8 m_ChannelMap[CConfig::ToneGenerators];
66+
u8 m_NRPNoffset[CConfig::ToneGenerators];
67+
u8 m_NRPNop[CConfig::ToneGenerators];
6668

6769
std::string m_DeviceName;
6870

src/minidexed.h

+2
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ class CMiniDexed
234234

235235
int m_nParameter[ParameterUnknown]; // global (non-TG) parameters
236236

237+
public:
237238
CDexedAdapter *m_pTG[CConfig::ToneGenerators];
239+
private:
238240

239241
unsigned m_nVoiceBankID[CConfig::ToneGenerators];
240242
unsigned m_nVoiceBankIDMSB[CConfig::ToneGenerators];

0 commit comments

Comments
 (0)