@ -42,6 +42,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_PCKeyboard ( this , pConfig , & m_UI ) ,
m_PCKeyboard ( this , pConfig , & m_UI ) ,
m_SerialMIDI ( this , pInterrupt , pConfig , & m_UI ) ,
m_SerialMIDI ( this , pInterrupt , pConfig , & m_UI ) ,
m_bUseSerial ( false ) ,
m_bUseSerial ( false ) ,
m_bQuadDAC8Chan ( false ) ,
m_pSoundDevice ( 0 ) ,
m_pSoundDevice ( 0 ) ,
m_bChannelsSwapped ( pConfig - > GetChannelsSwapped ( ) ) ,
m_bChannelsSwapped ( pConfig - > GetChannelsSwapped ( ) ) ,
# ifdef ARM_ALLOW_MULTI_CORE
# ifdef ARM_ALLOW_MULTI_CORE
@ -125,10 +126,26 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
if ( strcmp ( pDeviceName , " i2s " ) = = 0 )
if ( strcmp ( pDeviceName , " i2s " ) = = 0 )
{
{
LOGNOTE ( " I2S mode " ) ;
LOGNOTE ( " I2S mode " ) ;
# if RASPPI==5
// Quad DAC 8-channel mono only an option for RPI 5
m_bQuadDAC8Chan = pConfig - > GetQuadDAC8Chan ( ) ;
# endif
if ( m_bQuadDAC8Chan ) {
LOGNOTE ( " Configured for Quad DAC 8-channel Mono audio " ) ;
m_pSoundDevice = new CI2SSoundBaseDevice ( pInterrupt , pConfig - > GetSampleRate ( ) ,
pConfig - > GetChunkSize ( ) , false ,
pI2CMaster , pConfig - > GetDACI2CAddress ( ) ,
CI2SSoundBaseDevice : : DeviceModeTXOnly ,
8 ) ; // 8 channels - L+R x4 across 4 I2S lanes
}
else
{
m_pSoundDevice = new CI2SSoundBaseDevice ( pInterrupt , pConfig - > GetSampleRate ( ) ,
m_pSoundDevice = new CI2SSoundBaseDevice ( pInterrupt , pConfig - > GetSampleRate ( ) ,
pConfig - > GetChunkSize ( ) , false ,
pConfig - > GetChunkSize ( ) , false ,
pI2CMaster , pConfig - > GetDACI2CAddress ( ) ) ;
pI2CMaster , pConfig - > GetDACI2CAddress ( ) ,
CI2SSoundBaseDevice : : DeviceModeTXOnly ,
2 ) ; // 2 channels - L+R
}
}
}
else if ( strcmp ( pDeviceName , " hdmi " ) = = 0 )
else if ( strcmp ( pDeviceName , " hdmi " ) = = 0 )
{
{
@ -251,18 +268,30 @@ bool CMiniDexed::Initialize (void)
}
}
// setup and start the sound device
// setup and start the sound device
if ( ! m_pSoundDevice - > AllocateQueueFrames ( m_pConfig - > GetChunkSize ( ) ) )
int Channels = 1 ; // 16-bit Mono
# ifdef ARM_ALLOW_MULTI_CORE
if ( m_bQuadDAC8Chan )
{
Channels = 8 ; // 16-bit 8-channel mono
}
else
{
Channels = 2 ; // 16-bit Stereo
}
# endif
// Need 2 x ChunkSize / Channel queue frames as the audio driver uses
// two DMA channels each of ChunkSize and one single single frame
// contains a sample for each of all the channels.
//
// See discussion here: https://github.com/rsta2/circle/discussions/453
if ( ! m_pSoundDevice - > AllocateQueueFrames ( 2 * m_pConfig - > GetChunkSize ( ) / Channels ) )
{
{
LOGERR ( " Cannot allocate sound queue " ) ;
LOGERR ( " Cannot allocate sound queue " ) ;
return false ;
return false ;
}
}
# ifndef ARM_ALLOW_MULTI_CORE
m_pSoundDevice - > SetWriteFormat ( SoundFormatSigned16 , Channels ) ;
m_pSoundDevice - > SetWriteFormat ( SoundFormatSigned16 , 1 ) ; // 16-bit Mono
# else
m_pSoundDevice - > SetWriteFormat ( SoundFormatSigned16 , 2 ) ; // 16-bit Stereo
# endif
m_nQueueSizeFrames = m_pSoundDevice - > GetQueueSizeFrames ( ) ;
m_nQueueSizeFrames = m_pSoundDevice - > GetQueueSizeFrames ( ) ;
@ -1128,6 +1157,48 @@ void CMiniDexed::ProcessSound (void)
assert ( CConfig : : ToneGenerators = = 8 ) ;
assert ( CConfig : : ToneGenerators = = 8 ) ;
if ( m_bQuadDAC8Chan ) {
// No mixing is performed by MiniDexed, sound is output in 8 channels.
// Note: one TG per audio channel; output=mono; no processing.
const int Channels = 8 ; // One TG per channel
float32_t tmp_float [ nFrames * Channels ] ;
int16_t tmp_int [ nFrames * Channels ] ;
if ( nMasterVolume > 0.0 )
{
// Convert dual float array (8 chan) to single int16 array (8 chan)
for ( uint16_t i = 0 ; i < nFrames ; i + + )
{
// TGs will alternate on L/R channels for each output
// reading directly from the TG OutputLevel buffer with
// no additional processing.
for ( uint8_t tg = 0 ; tg < Channels ; tg + + )
{
if ( nMasterVolume > 0.0 & & nMasterVolume < 1.0 )
{
tmp_float [ ( i * Channels ) + tg ] = m_OutputLevel [ tg ] [ i ] * nMasterVolume ;
}
else if ( nMasterVolume = = 1.0 )
{
tmp_float [ ( i * Channels ) + tg ] = m_OutputLevel [ tg ] [ i ] ;
}
}
}
arm_float_to_q15 ( tmp_float , tmp_int , nFrames * Channels ) ;
}
else
{
arm_fill_q15 ( 0 , tmp_int , nFrames * Channels ) ;
}
if ( m_pSoundDevice - > Write ( tmp_int , sizeof ( tmp_int ) ) ! = ( int ) sizeof ( tmp_int ) )
{
LOGERR ( " Sound data dropped " ) ;
}
}
else
{
// Mix everything down to stereo
uint8_t indexL = 0 , indexR = 1 ;
uint8_t indexL = 0 , indexR = 1 ;
// BEGIN TG mixing
// BEGIN TG mixing
@ -1201,12 +1272,15 @@ void CMiniDexed::ProcessSound (void)
arm_float_to_q15 ( tmp_float , tmp_int , nFrames * 2 ) ;
arm_float_to_q15 ( tmp_float , tmp_int , nFrames * 2 ) ;
}
}
else
else
{
arm_fill_q15 ( 0 , tmp_int , nFrames * 2 ) ;
arm_fill_q15 ( 0 , tmp_int , nFrames * 2 ) ;
}
if ( m_pSoundDevice - > Write ( tmp_int , sizeof ( tmp_int ) ) ! = ( int ) sizeof ( tmp_int ) )
if ( m_pSoundDevice - > Write ( tmp_int , sizeof ( tmp_int ) ) ! = ( int ) sizeof ( tmp_int ) )
{
{
LOGERR ( " Sound data dropped " ) ;
LOGERR ( " Sound data dropped " ) ;
}
}
} // End of Stereo mixing
if ( m_bProfileEnabled )
if ( m_bProfileEnabled )
{
{