From 5c70a58d193b5fecadbe39ab2cef77a0abf593fc Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 11 Jul 2025 15:39:37 +0200 Subject: [PATCH 01/10] Revert "Skip ./circle-stdlib/libs/circle/boot (it fails) (#906)" This reverts commit 1ec9cb2d4026feb0b9652ed20b6a0d982df97c8d. --- .github/workflows/build.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 696493d..0e91f21 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,15 +64,11 @@ jobs: run: | set -ex export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH - # cd ./circle-stdlib/libs/circle/boot - # make - # make armstub64 - # cd - - # cp -r ./circle-stdlib/libs/circle/boot/* sdcard - cd ./sdcard - wget https://github.com/probonopd/MiniDexed/releases/download/assets/boot.zip - unzip boot.zip && rm boot.zip - cd .. + cd ./circle-stdlib/libs/circle/boot + make + make armstub64 + cd - + cp -r ./circle-stdlib/libs/circle/boot/* sdcard rm -rf sdcard/config*.txt sdcard/README sdcard/Makefile sdcard/armstub sdcard/COPYING.linux cp ./src/config.txt ./src/minidexed.ini ./src/performance.ini sdcard/ cp ./getsysex.sh sdcard/ From 07981a42e822af2ed1ea0ae4493c09f25a56cd6c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 18:22:58 +0200 Subject: [PATCH 02/10] reverb: do not use the reverb mixer if reverb is disabled --- src/minidexed.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 51e6444..0e1c283 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1409,7 +1409,6 @@ void CMiniDexed::ProcessSound (void) for (uint8_t i = 0; i < m_nToneGenerators; i++) { tg_mixer->doAddMix(i,m_OutputLevel[i]); - reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); } // END TG mixing @@ -1425,6 +1424,11 @@ void CMiniDexed::ProcessSound (void) { float32_t ReverbBuffer[2][nFrames]; float32_t ReverbSendBuffer[2][nFrames]; + + for (uint8_t i = 0; i < m_nToneGenerators; i++) + { + reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); + } arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames); arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames); From b0e7f24c1af198517a1c5bbbed08a6c253cd62fc Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 18:24:59 +0200 Subject: [PATCH 03/10] reverb: do not fill the reverb buffers unnecessarily they will be overwritten later --- src/minidexed.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 0e1c283..1b5b4f6 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1430,11 +1430,6 @@ void CMiniDexed::ProcessSound (void) reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); } - arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames); - arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames); - arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames); - arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames); - m_ReverbSpinLock.Acquire (); reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]); From 952a7b776f3ede3c2bca003b961a60723c961e5c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 19:15:03 +0200 Subject: [PATCH 04/10] mixer: use the buffer directly, do not copy --- src/effect_mixer.hpp | 14 ++++++++++++++ src/minidexed.cpp | 22 ++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 44184ab..78efbb4 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -168,6 +168,20 @@ public: arm_fill_f32(0.0f, sumbufR, buffer_length); } + void getBuffers(float32_t (*buffers[2])) + { + buffers[0] = sumbufL; + buffers[1] = sumbufR; + } + + void zeroFill() + { + if(sumbufL) + arm_fill_f32(0.0f, sumbufL, buffer_length); + if(sumbufR) + arm_fill_f32(0.0f, sumbufR, buffer_length); + } + protected: using AudioMixer::sumbufL; using AudioMixer::multiplier; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 1b5b4f6..c4aa1b8 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1406,25 +1406,28 @@ void CMiniDexed::ProcessSound (void) if(nMasterVolume > 0.0) { + // get the mix buffer of all TGs + float32_t (*SampleBuffer[2]); + tg_mixer->getBuffers(SampleBuffer); + + tg_mixer->zeroFill(); + for (uint8_t i = 0; i < m_nToneGenerators; i++) { tg_mixer->doAddMix(i,m_OutputLevel[i]); } // END TG mixing - // BEGIN create SampleBuffer for holding audio data - float32_t SampleBuffer[2][nFrames]; - // END create SampleBuffer for holding audio data - - // get the mix of all TGs - tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]); - // BEGIN adding reverb if (m_nParameter[ParameterReverbEnable]) { float32_t ReverbBuffer[2][nFrames]; - float32_t ReverbSendBuffer[2][nFrames]; - + + float32_t (*ReverbSendBuffer[2]); + reverb_send_mixer->getBuffers(ReverbSendBuffer); + + reverb_send_mixer->zeroFill(); + for (uint8_t i = 0; i < m_nToneGenerators; i++) { reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); @@ -1432,7 +1435,6 @@ void CMiniDexed::ProcessSound (void) m_ReverbSpinLock.Acquire (); - reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]); reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames); // scale down and add left reverb buffer by reverb level From eb80d99bcc931bbfefe7a4a44d2008a13af0f2da Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 20:47:53 +0200 Subject: [PATCH 05/10] mixer: remove the unused and buggy 3 parameter doAddMix() It doesn't work well if multiplier[channel]==UNITY_GAIN --- src/effect_mixer.hpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 78efbb4..2cf3586 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -135,23 +135,6 @@ public: arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } - void doAddMix(uint8_t channel, float32_t* inL, float32_t* inR) - { - float32_t tmp[buffer_length]; - - assert(inL); - assert(inR); - - // left - if(multiplier[channel]!=UNITY_GAIN) - arm_scale_f32(inL,multiplier[channel],tmp,buffer_length); - arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); - // right - if(multiplier[channel]!=UNITY_GAIN) - arm_scale_f32(inR,multiplier[channel],tmp,buffer_length); - arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); - } - void getMix(float32_t* bufferL, float32_t* bufferR) { assert(bufferR); From 0c1696a2ecf14bfce47a397f8dc8aa3d0f4425c9 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 20:52:56 +0200 Subject: [PATCH 06/10] mixer: prescale the scale parameter so one scale per element is enough --- src/effect_mixer.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 2cf3586..9cf5070 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -124,14 +124,10 @@ public: assert(in); // left - arm_scale_f32(in, panorama[channel][0], tmp, buffer_length); - if(multiplier[channel]!=UNITY_GAIN) - arm_scale_f32(tmp,multiplier[channel],tmp,buffer_length); + arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length); arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); // right - arm_scale_f32(in, panorama[channel][1], tmp, buffer_length); - if(multiplier[channel]!=UNITY_GAIN) - arm_scale_f32(tmp,multiplier[channel],tmp,buffer_length); + arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length); arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } From 2a1f2b2ef84c8cd2a68f82f4f94ad9bd020940a4 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 21:12:35 +0200 Subject: [PATCH 07/10] mixer: fix pan channel order 0.0 full left 1.0 full right --- src/effect_mixer.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 9cf5070..ea0b510 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -113,8 +113,8 @@ public: pan = MIN_PANORAMA; // From: https://stackoverflow.com/questions/67062207/how-to-pan-audio-sample-data-naturally - panorama[channel][0]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); - panorama[channel][1]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); } void doAddMix(uint8_t channel, float32_t* in) From 317266ac140f34371596e342a840d71112a8bf58 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 22:56:25 +0200 Subject: [PATCH 08/10] hdmi sound: remove default channel swap as it's fixed in the pan --- src/minidexed.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index c4aa1b8..75efdfb 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -213,10 +213,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_pSoundDevice = new CHDMISoundBaseDevice (pInterrupt, pConfig->GetSampleRate (), pConfig->GetChunkSize ()); - - // The channels are swapped by default in the HDMI sound driver. - // TODO: Remove this line, when this has been fixed in the driver. - m_bChannelsSwapped = !m_bChannelsSwapped; #endif } else From 0a85ff47892450da150ddcd341e1e99767107bf3 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 10 Jul 2025 23:54:43 +0200 Subject: [PATCH 09/10] effect_mixer: add zero cross detection There is no pop when changing the volume at zero crossing. Or less if there is DC. This makes the panning less noisy. --- src/effect_mixer.hpp | 66 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index ea0b510..e16b6f5 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -22,7 +22,10 @@ public: { buffer_length=len; for (uint8_t i=0; i 0U) + { + if (*pIn >= 0 && *(pIn - 1) < 0) + return blockSize - blkCnt; + + pIn++; + blkCnt--; + } + + return blockSize; + } + void pan(uint8_t channel, float32_t pan) { if (channel >= NN) return; @@ -113,22 +139,38 @@ public: pan = MIN_PANORAMA; // From: https://stackoverflow.com/questions/67062207/how-to-pan-audio-sample-data-naturally - panorama[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); - panorama[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama_w[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama_w[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); } void doAddMix(uint8_t channel, float32_t* in) { float32_t tmp[buffer_length]; - + uint32_t zc; assert(in); - // left - arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length); - arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); - // right - arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length); - arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + if ((panorama[channel][0] != panorama_w[channel][0] || multiplier[channel] != multiplier_w[channel]) && + (zc = find_zc_f32(in, buffer_length)) != buffer_length) + { + arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, zc); + arm_scale_f32(in + zc, panorama_w[channel][0] * multiplier_w[channel], tmp + zc, buffer_length - zc); + arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); + panorama[channel][0] = panorama_w[channel][0]; + + arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, zc); + arm_scale_f32(in + zc, panorama_w[channel][1] * multiplier_w[channel], tmp + zc, buffer_length - zc); + arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + panorama[channel][1] = panorama_w[channel][1]; + + multiplier[channel] = multiplier_w[channel]; + } + else + { + arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length); + arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); + arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length); + arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + } } void getMix(float32_t* bufferL, float32_t* bufferR) @@ -164,8 +206,10 @@ public: protected: using AudioMixer::sumbufL; using AudioMixer::multiplier; + using AudioMixer::multiplier_w; using AudioMixer::buffer_length; float32_t panorama[NN][2]; + float32_t panorama_w[NN][2]; float32_t* sumbufR; }; From b68e57e106376d032be6adeda747c89eb3ff88bb Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 11 Jul 2025 20:35:51 +0200 Subject: [PATCH 10/10] patch Synth_Dexed PluginFX to use zero cross detection --- .github/workflows/build.yml | 10 +++ ...luginFX-change-gain-at-zero-crossing.patch | 73 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e91f21..cc87341 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,6 +39,11 @@ jobs: wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz tar xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz + # Patch Synth_Dexed PluginFX + - name: Patch Synth_Dexed + run: | + ( cd Synth_Dexed ; patch -p1 < ../src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch ) + - name: Build for Raspberry Pi 5 (64-bit) run: | set -ex @@ -124,6 +129,11 @@ jobs: wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz tar xf gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz + # Patch Synth_Dexed PluginFX + - name: Patch Synth_Dexed + run: | + ( cd Synth_Dexed ; patch -p1 < ../src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch ) + - name: Build for Raspberry Pi 2 (32-bit) run: | set -ex diff --git a/src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch b/src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch new file mode 100644 index 0000000..ec72f63 --- /dev/null +++ b/src/patches/0001-PluginFX-change-gain-at-zero-crossing.patch @@ -0,0 +1,73 @@ +From 7daa07bd662d1894bc312b81c6b9e79260e7a66a Mon Sep 17 00:00:00 2001 +From: Gergo Koteles +Date: Fri, 11 Jul 2025 20:28:52 +0200 +Subject: [PATCH] PluginFX change gain at zero crossing + +--- + src/PluginFx.cpp | 26 +++++++++++++++++++------- + src/PluginFx.h | 2 ++ + 2 files changed, 21 insertions(+), 7 deletions(-) + +diff --git a/src/PluginFx.cpp b/src/PluginFx.cpp +index 7c3a1ab..2b7bb9b 100644 +--- a/src/PluginFx.cpp ++++ b/src/PluginFx.cpp +@@ -56,6 +56,7 @@ PluginFx::PluginFx() { + Cutoff = 1.0; + Reso = 0.0; + Gain = 1.0; ++ aGain = 1.0; + } + + void PluginFx::init(FRAC_NUM sr) { +@@ -117,16 +118,27 @@ void PluginFx::process(float *work, uint16_t sampleSize) { + + dc_od = work[sampleSize - 1]; + +- // Gain +- if (Gain == 0.0) +- { ++ if (Gain != aGain) { + for (uint16_t i = 0; i < sampleSize; i++ ) +- work[i] = 0.0; ++ { ++ if (i != 0 && work[i] >= 0 && work[i-1] <= 0) ++ aGain = Gain; ++ work[i] *= aGain; ++ } + } +- else if ( Gain != 1.0) ++ else + { +- for (uint16_t i = 0; i < sampleSize; i++ ) +- work[i] *= Gain; ++ // Gain ++ if (aGain == 0.0) ++ { ++ for (uint16_t i = 0; i < sampleSize; i++ ) ++ work[i] = 0.0; ++ } ++ else if ( aGain != 1.0) ++ { ++ for (uint16_t i = 0; i < sampleSize; i++ ) ++ work[i] *= aGain; ++ } + } + + // don't apply the LPF if the cutoff is to maximum +diff --git a/src/PluginFx.h b/src/PluginFx.h +index 090e241..c27ccc5 100644 +--- a/src/PluginFx.h ++++ b/src/PluginFx.h +@@ -67,6 +67,8 @@ class PluginFx { + float Reso; + float Gain; + ++ float aGain; ++ + void init(FRAC_NUM sampleRate); + void process(float *work, uint16_t sampleSize); + float getGain(void); +-- +2.50.1 +