Skip to content

Commit d6025f1

Browse files
authored
Support multiple Dexed instances (#50)
* dexedadapter: Protect setSustain() with spin-lock too * Initial support for multiple Dexed instances * Currently 2 similar instances, which work with the same parameters * Only 1 instance with max. 8 notes polyphony on RPi 1 * Chunk size needs to be increased on RPi 1 * Support 8 Dexed instances (TGs) with multi-core * Core 1 kicks core 2 and 3 and processes two TGs then * Cores 2 and 3 wait for a kick and process three TGs each then * When all cores are ready, the output will be summed up * All 8 TGs generate the same sound at the moment * The maximum chunk size is limited to 4096 now * Maintain voice bank number per TG * Support TG select in UI * Active TG number is shown on LCD display * Next TG is selected by double click * MIDI receive and PC keyboard are still in omni mode * pckeyboard: Fake MIDI events * on MIDI cable 0, channel 0 * instead of calling key[down|up]() * derive from class CMIDIDevice * ui: Precede screen messages with TG number * Configure MIDI mapping from UI * ui: New menu item "MIDI" for configures assigned MIDI channel * ui: Holding switch for at least one second returns to menu home * ui: Do not show TG instance, if there is only one * By default TG1 is in omni mode, all other TGs are not assigned * config: Default chunk size is 1024 without multi-core
1 parent ae302e4 commit d6025f1

13 files changed

+551
-172
lines changed

src/config.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ void CConfig::Load (void)
3838
m_SoundDevice = m_Properties.GetString ("SoundDevice", "pwm");
3939

4040
m_nSampleRate = m_Properties.GetNumber ("SampleRate", 48000);
41+
#ifdef ARM_ALLOW_MULTI_CORE
4142
m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 256);
43+
#else
44+
m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 1024);
45+
#endif
4246
m_nDACI2CAddress = m_Properties.GetNumber ("DACI2CAddress", 0);
4347

4448
m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250);

src/config.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,27 @@
2525

2626
#include <fatfs/ff.h>
2727
#include <Properties/propertiesfatfsfile.h>
28+
#include <circle/sysconfig.h>
2829
#include <string>
2930

3031
class CConfig // Configuration for MiniDexed
3132
{
3233
public:
33-
static const unsigned MaxNotes = 16; // polyphony
34+
#ifndef ARM_ALLOW_MULTI_CORE
35+
static const unsigned ToneGenerators = 1;
36+
#else
37+
static const unsigned TGsCore1 = 2; // process 2 TGs on core 1
38+
static const unsigned TGsCore23 = 3; // process 3 TGs on core 2 and 3 each
39+
static const unsigned ToneGenerators = TGsCore1 + 2*TGsCore23;
40+
#endif
41+
42+
#if RASPPI == 1
43+
static const unsigned MaxNotes = 8; // polyphony
44+
#else
45+
static const unsigned MaxNotes = 16;
46+
#endif
47+
48+
static const unsigned MaxChunkSize = 4096;
3449

3550
#if RASPPI <= 3
3651
static const unsigned MaxUSBMIDIDevices = 2;

src/dexedadapter.h

+7
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ class CDexedAdapter : public Dexed
7070
m_SpinLock.Release ();
7171
}
7272

73+
void setSustain (bool sustain)
74+
{
75+
m_SpinLock.Acquire ();
76+
Dexed::setSustain (sustain);
77+
m_SpinLock.Release ();
78+
}
79+
7380
private:
7481
CSpinLock m_SpinLock;
7582
};

src/mididevice.cpp

+101-79
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,29 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
4545
: m_pSynthesizer (pSynthesizer),
4646
m_pConfig (pConfig)
4747
{
48+
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
49+
{
50+
m_ChannelMap[nTG] = Disabled;
51+
}
4852
}
4953

5054
CMIDIDevice::~CMIDIDevice (void)
5155
{
5256
m_pSynthesizer = 0;
5357
}
5458

59+
void CMIDIDevice::SetChannel (u8 ucChannel, unsigned nTG)
60+
{
61+
assert (nTG < CConfig::ToneGenerators);
62+
m_ChannelMap[nTG] = ucChannel;
63+
}
64+
65+
u8 CMIDIDevice::GetChannel (unsigned nTG) const
66+
{
67+
assert (nTG < CConfig::ToneGenerators);
68+
return m_ChannelMap[nTG];
69+
}
70+
5571
void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
5672
{
5773
assert (m_pSynthesizer != 0);
@@ -67,17 +83,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
6783
if ( pMessage[0] != MIDI_TIMING_CLOCK
6884
&& pMessage[0] != MIDI_ACTIVE_SENSING)
6985
{
70-
printf ("MIDI %u: %02X\n", nCable, (unsigned) pMessage[0]);
86+
printf ("MIDI%u: %02X\n", nCable, (unsigned) pMessage[0]);
7187
}
7288
break;
7389

7490
case 2:
75-
printf ("MIDI %u: %02X %02X\n", nCable,
91+
printf ("MIDI%u: %02X %02X\n", nCable,
7692
(unsigned) pMessage[0], (unsigned) pMessage[1]);
7793
break;
7894

7995
case 3:
80-
printf ("MIDI %u: %02X %02X %02X\n", nCable,
96+
printf ("MIDI%u: %02X %02X %02X\n", nCable,
8197
(unsigned) pMessage[0], (unsigned) pMessage[1],
8298
(unsigned) pMessage[2]);
8399
break;
@@ -89,87 +105,93 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
89105
return;
90106
}
91107

92-
u8 ucStatus = pMessage[0];
93-
// TODO: u8 ucChannel = ucStatus & 0x0F;
94-
u8 ucType = ucStatus >> 4;
95-
u8 ucKeyNumber = pMessage[1];
96-
u8 ucVelocity = pMessage[2];
108+
u8 ucStatus = pMessage[0];
109+
u8 ucChannel = ucStatus & 0x0F;
110+
u8 ucType = ucStatus >> 4;
97111

98-
switch (ucType)
112+
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
99113
{
100-
case MIDI_NOTE_ON:
101-
if (nLength < 3)
114+
if ( m_ChannelMap[nTG] == ucChannel
115+
|| m_ChannelMap[nTG] == OmniMode)
102116
{
103-
break;
104-
}
105-
106-
if (ucVelocity > 0)
107-
{
108-
if (ucVelocity <= 127)
117+
switch (ucType)
109118
{
110-
m_pSynthesizer->keydown (ucKeyNumber, ucVelocity);
119+
case MIDI_NOTE_ON:
120+
if (nLength < 3)
121+
{
122+
break;
123+
}
124+
125+
if (pMessage[2] > 0)
126+
{
127+
if (pMessage[2] <= 127)
128+
{
129+
m_pSynthesizer->keydown (pMessage[1],
130+
pMessage[2], nTG);
131+
}
132+
}
133+
else
134+
{
135+
m_pSynthesizer->keyup (pMessage[1], nTG);
136+
}
137+
break;
138+
139+
case MIDI_NOTE_OFF:
140+
if (nLength < 3)
141+
{
142+
break;
143+
}
144+
145+
m_pSynthesizer->keyup (pMessage[1], nTG);
146+
break;
147+
148+
case MIDI_CONTROL_CHANGE:
149+
if (nLength < 3)
150+
{
151+
break;
152+
}
153+
154+
switch (pMessage[1])
155+
{
156+
case MIDI_CC_MODULATION:
157+
m_pSynthesizer->setModWheel (pMessage[2], nTG);
158+
m_pSynthesizer->ControllersRefresh (nTG);
159+
break;
160+
161+
case MIDI_CC_VOLUME:
162+
m_pSynthesizer->SetVolume (pMessage[2], nTG);
163+
break;
164+
165+
case MIDI_CC_BANK_SELECT_LSB:
166+
m_pSynthesizer->BankSelectLSB (pMessage[2], nTG);
167+
break;
168+
169+
case MIDI_CC_BANK_SUSTAIN:
170+
m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
171+
break;
172+
}
173+
break;
174+
175+
case MIDI_PROGRAM_CHANGE:
176+
m_pSynthesizer->ProgramChange (pMessage[1], nTG);
177+
break;
178+
179+
case MIDI_PITCH_BEND: {
180+
if (nLength < 3)
181+
{
182+
break;
183+
}
184+
185+
s16 nValue = pMessage[1];
186+
nValue |= (s16) pMessage[2] << 7;
187+
nValue -= 0x2000;
188+
189+
m_pSynthesizer->setPitchbend (nValue, nTG);
190+
} break;
191+
192+
default:
193+
break;
111194
}
112195
}
113-
else
114-
{
115-
m_pSynthesizer->keyup (ucKeyNumber);
116-
}
117-
break;
118-
119-
case MIDI_NOTE_OFF:
120-
if (nLength < 3)
121-
{
122-
break;
123-
}
124-
125-
m_pSynthesizer->keyup (ucKeyNumber);
126-
break;
127-
128-
case MIDI_CONTROL_CHANGE:
129-
if (nLength < 3)
130-
{
131-
break;
132-
}
133-
134-
switch (pMessage[1])
135-
{
136-
case MIDI_CC_MODULATION:
137-
m_pSynthesizer->setModWheel (pMessage[2]);
138-
m_pSynthesizer->ControllersRefresh ();
139-
break;
140-
141-
case MIDI_CC_VOLUME:
142-
m_pSynthesizer->SetVolume (pMessage[2]);
143-
break;
144-
145-
case MIDI_CC_BANK_SELECT_LSB:
146-
m_pSynthesizer->BankSelectLSB (pMessage[2]);
147-
break;
148-
149-
case MIDI_CC_BANK_SUSTAIN:
150-
m_pSynthesizer->setSustain (pMessage[2] >= 64);
151-
break;
152-
}
153-
break;
154-
155-
case MIDI_PROGRAM_CHANGE:
156-
m_pSynthesizer->ProgramChange (pMessage[1]);
157-
break;
158-
159-
case MIDI_PITCH_BEND: {
160-
if (nLength < 3)
161-
{
162-
break;
163-
}
164-
165-
s16 nValue = pMessage[1];
166-
nValue |= (s16) pMessage[2] << 7;
167-
nValue -= 0x2000;
168-
169-
m_pSynthesizer->setPitchbend (nValue);
170-
} break;
171-
172-
default:
173-
break;
174196
}
175197
}

src/mididevice.h

+14
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,30 @@ class CMiniDexed;
3030

3131
class CMIDIDevice
3232
{
33+
public:
34+
enum TChannel
35+
{
36+
Channels = 16,
37+
OmniMode = Channels,
38+
Disabled,
39+
ChannelUnknown
40+
};
41+
3342
public:
3443
CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig);
3544
~CMIDIDevice (void);
3645

46+
void SetChannel (u8 ucChannel, unsigned nTG);
47+
u8 GetChannel (unsigned nTG) const;
48+
3749
protected:
3850
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);
3951

4052
private:
4153
CMiniDexed *m_pSynthesizer;
4254
CConfig *m_pConfig;
55+
56+
u8 m_ChannelMap[CConfig::ToneGenerators];
4357
};
4458

4559
#endif

0 commit comments

Comments
 (0)