Skip to content

Commit

Permalink
Support multiple Dexed instances (#50)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
rsta2 authored Mar 19, 2022
1 parent ae302e4 commit d6025f1
Show file tree
Hide file tree
Showing 13 changed files with 551 additions and 172 deletions.
4 changes: 4 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ void CConfig::Load (void)
m_SoundDevice = m_Properties.GetString ("SoundDevice", "pwm");

m_nSampleRate = m_Properties.GetNumber ("SampleRate", 48000);
#ifdef ARM_ALLOW_MULTI_CORE
m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 256);
#else
m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 1024);
#endif
m_nDACI2CAddress = m_Properties.GetNumber ("DACI2CAddress", 0);

m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250);
Expand Down
17 changes: 16 additions & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,27 @@

#include <fatfs/ff.h>
#include <Properties/propertiesfatfsfile.h>
#include <circle/sysconfig.h>
#include <string>

class CConfig // Configuration for MiniDexed
{
public:
static const unsigned MaxNotes = 16; // polyphony
#ifndef ARM_ALLOW_MULTI_CORE
static const unsigned ToneGenerators = 1;
#else
static const unsigned TGsCore1 = 2; // process 2 TGs on core 1
static const unsigned TGsCore23 = 3; // process 3 TGs on core 2 and 3 each
static const unsigned ToneGenerators = TGsCore1 + 2*TGsCore23;
#endif

#if RASPPI == 1
static const unsigned MaxNotes = 8; // polyphony
#else
static const unsigned MaxNotes = 16;
#endif

static const unsigned MaxChunkSize = 4096;

#if RASPPI <= 3
static const unsigned MaxUSBMIDIDevices = 2;
Expand Down
7 changes: 7 additions & 0 deletions src/dexedadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ class CDexedAdapter : public Dexed
m_SpinLock.Release ();
}

void setSustain (bool sustain)
{
m_SpinLock.Acquire ();
Dexed::setSustain (sustain);
m_SpinLock.Release ();
}

private:
CSpinLock m_SpinLock;
};
Expand Down
180 changes: 101 additions & 79 deletions src/mididevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,29 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
: m_pSynthesizer (pSynthesizer),
m_pConfig (pConfig)
{
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
m_ChannelMap[nTG] = Disabled;
}
}

CMIDIDevice::~CMIDIDevice (void)
{
m_pSynthesizer = 0;
}

void CMIDIDevice::SetChannel (u8 ucChannel, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
m_ChannelMap[nTG] = ucChannel;
}

u8 CMIDIDevice::GetChannel (unsigned nTG) const
{
assert (nTG < CConfig::ToneGenerators);
return m_ChannelMap[nTG];
}

void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
{
assert (m_pSynthesizer != 0);
Expand All @@ -67,17 +83,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
if ( pMessage[0] != MIDI_TIMING_CLOCK
&& pMessage[0] != MIDI_ACTIVE_SENSING)
{
printf ("MIDI %u: %02X\n", nCable, (unsigned) pMessage[0]);
printf ("MIDI%u: %02X\n", nCable, (unsigned) pMessage[0]);
}
break;

case 2:
printf ("MIDI %u: %02X %02X\n", nCable,
printf ("MIDI%u: %02X %02X\n", nCable,
(unsigned) pMessage[0], (unsigned) pMessage[1]);
break;

case 3:
printf ("MIDI %u: %02X %02X %02X\n", nCable,
printf ("MIDI%u: %02X %02X %02X\n", nCable,
(unsigned) pMessage[0], (unsigned) pMessage[1],
(unsigned) pMessage[2]);
break;
Expand All @@ -89,87 +105,93 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
return;
}

u8 ucStatus = pMessage[0];
// TODO: u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4;
u8 ucKeyNumber = pMessage[1];
u8 ucVelocity = pMessage[2];
u8 ucStatus = pMessage[0];
u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4;

switch (ucType)
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
case MIDI_NOTE_ON:
if (nLength < 3)
if ( m_ChannelMap[nTG] == ucChannel
|| m_ChannelMap[nTG] == OmniMode)
{
break;
}

if (ucVelocity > 0)
{
if (ucVelocity <= 127)
switch (ucType)
{
m_pSynthesizer->keydown (ucKeyNumber, ucVelocity);
case MIDI_NOTE_ON:
if (nLength < 3)
{
break;
}

if (pMessage[2] > 0)
{
if (pMessage[2] <= 127)
{
m_pSynthesizer->keydown (pMessage[1],
pMessage[2], nTG);
}
}
else
{
m_pSynthesizer->keyup (pMessage[1], nTG);
}
break;

case MIDI_NOTE_OFF:
if (nLength < 3)
{
break;
}

m_pSynthesizer->keyup (pMessage[1], nTG);
break;

case MIDI_CONTROL_CHANGE:
if (nLength < 3)
{
break;
}

switch (pMessage[1])
{
case MIDI_CC_MODULATION:
m_pSynthesizer->setModWheel (pMessage[2], nTG);
m_pSynthesizer->ControllersRefresh (nTG);
break;

case MIDI_CC_VOLUME:
m_pSynthesizer->SetVolume (pMessage[2], nTG);
break;

case MIDI_CC_BANK_SELECT_LSB:
m_pSynthesizer->BankSelectLSB (pMessage[2], nTG);
break;

case MIDI_CC_BANK_SUSTAIN:
m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
break;
}
break;

case MIDI_PROGRAM_CHANGE:
m_pSynthesizer->ProgramChange (pMessage[1], nTG);
break;

case MIDI_PITCH_BEND: {
if (nLength < 3)
{
break;
}

s16 nValue = pMessage[1];
nValue |= (s16) pMessage[2] << 7;
nValue -= 0x2000;

m_pSynthesizer->setPitchbend (nValue, nTG);
} break;

default:
break;
}
}
else
{
m_pSynthesizer->keyup (ucKeyNumber);
}
break;

case MIDI_NOTE_OFF:
if (nLength < 3)
{
break;
}

m_pSynthesizer->keyup (ucKeyNumber);
break;

case MIDI_CONTROL_CHANGE:
if (nLength < 3)
{
break;
}

switch (pMessage[1])
{
case MIDI_CC_MODULATION:
m_pSynthesizer->setModWheel (pMessage[2]);
m_pSynthesizer->ControllersRefresh ();
break;

case MIDI_CC_VOLUME:
m_pSynthesizer->SetVolume (pMessage[2]);
break;

case MIDI_CC_BANK_SELECT_LSB:
m_pSynthesizer->BankSelectLSB (pMessage[2]);
break;

case MIDI_CC_BANK_SUSTAIN:
m_pSynthesizer->setSustain (pMessage[2] >= 64);
break;
}
break;

case MIDI_PROGRAM_CHANGE:
m_pSynthesizer->ProgramChange (pMessage[1]);
break;

case MIDI_PITCH_BEND: {
if (nLength < 3)
{
break;
}

s16 nValue = pMessage[1];
nValue |= (s16) pMessage[2] << 7;
nValue -= 0x2000;

m_pSynthesizer->setPitchbend (nValue);
} break;

default:
break;
}
}
14 changes: 14 additions & 0 deletions src/mididevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,30 @@ class CMiniDexed;

class CMIDIDevice
{
public:
enum TChannel
{
Channels = 16,
OmniMode = Channels,
Disabled,
ChannelUnknown
};

public:
CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig);
~CMIDIDevice (void);

void SetChannel (u8 ucChannel, unsigned nTG);
u8 GetChannel (unsigned nTG) const;

protected:
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);

private:
CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig;

u8 m_ChannelMap[CConfig::ToneGenerators];
};

#endif
Loading

0 comments on commit d6025f1

Please sign in to comment.