diff --git a/build.sh b/build.sh
index ef9ce685..de4d9f14 100755
--- a/build.sh
+++ b/build.sh
@@ -18,6 +18,9 @@ fi
cd circle-stdlib/
make mrproper || true
./configure -r ${RPI} --prefix "${TOOLCHAIN_PREFIX}"
+if [ "${RPI}" -gt "1" ]; then
+ echo "DEFINE += -DARM_ALLOW_MULTI_CORE" >> libs/circle/Config.mk
+fi
echo "DEFINE += -DUSE_PWM_AUDIO_ON_ZERO" >> libs/circle/Config.mk
echo "DEFINE += -DSAVE_VFP_REGS_ON_IRQ" >> libs/circle/Config.mk
echo "DEFINE += -DREALTIME" >> libs/circle/Config.mk
diff --git a/src/kernel.cpp b/src/kernel.cpp
index 2ad706d3..dde24f06 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -18,7 +18,6 @@
// along with this program. If not, see .
//
#include "kernel.h"
-#include
#include
#include
#include
@@ -65,27 +64,7 @@ bool CKernel::Initialize (void)
m_Config.Load ();
- // select the sound device
- const char *pSoundDevice = m_Config.GetSoundDevice ();
- if (strcmp (pSoundDevice, "i2s") == 0)
- {
- LOGNOTE ("I2S mode");
-
- m_pDexed = new CMiniDexedI2S (&m_Config, &mInterrupt, &m_GPIOManager, &m_I2CMaster);
- }
- else if (strcmp (pSoundDevice, "hdmi") == 0)
- {
- LOGNOTE ("HDMI mode");
-
- m_pDexed = new CMiniDexedHDMI (&m_Config, &mInterrupt, &m_GPIOManager);
- }
- else
- {
- LOGNOTE ("PWM mode");
-
- m_pDexed = new CMiniDexedPWM (&m_Config, &mInterrupt, &m_GPIOManager);
- }
-
+ m_pDexed = new CMiniDexed (&m_Config, &mInterrupt, &m_GPIOManager, &m_I2CMaster);
assert (m_pDexed);
if (!m_pDexed->Initialize ())
diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index 476a8f3e..23f64cb1 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -19,18 +19,28 @@
//
#include "minidexed.h"
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
LOGMODULE ("minidexed");
-CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, CGPIOManager *pGPIOManager)
+CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
+ CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster)
: CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ()),
+#ifdef ARM_ALLOW_MULTI_CORE
+ CMultiCoreSupport (CMemorySystem::Get ()),
+#endif
m_pConfig (pConfig),
m_UI (this, pGPIOManager, pConfig),
m_PCKeyboard (this),
m_SerialMIDI (this, pInterrupt, pConfig),
m_bUseSerial (false),
+ m_pSoundDevice (0),
m_GetChunkTimer ("GetChunk",
1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()),
m_bProfileEnabled (m_pConfig->GetProfileEnabled ())
@@ -40,10 +50,38 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, CGPIOMan
m_pMIDIKeyboard[i] = new CMIDIKeyboard (this, pConfig, i);
assert (m_pMIDIKeyboard[i]);
}
+
+ // select the sound device
+ const char *pDeviceName = pConfig->GetSoundDevice ();
+ if (strcmp (pDeviceName, "i2s") == 0)
+ {
+ LOGNOTE ("I2S mode");
+
+ m_pSoundDevice = new CI2SSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
+ pConfig->GetChunkSize (), false,
+ pI2CMaster, pConfig->GetDACI2CAddress ());
+ }
+ else if (strcmp (pDeviceName, "hdmi") == 0)
+ {
+ LOGNOTE ("HDMI mode");
+
+ m_pSoundDevice = new CHDMISoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
+ pConfig->GetChunkSize ());
+ }
+ else
+ {
+ LOGNOTE ("PWM mode");
+
+ m_pSoundDevice = new CPWMSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
+ pConfig->GetChunkSize ());
+ }
};
bool CMiniDexed::Initialize (void)
{
+ assert (m_pConfig);
+ assert (m_pSoundDevice);
+
if (!m_UI.Initialize ())
{
return false;
@@ -63,11 +101,37 @@ bool CMiniDexed::Initialize (void)
ProgramChange (0);
setTranspose (24);
+ // setup and start the sound device
+ if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ()/2))
+ {
+ LOGERR ("Cannot allocate sound queue");
+
+ return false;
+ }
+
+ m_pSoundDevice->SetWriteFormat (SoundFormatSigned16, 1); // 16-bit Mono
+
+ m_nQueueSizeFrames = m_pSoundDevice->GetQueueSizeFrames ();
+
+ m_pSoundDevice->Start ();
+
+#ifdef ARM_ALLOW_MULTI_CORE
+ // start secondary cores
+ if (!CMultiCoreSupport::Initialize ())
+ {
+ return false;
+ }
+#endif
+
return true;
}
void CMiniDexed::Process (bool bPlugAndPlayUpdated)
{
+#ifndef ARM_ALLOW_MULTI_CORE
+ ProcessSound ();
+#endif
+
for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++)
{
assert (m_pMIDIKeyboard[i]);
@@ -89,6 +153,21 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
}
}
+#ifdef ARM_ALLOW_MULTI_CORE
+
+void CMiniDexed::Run (unsigned nCore)
+{
+ if (nCore == 1)
+ {
+ while (1)
+ {
+ ProcessSound ();
+ }
+ }
+}
+
+#endif
+
CSysExFileLoader *CMiniDexed::GetSysExFileLoader (void)
{
return &m_SysExFileLoader;
@@ -120,159 +199,30 @@ void CMiniDexed::ProgramChange (unsigned nProgram)
m_UI.ProgramChanged (nProgram);
}
-//// PWM //////////////////////////////////////////////////////////////////////
-
-CMiniDexedPWM::CMiniDexedPWM (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager)
-: CMiniDexed (pConfig, pInterrupt, pGPIOManager),
- CPWMSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
- pConfig->GetChunkSize ())
+void CMiniDexed::ProcessSound (void)
{
-}
+ assert (m_pSoundDevice);
-bool CMiniDexedPWM::Initialize (void)
-{
- if (!CMiniDexed::Initialize ())
- {
- return false;
- }
-
- return Start ();
-}
-
-unsigned CMiniDexedPWM::GetChunk (u32 *pBuffer, unsigned nChunkSize)
-{
- if (m_bProfileEnabled)
+ unsigned nFrames = m_nQueueSizeFrames - m_pSoundDevice->GetQueueFramesAvail ();
+ if (nFrames >= m_nQueueSizeFrames/2)
{
- m_GetChunkTimer.Start ();
- }
-
- unsigned nResult = nChunkSize;
-
- int16_t SampleBuffer[nChunkSize/2];
- getSamples (nChunkSize/2, SampleBuffer);
-
- for (unsigned i = 0; nChunkSize > 0; nChunkSize -= 2) // fill the whole buffer
- {
- s32 nSample = SampleBuffer[i++];
- nSample += 32768;
- nSample *= GetRangeMax()/2;
- nSample /= 32768;
-
- *pBuffer++ = nSample; // 2 stereo channels
- *pBuffer++ = nSample;
- }
-
- if (m_bProfileEnabled)
- {
- m_GetChunkTimer.Stop ();
- }
-
- return nResult;
-};
-
-//// I2S //////////////////////////////////////////////////////////////////////
-
-CMiniDexedI2S::CMiniDexedI2S (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster)
-: CMiniDexed (pConfig, pInterrupt, pGPIOManager),
- CI2SSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
- pConfig->GetChunkSize (), false, pI2CMaster,
- pConfig->GetDACI2CAddress ())
-{
-}
-
-bool CMiniDexedI2S::Initialize (void)
-{
- if (!CMiniDexed::Initialize ())
- {
- return false;
- }
-
- return Start ();
-}
-
-unsigned CMiniDexedI2S::GetChunk (u32 *pBuffer, unsigned nChunkSize)
-{
- if (m_bProfileEnabled)
- {
- m_GetChunkTimer.Start ();
- }
-
- unsigned nResult = nChunkSize;
-
- int16_t SampleBuffer[nChunkSize/2];
- getSamples (nChunkSize/2, SampleBuffer);
-
- for (unsigned i = 0; nChunkSize > 0; nChunkSize -= 2) // fill the whole buffer
- {
- s32 nSample = SampleBuffer[i++];
- nSample <<= 8;
-
- *pBuffer++ = nSample; // 2 stereo channels
- *pBuffer++ = nSample;
- }
-
- if (m_bProfileEnabled)
- {
- m_GetChunkTimer.Stop ();
- }
-
- return nResult;
-};
-
-//// HDMI /////////////////////////////////////////////////////////////////////
-
-CMiniDexedHDMI::CMiniDexedHDMI (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager)
-: CMiniDexed (pConfig, pInterrupt, pGPIOManager),
- CHDMISoundBaseDevice (pInterrupt, pConfig->GetSampleRate (),
- pConfig->GetChunkSize ())
-{
-}
-
-bool CMiniDexedHDMI::Initialize (void)
-{
- if (!CMiniDexed::Initialize ())
- {
- return false;
- }
-
- return Start ();
-}
-
-unsigned CMiniDexedHDMI::GetChunk(u32 *pBuffer, unsigned nChunkSize)
-{
- if (m_bProfileEnabled)
- {
- m_GetChunkTimer.Start ();
- }
-
- unsigned nResult = nChunkSize;
+ if (m_bProfileEnabled)
+ {
+ m_GetChunkTimer.Start ();
+ }
- int16_t SampleBuffer[nChunkSize/2];
- getSamples (nChunkSize/2, SampleBuffer);
+ int16_t SampleBuffer[nFrames];
+ getSamples (nFrames, SampleBuffer);
- unsigned nFrame = 0;
- for (unsigned i = 0; nChunkSize > 0; nChunkSize -= 2) // fill the whole buffer
- {
- s32 nSample = SampleBuffer[i++];
- nSample <<= 8;
-
- nSample = ConvertIEC958Sample (nSample, nFrame);
- if (++nFrame == IEC958_FRAMES_PER_BLOCK)
+ if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer)
+ != (int) sizeof SampleBuffer)
{
- nFrame = 0;
+ LOGERR ("Sound data dropped");
}
- *pBuffer++ = nSample; // 2 stereo channels
- *pBuffer++ = nSample;
- }
-
- if (m_bProfileEnabled)
- {
- m_GetChunkTimer.Stop();
+ if (m_bProfileEnabled)
+ {
+ m_GetChunkTimer.Stop ();
+ }
}
-
- return nResult;
-};
+}
diff --git a/src/minidexed.h b/src/minidexed.h
index d817f87d..ae0eff65 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -33,25 +33,34 @@
#include
#include
#include
-#include
-#include
-#include
+#include
+#include
class CMiniDexed : public CDexedAdapter
+#ifdef ARM_ALLOW_MULTI_CORE
+ , public CMultiCoreSupport
+#endif
{
public:
CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager);
+ CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster);
- virtual bool Initialize (void);
+ bool Initialize (void);
void Process (bool bPlugAndPlayUpdated);
+#ifdef ARM_ALLOW_MULTI_CORE
+ void Run (unsigned nCore);
+#endif
+
CSysExFileLoader *GetSysExFileLoader (void);
void BankSelectLSB (unsigned nBankLSB);
void ProgramChange (unsigned nProgram);
+private:
+ void ProcessSound (void);
+
private:
CConfig *m_pConfig;
@@ -63,48 +72,12 @@ class CMiniDexed : public CDexedAdapter
CSerialMIDIDevice m_SerialMIDI;
bool m_bUseSerial;
+ CSoundBaseDevice *m_pSoundDevice;
+ unsigned m_nQueueSizeFrames;
+
protected:
CPerformanceTimer m_GetChunkTimer;
bool m_bProfileEnabled;
};
-//// PWM //////////////////////////////////////////////////////////////////////
-
-class CMiniDexedPWM : public CMiniDexed, public CPWMSoundBaseDevice
-{
-public:
- CMiniDexedPWM (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager);
-
- bool Initialize (void);
-
- unsigned GetChunk (u32 *pBuffer, unsigned nChunkSize);
-};
-
-//// I2S //////////////////////////////////////////////////////////////////////
-
-class CMiniDexedI2S : public CMiniDexed, public CI2SSoundBaseDevice
-{
-public:
- CMiniDexedI2S (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster);
-
- bool Initialize (void);
-
- unsigned GetChunk (u32 *pBuffer, unsigned nChunkSize);
-};
-
-//// HDMI /////////////////////////////////////////////////////////////////////
-
-class CMiniDexedHDMI : public CMiniDexed, public CHDMISoundBaseDevice
-{
-public:
- CMiniDexedHDMI (CConfig *pConfig, CInterruptSystem *pInterrupt,
- CGPIOManager *pGPIOManager);
-
- bool Initialize (void);
-
- unsigned GetChunk (u32 *pBuffer, unsigned nChunkSize);
-};
-
#endif