From 8f8552f3e7a8caa5a7843565e052ef6a4ed8b363 Mon Sep 17 00:00:00 2001 From: Rene Stange Date: Sun, 20 Mar 2022 21:32:12 +0100 Subject: [PATCH] Add detune and Stereo balance (#51), closes #13 * Add master tune parameter to UI * Add Stereo balance (pan) setting --- src/minidexed.cpp | 84 +++++++++++++++++++++++++++++++++++++------ src/minidexed.h | 4 +++ src/userinterface.cpp | 77 +++++++++++++++++++++++++++++++++++++++ src/userinterface.h | 6 ++++ 4 files changed, 160 insertions(+), 11 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 762cf3d..df37609 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -41,6 +41,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_SerialMIDI (this, pInterrupt, pConfig), m_bUseSerial (false), m_pSoundDevice (0), +#ifdef ARM_ALLOW_MULTI_CORE + m_nActiveTGsLog2 (0), +#endif m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()) @@ -50,6 +53,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned i = 0; i < CConfig::ToneGenerators; i++) { m_nVoiceBankID[i] = 0; + m_nPan[i] = 64; m_pTG[i] = new CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ()); assert (m_pTG[i]); @@ -138,7 +142,11 @@ bool CMiniDexed::Initialize (void) return false; } +#ifndef ARM_ALLOW_MULTI_CORE m_pSoundDevice->SetWriteFormat (SoundFormatSigned16, 1); // 16-bit Mono +#else + m_pSoundDevice->SetWriteFormat (SoundFormatSigned16, 2); // 16-bit Stereo +#endif m_nQueueSizeFrames = m_pSoundDevice->GetQueueSizeFrames (); @@ -291,6 +299,33 @@ void CMiniDexed::SetVolume (unsigned nVolume, unsigned nTG) m_UI.VolumeChanged (nVolume, nTG); } +void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) +{ + if (nPan > 127) + { + return; + } + + assert (nTG < CConfig::ToneGenerators); + m_nPan[nTG] = nPan; + + m_UI.PanChanged (nPan, nTG); +} + +void CMiniDexed::SetMasterTune (int nMasterTune, unsigned nTG) +{ + if (!(-99 <= nMasterTune && nMasterTune <= 99)) + { + return; + } + + assert (nTG < CConfig::ToneGenerators); + assert (m_pTG[nTG]); + m_pTG[nTG]->setMasterTune ((int8_t) nMasterTune); + + m_UI.MasterTuneChanged (nMasterTune, nTG); +} + void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) { assert (nTG < CConfig::ToneGenerators); @@ -308,6 +343,21 @@ void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) m_SerialMIDI.SetChannel (uchChannel, nTG); } +#ifdef ARM_ALLOW_MULTI_CORE + unsigned nActiveTGs = 0; + for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + { + if (m_PCKeyboard.GetChannel (nTG) != CMIDIDevice::Disabled) + { + nActiveTGs++; + } + } + + assert (nActiveTGs <= 8); + static const unsigned Log2[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; + m_nActiveTGsLog2 = Log2[nActiveTGs]; +#endif + m_UI.MIDIChannelChanged (uchChannel, nTG); } @@ -438,20 +488,32 @@ void CMiniDexed::ProcessSound (void) } // now mix the output of all TGs - int16_t SampleBuffer[nFrames]; + int16_t SampleBuffer[nFrames][2]; 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); + int32_t nLeft = m_OutputLevel[0][i] * (127-m_nPan[0]) + + m_OutputLevel[1][i] * (127-m_nPan[1]) + + m_OutputLevel[2][i] * (127-m_nPan[2]) + + m_OutputLevel[3][i] * (127-m_nPan[3]) + + m_OutputLevel[4][i] * (127-m_nPan[4]) + + m_OutputLevel[5][i] * (127-m_nPan[5]) + + m_OutputLevel[6][i] * (127-m_nPan[6]) + + m_OutputLevel[7][i] * (127-m_nPan[7]); + nLeft >>= m_nActiveTGsLog2 + 7; + + int32_t nRight = m_OutputLevel[0][i] * m_nPan[0] + + m_OutputLevel[1][i] * m_nPan[1] + + m_OutputLevel[2][i] * m_nPan[2] + + m_OutputLevel[3][i] * m_nPan[3] + + m_OutputLevel[4][i] * m_nPan[4] + + m_OutputLevel[5][i] * m_nPan[5] + + m_OutputLevel[6][i] * m_nPan[6] + + m_OutputLevel[7][i] * m_nPan[7]; + nRight >>= m_nActiveTGsLog2 + 7; + + SampleBuffer[i][0] = (int16_t) nLeft; + SampleBuffer[i][1] = (int16_t) nRight; } if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer) diff --git a/src/minidexed.h b/src/minidexed.h index 144e53b..b592af7 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -59,6 +59,8 @@ public: void BankSelectLSB (unsigned nBankLSB, unsigned nTG); void ProgramChange (unsigned nProgram, unsigned nTG); void SetVolume (unsigned nVolume, unsigned nTG); + void SetPan (unsigned nPan, unsigned nTG); // 0 .. 127 + void SetMasterTune (int nMasterTune, unsigned nTG); // -99 .. 99 void SetMIDIChannel (uint8_t uchChannel, unsigned nTG); void keyup (int16_t pitch, unsigned nTG); @@ -90,6 +92,7 @@ private: CDexedAdapter *m_pTG[CConfig::ToneGenerators]; unsigned m_nVoiceBankID[CConfig::ToneGenerators]; + unsigned m_nPan[CConfig::ToneGenerators]; CUserInterface m_UI; CSysExFileLoader m_SysExFileLoader; @@ -103,6 +106,7 @@ private: unsigned m_nQueueSizeFrames; #ifdef ARM_ALLOW_MULTI_CORE + unsigned m_nActiveTGsLog2; volatile TCoreStatus m_CoreStatus[CORES]; volatile unsigned m_nFramesToProcess; int16_t m_OutputLevel[CConfig::ToneGenerators][CConfig::MaxChunkSize]; diff --git a/src/userinterface.cpp b/src/userinterface.cpp index ee9bf4b..2df0fdc 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -44,6 +44,8 @@ CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManag m_nBank[nTG] = 0; m_nProgram[nTG] = 0; m_nVolume[nTG] = 0; + m_nPan[nTG] = 64; + m_nMasterTune[nTG] = 0; m_uchMIDIChannel[nTG] = CMIDIDevice::Disabled; } } @@ -184,6 +186,51 @@ void CUserInterface::VolumeChanged (unsigned nVolume, unsigned nTG) } } +void CUserInterface::PanChanged (unsigned nPan, unsigned nTG) +{ + assert (nPan < 128); + assert (nTG < CConfig::ToneGenerators); + m_nPan[nTG] = nPan; + + if ( m_UIMode == UIModePan + && m_nTG == nTG) + { + CString TG; + TG.Format ("TG%u", nTG+1); + + char PanMarker[CConfig::LCDColumns+1]; + memset (PanMarker, '.', CConfig::LCDColumns); + PanMarker[CConfig::LCDColumns] = '\0'; + unsigned nIndex = nPan * CConfig::LCDColumns / 127; + if (nIndex == CConfig::LCDColumns) + { + nIndex--; + } + PanMarker[nIndex] = '\xFF'; + + DisplayWrite (TG, "PAN", PanMarker); + } +} + +void CUserInterface::MasterTuneChanged (int nMasterTune, unsigned nTG) +{ + assert (-99 <= nMasterTune && nMasterTune <= 99); + assert (nTG < CConfig::ToneGenerators); + m_nMasterTune[nTG] = nMasterTune; + + if ( m_UIMode == UIModeMasterTune + && m_nTG == nTG) + { + CString TG; + TG.Format ("TG%u", nTG+1); + + CString String; + String.Format ("%d", nMasterTune); + + DisplayWrite (TG, "MASTER TUNE", "DETUNE", (const char *) String); + } +} + void CUserInterface::MIDIChannelChanged (uint8_t uchChannel, unsigned nTG) { assert (nTG < CConfig::ToneGenerators); @@ -344,6 +391,36 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event) m_pMiniDexed->SetVolume (nVolume, m_nTG); } break; + case UIModePan: { + const int Increment = 128 / CConfig::LCDColumns; + + int nPan = m_nPan[m_nTG] + nStep*Increment; + if (nPan < 0) + { + nPan = 0; + } + else if (nPan > 127) + { + nPan = 127; + } + + m_pMiniDexed->SetPan (nPan, m_nTG); + } break; + + case UIModeMasterTune: { + int nMasterTune = m_nMasterTune[m_nTG] + nStep; + if (nMasterTune < -99) + { + nMasterTune = -99; + } + else if (nMasterTune > 99) + { + nMasterTune = 99; + } + + m_pMiniDexed->SetMasterTune (nMasterTune, m_nTG); + } break; + case UIModeMIDI: if ((uint8_t) (m_uchMIDIChannel[m_nTG] + nStep) < CMIDIDevice::ChannelUnknown) { diff --git a/src/userinterface.h b/src/userinterface.h index 05d7d61..3602d64 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -42,6 +42,8 @@ public: void BankSelected (unsigned nBankLSB, unsigned nTG); // 0 .. 127 void ProgramChanged (unsigned nProgram, unsigned nTG); // 0 .. 127 void VolumeChanged (unsigned nVolume, unsigned nTG); // 0 .. 127 + void PanChanged (unsigned nPan, unsigned nTG); // 0 .. 127 + void MasterTuneChanged (int nMasterTune, unsigned nTG); // -99 .. 99 void MIDIChannelChanged (uint8_t uchChannel, unsigned nTG); private: @@ -65,6 +67,8 @@ private: UIModeVoiceSelect = UIModeStart, UIModeBankSelect, UIModeVolume, + UIModePan, + UIModeMasterTune, UIModeMIDI, UIModeUnknown }; @@ -85,6 +89,8 @@ private: unsigned m_nBank[CConfig::ToneGenerators]; unsigned m_nProgram[CConfig::ToneGenerators]; unsigned m_nVolume[CConfig::ToneGenerators]; + unsigned m_nPan[CConfig::ToneGenerators]; + int m_nMasterTune[CConfig::ToneGenerators]; uint8_t m_uchMIDIChannel[CConfig::ToneGenerators]; };