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
pull/50/head
Rene Stange 3 years ago
parent 52ebc43671
commit 0045c6012e
  1. 15
      src/config.h
  2. 140
      src/minidexed.cpp
  3. 17
      src/minidexed.h

@ -25,19 +25,28 @@
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <Properties/propertiesfatfsfile.h> #include <Properties/propertiesfatfsfile.h>
#include <circle/sysconfig.h>
#include <string> #include <string>
class CConfig // Configuration for MiniDexed class CConfig // Configuration for MiniDexed
{ {
public: public:
#if RASPPI == 1 #ifndef ARM_ALLOW_MULTI_CORE
static const unsigned ToneGenerators = 1; 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 static const unsigned MaxNotes = 8; // polyphony
#else #else
static const unsigned ToneGenerators = 2; static const unsigned MaxNotes = 16;
static const unsigned MaxNotes = 16; // polyphony
#endif #endif
static const unsigned MaxChunkSize = 4096;
#if RASPPI <= 3 #if RASPPI <= 3
static const unsigned MaxUSBMIDIDevices = 2; static const unsigned MaxUSBMIDIDevices = 2;
#else #else

@ -85,6 +85,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_pSoundDevice = new CPWMSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (), m_pSoundDevice = new CPWMSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
pConfig->GetChunkSize ()); pConfig->GetChunkSize ());
} }
#ifdef ARM_ALLOW_MULTI_CORE
for (unsigned nCore = 0; nCore < CORES; nCore++)
{
m_CoreStatus[nCore] = CoreStatusInit;
}
#endif
}; };
bool CMiniDexed::Initialize (void) bool CMiniDexed::Initialize (void)
@ -175,13 +182,58 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
void CMiniDexed::Run (unsigned nCore) void CMiniDexed::Run (unsigned nCore)
{ {
assert (1 <= nCore && nCore < CORES);
if (nCore == 1) if (nCore == 1)
{ {
while (1) m_CoreStatus[nCore] = CoreStatusIdle; // core 1 ready
// wait for cores 2 and 3 to be ready
for (unsigned nCore = 2; nCore < CORES; nCore++)
{
while (m_CoreStatus[nCore] != CoreStatusIdle)
{
// just wait
}
}
while (m_CoreStatus[nCore] != CoreStatusExit)
{ {
ProcessSound (); ProcessSound ();
} }
} }
else // core 2 and 3
{
while (1)
{
m_CoreStatus[nCore] = CoreStatusIdle; // ready to be kicked
while (m_CoreStatus[nCore] == CoreStatusIdle)
{
// just wait
}
// now kicked from core 1
if (m_CoreStatus[nCore] == CoreStatusExit)
{
m_CoreStatus[nCore] = CoreStatusUnknown;
break;
}
assert (m_CoreStatus[nCore] == CoreStatusBusy);
// process the TGs, assigned to this core (2 or 3)
assert (m_nFramesToProcess <= CConfig::MaxChunkSize);
unsigned nTG = CConfig::TGsCore1 + (nCore-2)*CConfig::TGsCore23;
for (unsigned i = 0; i < CConfig::TGsCore23; i++, nTG++)
{
assert (m_pTG[nTG]);
m_pTG[nTG]->getSamples (m_nFramesToProcess, m_OutputLevel[nTG]);
}
}
}
} }
#endif #endif
@ -303,6 +355,8 @@ std::string CMiniDexed::GetVoiceName (unsigned nTG)
return Result; return Result;
} }
#ifndef ARM_ALLOW_MULTI_CORE
void CMiniDexed::ProcessSound (void) void CMiniDexed::ProcessSound (void)
{ {
assert (m_pSoundDevice); assert (m_pSoundDevice);
@ -316,33 +370,77 @@ void CMiniDexed::ProcessSound (void)
} }
int16_t SampleBuffer[nFrames]; int16_t SampleBuffer[nFrames];
m_pTG[0]->getSamples (nFrames, SampleBuffer);
if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer)
!= (int) sizeof SampleBuffer)
{
LOGERR ("Sound data dropped");
}
#if RASPPI > 1 if (m_bProfileEnabled)
for (unsigned i = 0; i < CConfig::ToneGenerators; i++)
{ {
int16_t TempBuffer[nFrames]; m_GetChunkTimer.Stop ();
}
}
}
#else // #ifdef ARM_ALLOW_MULTI_CORE
void CMiniDexed::ProcessSound (void)
{
assert (m_pSoundDevice);
unsigned nFrames = m_nQueueSizeFrames - m_pSoundDevice->GetQueueFramesAvail ();
if (nFrames >= m_nQueueSizeFrames/2)
{
if (m_bProfileEnabled)
{
m_GetChunkTimer.Start ();
}
m_nFramesToProcess = nFrames;
// kick secondary cores
for (unsigned nCore = 2; nCore < CORES; nCore++)
{
assert (m_CoreStatus[nCore] == CoreStatusIdle);
m_CoreStatus[nCore] = CoreStatusBusy;
}
// process the TGs assigned to core 1
assert (nFrames <= CConfig::MaxChunkSize);
for (unsigned i = 0; i < CConfig::TGsCore1; i++)
{
assert (m_pTG[i]); assert (m_pTG[i]);
m_pTG[i]->getSamples (nFrames, TempBuffer); m_pTG[i]->getSamples (nFrames, m_OutputLevel[i]);
}
if (i == 0) // wait for cores 2 and 3 to complete their work
{ for (unsigned nCore = 2; nCore < CORES; nCore++)
for (unsigned j = 0; j < nFrames; j++) {
{ while (m_CoreStatus[nCore] != CoreStatusIdle)
SampleBuffer[j] = TempBuffer[j] / CConfig::ToneGenerators;
}
}
else
{ {
for (unsigned j = 0; j < nFrames; j++) // just wait
{
SampleBuffer[j] += TempBuffer[j] / CConfig::ToneGenerators;
}
} }
} }
#else
m_pTG[0]->getSamples (nFrames, SampleBuffer); // now mix the output of all TGs
#endif int16_t SampleBuffer[nFrames];
assert (CConfig::ToneGenerators == 8);
for (unsigned i = 0; i < nFrames; i++)
{
int32_t nSample = m_OutputLevel[0][i]
+ m_OutputLevel[1][i]
+ m_OutputLevel[2][i]
+ m_OutputLevel[3][i]
+ m_OutputLevel[4][i]
+ m_OutputLevel[5][i]
+ m_OutputLevel[6][i]
+ m_OutputLevel[7][i];
SampleBuffer[i] = (int16_t) (nSample / CConfig::ToneGenerators);
}
if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer) if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer)
!= (int) sizeof SampleBuffer) != (int) sizeof SampleBuffer)
@ -356,3 +454,5 @@ void CMiniDexed::ProcessSound (void)
} }
} }
} }
#endif

@ -73,6 +73,17 @@ public:
private: private:
void ProcessSound (void); void ProcessSound (void);
#ifdef ARM_ALLOW_MULTI_CORE
enum TCoreStatus
{
CoreStatusInit,
CoreStatusIdle,
CoreStatusBusy,
CoreStatusExit,
CoreStatusUnknown
};
#endif
private: private:
CConfig *m_pConfig; CConfig *m_pConfig;
@ -89,6 +100,12 @@ private:
CSoundBaseDevice *m_pSoundDevice; CSoundBaseDevice *m_pSoundDevice;
unsigned m_nQueueSizeFrames; unsigned m_nQueueSizeFrames;
#ifdef ARM_ALLOW_MULTI_CORE
volatile TCoreStatus m_CoreStatus[CORES];
volatile unsigned m_nFramesToProcess;
int16_t m_OutputLevel[CConfig::ToneGenerators][CConfig::MaxChunkSize];
#endif
CPerformanceTimer m_GetChunkTimer; CPerformanceTimer m_GetChunkTimer;
bool m_bProfileEnabled; bool m_bProfileEnabled;
}; };

Loading…
Cancel
Save