From c3132dead9b962393d5bd99880b6cd9e9fb05c16 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 11:19:33 +0200 Subject: [PATCH 001/136] midi: remove the BANK typo from MIDI_CC_BANK_SUSTAIN --- src/midi.h | 2 +- src/mididevice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/midi.h b/src/midi.h index 0e50f19b1..76e106d0c 100644 --- a/src/midi.h +++ b/src/midi.h @@ -35,7 +35,7 @@ #define MIDI_CC_PAN_POSITION 10 #define MIDI_CC_EXPRESSION 11 #define MIDI_CC_BANK_SELECT_LSB 32 -#define MIDI_CC_BANK_SUSTAIN 64 +#define MIDI_CC_SUSTAIN 64 #define MIDI_CC_PORTAMENTO 65 #define MIDI_CC_SOSTENUTO 66 #define MIDI_CC_HOLD2 69 diff --git a/src/mididevice.cpp b/src/mididevice.cpp index f6891a11a..26b42edc9 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -548,7 +548,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); break; - case MIDI_CC_BANK_SUSTAIN: + case MIDI_CC_SUSTAIN: m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); break; From 5efaf365eb95af274b3a997fa85c46eeb14b3c16 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 21:12:35 +0200 Subject: [PATCH 002/136] 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 9cf5070c5..ea0b510a2 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -113,8 +113,8 @@ template class AudioStereoMixer : public AudioMixer 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 52f76d105a993909e9ace386475b50a5a3bcafab Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 9 Jul 2025 22:56:25 +0200 Subject: [PATCH 003/136] 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 257ef55ce..20e83aa9d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -214,10 +214,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 5037524fec2f462fc37c3d7446b9e928c7a3ac9f Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 30 Jul 2025 11:56:16 +0200 Subject: [PATCH 004/136] update Synth_Dexed to a02b5c0bf2 --- Synth_Dexed | 2 +- submod.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Synth_Dexed b/Synth_Dexed index 8c677ceb4..a02b5c0bf 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit 8c677ceb4b3fb73f8643e30ff6cf4158dc8b9e53 +Subproject commit a02b5c0bf2da132f49a923f9c69796220a8ea93f diff --git a/submod.sh b/submod.sh index 28d467bba..5c5580e90 100755 --- a/submod.sh +++ b/submod.sh @@ -18,6 +18,6 @@ cd - #cd - # Use fixed master branch of Synth_Dexed -cd Synth_Dexed/ -git checkout -f 3c683fc801 -cd - +#cd Synth_Dexed/ +#git checkout -f a02b5c0bf2da132f49a923f9c69796220a8ea93f +#cd - From e50e00a9256329132bae243867654318fd8921b9 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 25 Jul 2025 01:31:32 +0200 Subject: [PATCH 005/136] scale_zip: use f32x4x2_t --- src/arm_scale_zip_f32.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/arm_scale_zip_f32.c b/src/arm_scale_zip_f32.c index 28ff1c700..a3ac8ac7f 100644 --- a/src/arm_scale_zip_f32.c +++ b/src/arm_scale_zip_f32.c @@ -28,21 +28,21 @@ void arm_scale_zip_f32( { uint32_t blkCnt; /* Loop counter */ - f32x2x2_t res; + f32x4x2_t res; - /* Compute 2 outputs at a time */ - blkCnt = blockSize >> 1U; + /* Compute 4 outputs at a time */ + blkCnt = blockSize >> 2U; while (blkCnt > 0U) { - res.val[0] = vmul_n_f32(vld1_f32(pSrc1), scale); - res.val[1] = vmul_n_f32(vld1_f32(pSrc2), scale); - vst2_f32(pDst, res); + res.val[0] = vmulq_n_f32(vld1q_f32(pSrc1), scale); + res.val[1] = vmulq_n_f32(vld1q_f32(pSrc2), scale); + vst2q_f32(pDst, res); /* Increment pointers */ - pSrc1 += 2; - pSrc2 += 2; - pDst += 4; + pSrc1 += 4; + pSrc2 += 4; + pDst += 8; /* Decrement the loop counter */ blkCnt--; @@ -50,7 +50,7 @@ void arm_scale_zip_f32( /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ** No loop unrolling is used. */ - blkCnt = blockSize & 1; + blkCnt = blockSize & 3; while (blkCnt > 0U) { From 9dbbe75d80cafbeaee2f99f4e57ca3ce63ab2672 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 10 Jul 2025 23:54:43 +0200 Subject: [PATCH 006/136] effect_mixer: add ramping and zero cross detection Ramp the scale parameter and change it only at zero crossings to minimize pops and clicks. --- src/Makefile | 2 +- src/arm_scale_zc_ramp_f32.c | 119 ++++++++++++++++++++++++++++++++++++ src/arm_scale_zc_ramp_f32.h | 22 +++++++ src/effect_mixer.hpp | 58 ++++++++++++++++-- 4 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 src/arm_scale_zc_ramp_f32.c create mode 100644 src/arm_scale_zc_ramp_f32.h diff --git a/src/Makefile b/src/Makefile index 2aed327d1..45fd4fbee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ effect_platervbstereo.o uibuttons.o midipin.o \ - arm_float_to_q23.o arm_scale_zip_f32.o \ + arm_float_to_q23.o arm_scale_zc_ramp_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o OPTIMIZE = -O3 diff --git a/src/arm_scale_zc_ramp_f32.c b/src/arm_scale_zc_ramp_f32.c new file mode 100644 index 000000000..933437c71 --- /dev/null +++ b/src/arm_scale_zc_ramp_f32.c @@ -0,0 +1,119 @@ +#include "arm_scale_zc_ramp_f32.h" + +const float32_t RAMP_DT = 1.0 / 254; +const float32_t RAMP_EPS = 1.0 / 127; + +/** +* @brief Scale a floating-point vector with a scalar and scalar2 after a zero cross. +* @param[in] pSrc points to the input vector 1 +* @param[in] scale1 scale1 scalar +* @param[in] scale2 scale2 scalar +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ + +#if defined(ARM_MATH_NEON_EXPERIMENTAL) + +static inline int +v_any_u32(uint32x4_t d) +{ + return vpaddd_u64(vreinterpretq_u64_u32(d)) != 0; +} + +void arm_scale_zc_ramp_f32( + const float32_t * pSrc, + float32_t * pScale, + float32_t dScale, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + float32_t scale = *pScale; + + f32x4_t res; + + blkCnt = blockSize >> 2U; + + while (blkCnt > 0U) + { + res = vmulq_n_f32(vld1q_f32(pSrc), scale); + vst1q_f32(pDst, res); + + pSrc += 4; + pDst += 4; + + /* Decrement the loop counter */ + blkCnt--; + + if (scale != dScale && blkCnt) + { + f32x4_t resn1 = vld1q_f32(pSrc-3); + + // this probably runs faster, but does not find all zc + // so ramping is a bit slower + //if (vminnmvq_f32(res) <= 0 && vmaxnmvq_f32(res) >= 0) + + if (v_any_u32(vorrq_u32( + vandq_u32(vcgezq_f32(res), vclezq_f32(resn1)), + vandq_u32(vclezq_f32(res), vcgezq_f32(resn1)) + ))) + { + scale += dScale > scale ? RAMP_DT : -RAMP_DT; + if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; + } + } + } + + /* If the blockSize is not a multiple of 4, compute any remaining output samples here. + ** No loop unrolling is used. */ + blkCnt = blockSize & 3; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc++ * scale; + + /* Decrement the loop counter */ + blkCnt--; + + if (blkCnt && scale != dScale && (*(pSrc-1) <= 0 && *pSrc >= 0 || *(pSrc-1) >= 0 && *pSrc <= 0)) + { + scale += dScale > scale ? RAMP_DT : -RAMP_DT; + if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; + } + } + + *pScale = scale; +} + +#else + +void arm_scale_zc_ramp_f32( + const float32_t * pSrc, + float32_t * pScale, + float32_t dScale, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + float32_t scale = *pScale; + + blkCnt = blockSize; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc++ * scale; + + /* Decrement the loop counter */ + blkCnt--; + + if (blkCnt && scale != dScale && (*(pSrc-1) <= 0 && *pSrc >= 0 || *(pSrc-1) >= 0 && *pSrc <= 0)) + { + scale += dScale > scale ? RAMP_DT : -RAMP_DT; + if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; + } + } + + *pScale = scale; +} + +#endif diff --git a/src/arm_scale_zc_ramp_f32.h b/src/arm_scale_zc_ramp_f32.h new file mode 100644 index 000000000..6e7d51702 --- /dev/null +++ b/src/arm_scale_zc_ramp_f32.h @@ -0,0 +1,22 @@ +#pragma once + +#include "arm_math_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** +* @brief Scale a floating-point vector with a scalar and scalar2 after a zero cross. +* @param[in] pSrc points to the input vector 1 +* @param[inout] pScale points to actual scale scalar +* @param[in] dScale destination scale scalar +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ +void arm_scale_zc_ramp_f32(const float32_t * pSrc, float32_t * pScale, float32_t dScale, float32_t * pDst, uint32_t blockSize); + +#ifdef __cplusplus +} +#endif diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index ea0b510a2..f229ed35d 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -7,6 +7,7 @@ #include #include #include "arm_math.h" +#include "arm_scale_zc_ramp_f32.h" #define UNITY_GAIN 1.0f #define MAX_GAIN 1.0f @@ -57,13 +58,15 @@ template class AudioMixer void gain(float32_t gain) { + float32_t gain4 = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + for (uint8_t i = 0; i < NN; i++) { if (gain > MAX_GAIN) gain = MAX_GAIN; else if (gain < MIN_GAIN) gain = MIN_GAIN; - multiplier[i] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + multiplier[i] = gain4; } } @@ -92,6 +95,8 @@ template class AudioStereoMixer : public AudioMixer { panorama[i][0] = UNITY_PANORAMA; panorama[i][1] = UNITY_PANORAMA; + mp[i][0] = mp_w[i][0] = UNITY_GAIN * UNITY_PANORAMA; + mp[i][1] = mp_w[i][1] = UNITY_GAIN * UNITY_PANORAMA; } sumbufR=new float32_t[buffer_length]; @@ -103,6 +108,37 @@ template class AudioStereoMixer : public AudioMixer delete [] sumbufR; } + void gain(uint8_t channel, float32_t gain) + { + if (channel >= NN) return; + + if (gain > MAX_GAIN) + gain = MAX_GAIN; + else if (gain < MIN_GAIN) + gain = MIN_GAIN; + multiplier[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + + mp_w[channel][0] = multiplier[channel] * panorama[channel][0]; + mp_w[channel][1] = multiplier[channel] * panorama[channel][1]; + } + + void gain(float32_t gain) + { + float32_t gain4 = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + + for (uint8_t i = 0; i < NN; i++) + { + if (gain > MAX_GAIN) + gain = MAX_GAIN; + else if (gain < MIN_GAIN) + gain = MIN_GAIN; + multiplier[i] = gain4; + + mp_w[i][0] = multiplier[i] * panorama[i][0]; + mp_w[i][1] = multiplier[i] * panorama[i][1]; + } + } + void pan(uint8_t channel, float32_t pan) { if (channel >= NN) return; @@ -115,6 +151,9 @@ template class AudioStereoMixer : public AudioMixer // 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)); + + mp_w[channel][0] = multiplier[channel] * panorama[channel][0]; + mp_w[channel][1] = multiplier[channel] * panorama[channel][1]; } void doAddMix(uint8_t channel, float32_t* in) @@ -123,11 +162,18 @@ template class AudioStereoMixer : public AudioMixer assert(in); - // left - arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length); + if (mp[channel][0] == mp_w[channel][0]) + arm_scale_f32(in, mp[channel][0], tmp, buffer_length); + else + arm_scale_zc_ramp_f32(in, &mp[channel][0], mp_w[channel][0], tmp, buffer_length); + arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); - // right - arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length); + + if (mp[channel][1] == mp_w[channel][1]) + arm_scale_f32(in, mp[channel][1], tmp, buffer_length); + else + arm_scale_zc_ramp_f32(in, &mp[channel][1], mp_w[channel][1], tmp, buffer_length); + arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } @@ -166,6 +212,8 @@ template class AudioStereoMixer : public AudioMixer using AudioMixer::multiplier; using AudioMixer::buffer_length; float32_t panorama[NN][2]; + float32_t mp[NN][2]; + float32_t mp_w[NN][2]; float32_t* sumbufR; }; From b6f2c6a7521db53039a77a498febfd2e1da0d304 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 22 Jul 2025 01:54:44 +0200 Subject: [PATCH 007/136] ramp the MasterVolume at zero crossings --- src/Makefile | 2 +- src/arm_zip_f32.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ src/arm_zip_f32.h | 21 ++++++++++++ src/minidexed.cpp | 21 +++++++++--- src/minidexed.h | 6 ++-- 5 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 src/arm_zip_f32.c create mode 100644 src/arm_zip_f32.h diff --git a/src/Makefile b/src/Makefile index 45fd4fbee..36a49377b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ effect_platervbstereo.o uibuttons.o midipin.o \ - arm_float_to_q23.o arm_scale_zc_ramp_f32.o arm_scale_zip_f32.o \ + arm_float_to_q23.o arm_scale_zc_ramp_f32.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o OPTIMIZE = -O3 diff --git a/src/arm_zip_f32.c b/src/arm_zip_f32.c new file mode 100644 index 000000000..012ab3d98 --- /dev/null +++ b/src/arm_zip_f32.c @@ -0,0 +1,82 @@ +#include "arm_zip_f32.h" + +/** + zip two vectors. For floating-point data, the algorithm used is: + +
+      pDst[n] = pSrc1[n], pDst[n+1] = pSrc2[n]   0 <= n < blockSize.
+  
+ + */ + +/** +* @brief Scale two floating-point vector with a scalar and zip after. +* @param[in] pSrc1 points to the input vector 1 +* @param[in] pSrc2 points to the input vector 2 +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ + +#if defined(ARM_MATH_NEON_EXPERIMENTAL) +void arm_zip_f32( + const float32_t * pSrc1, + const float32_t * pSrc2, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + + f32x4x2_t res; + + /* Compute 4 outputs at a time */ + blkCnt = blockSize >> 2U; + + while (blkCnt > 0U) + { + res.val[0] = vld1q_f32(pSrc1); + res.val[1] = vld1q_f32(pSrc2); + vst2q_f32(pDst, res); + + /* Increment pointers */ + pSrc1 += 4; + pSrc2 += 4; + pDst += 8; + + /* Decrement the loop counter */ + blkCnt--; + } + + /* If the blockSize is not a multiple of 4, compute any remaining output samples here. + ** No loop unrolling is used. */ + blkCnt = blockSize & 3; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc1++; + *pDst++ = *pSrc2++; + + /* Decrement the loop counter */ + blkCnt--; + } +} +#else +void arm_zip_f32( + const float32_t * pSrc1, + const float32_t * pSrc2, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + + blkCnt = blockSize; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc1++; + *pDst++ = *pSrc2++; + + /* Decrement the loop counter */ + blkCnt--; + } +} +#endif diff --git a/src/arm_zip_f32.h b/src/arm_zip_f32.h new file mode 100644 index 000000000..61a09c995 --- /dev/null +++ b/src/arm_zip_f32.h @@ -0,0 +1,21 @@ +#pragma once + +#include "arm_math_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** +* @brief zip two floating-point vector. +* @param[in] pSrc1 points to the input vector 1 +* @param[in] pSrc2 points to the input vector 2 +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ +void arm_zip_f32(const float32_t * pSrc1, const float32_t * pSrc2, float32_t * pDst, uint32_t blockSize); + +#ifdef __cplusplus +} +#endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 20e83aa9d..d6b6374ac 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -30,7 +30,9 @@ #include #include #include "arm_float_to_q23.h" +#include "arm_scale_zc_ramp_f32.h" #include "arm_scale_zip_f32.h" +#include "arm_zip_f32.h" const char WLANFirmwarePath[] = "SD:firmware/"; const char WLANConfigFile[] = "SD:wpa_supplicant.conf"; @@ -50,6 +52,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_PerformanceConfig (pFileSystem), m_PCKeyboard (this, pConfig, &m_UI), m_SerialMIDI (this, pInterrupt, pConfig, &m_UI), + m_fMasterVolume{}, + m_fMasterVolumeW(0), m_bUseSerial (false), m_bQuadDAC8Chan (false), m_pSoundDevice (0), @@ -1359,7 +1363,7 @@ void CMiniDexed::ProcessSound (void) // no additional processing. for (uint8_t tg = 0; tg < Channels; tg++) { - tmp_float[(i*Channels)+tg]=m_OutputLevel[tg][i] * nMasterVolume; + tmp_float[(i*Channels)+tg]=m_OutputLevel[tg][i] * m_fMasterVolumeW; } } @@ -1437,8 +1441,17 @@ void CMiniDexed::ProcessSound (void) indexR=0; } - // Convert dual float array (left, right) to single int16 array (left/right) - arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], nMasterVolume, tmp_float, nFrames); + // Convert dual float array (left, right) to single int32 (q23) array (left/right) + if (m_fMasterVolume[0] == m_fMasterVolumeW && m_fMasterVolume[1] == m_fMasterVolumeW) + { + arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], m_fMasterVolumeW, tmp_float, nFrames); + } + else + { + arm_scale_zc_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], m_fMasterVolumeW, SampleBuffer[0], nFrames); + arm_scale_zc_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], m_fMasterVolumeW, SampleBuffer[1], nFrames); + arm_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], tmp_float, nFrames); + } arm_float_to_q23(tmp_float,tmp_int,nFrames*2); @@ -1856,7 +1869,7 @@ void CMiniDexed::setMasterVolume(float32_t vol) // Apply logarithmic scaling to match perceived loudness vol = powf(vol, 2.0f); - nMasterVolume = vol; + m_fMasterVolumeW = vol; } std::string CMiniDexed::GetPerformanceFileName(unsigned nID) diff --git a/src/minidexed.h b/src/minidexed.h index 225f1620c..181d2407f 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -238,7 +238,7 @@ class CMiniDexed bool DoSavePerformance (void); void setMasterVolume (float32_t vol); - int GetMasterVolume127() const { return (int)(nMasterVolume >= 1.0f ? 127 : (nMasterVolume <= 0.0f ? 0 : sqrtf(nMasterVolume) * 127.0f)); } + int GetMasterVolume127() const { return m_fMasterVolumeW >= 1.0f ? 127 : (m_fMasterVolumeW <= 0.0f ? 0 : sqrtf(m_fMasterVolumeW) * 127.0f); } bool InitNetwork(); void UpdateNetwork(); @@ -307,8 +307,6 @@ class CMiniDexed uint8_t m_nRawVoiceData[156]; - - float32_t nMasterVolume; CUserInterface m_UI; CSysExFileLoader m_SysExFileLoader; @@ -317,6 +315,8 @@ class CMiniDexed CMIDIKeyboard *m_pMIDIKeyboard[CConfig::MaxUSBMIDIDevices]; CPCKeyboard m_PCKeyboard; CSerialMIDIDevice m_SerialMIDI; + float32_t m_fMasterVolume[8]; + float32_t m_fMasterVolumeW; bool m_bUseSerial; bool m_bQuadDAC8Chan; From 11d2f0e49cf9be093386b513385b3fa9265fae50 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 25 Jul 2025 13:47:36 +0200 Subject: [PATCH 008/136] CMiniDexed: add MasterVolume global parameter Handle MasterVolume as other global parameters to simplify code. --- src/mididevice.cpp | 5 +---- src/minidexed.cpp | 12 +++++++++--- src/minidexed.h | 2 +- src/uimenu.cpp | 42 ++++-------------------------------------- src/uimenu.h | 1 - 5 files changed, 15 insertions(+), 47 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 26b42edc9..c10fd7dfa 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -258,10 +258,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { // Convert LSB/MSB to 14-bit integer volume uint32_t nMasterVolume=((pMessage[5] & 0x7F) | ((pMessage[6] & 0x7F) <<7)); - // Convert to value between 0.0 and 1.0 - float32_t fMasterVolume = (float32_t)nMasterVolume / 16384.0; - //printf("Master volume: %f (%d)\n",fMasterVolume, nMasterVolume); - m_pSynthesizer->setMasterVolume(fMasterVolume); + m_pSynthesizer->SetParameter (CMiniDexed::ParameterMasterVolume, maplong (nMasterVolume, 0, 16383, 0, 127)); } else { diff --git a/src/minidexed.cpp b/src/minidexed.cpp index d6b6374ac..2b9108db3 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -235,9 +235,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, } #endif - float masterVolNorm = (float)(pConfig->GetMasterVolume()) / 127.0f; - setMasterVolume(masterVolNorm); - // BEGIN setup tg_mixer tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); // END setup tgmixer @@ -245,6 +242,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, // BEGIN setup reverb reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); + + SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); + SetParameter (ParameterReverbEnable, 1); SetParameter (ParameterReverbSize, 70); SetParameter (ParameterReverbHighDamp, 50); @@ -1069,6 +1069,12 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) BankSelectPerformance(nValue); break; + case ParameterMasterVolume: + nValue=constrain((int)nValue,0,127); + setMasterVolume (nValue / 127.0f); + m_UI.ParameterChanged (); + break; + default: assert (0); break; diff --git a/src/minidexed.h b/src/minidexed.h index 181d2407f..22fd5eff0 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -168,6 +168,7 @@ class CMiniDexed ParameterReverbLevel, ParameterPerformanceSelectChannel, ParameterPerformanceBank, + ParameterMasterVolume, ParameterUnknown }; @@ -238,7 +239,6 @@ class CMiniDexed bool DoSavePerformance (void); void setMasterVolume (float32_t vol); - int GetMasterVolume127() const { return m_fMasterVolumeW >= 1.0f ? 127 : (m_fMasterVolumeW <= 0.0f ? 0 : sqrtf(m_fMasterVolumeW) * 127.0f); } bool InitNetwork(); void UpdateNetwork(); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index e8342c8ab..abf8bfeeb 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -64,7 +64,7 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = #endif #endif {"Effects", MenuHandler, s_EffectsMenu}, - {"Master Volume", EditMasterVolume, 0, 0}, + {"Master Volume", EditGlobalParameter, 0, CMiniDexed::ParameterMasterVolume}, {"Performance", MenuHandler, s_PerformanceMenu}, {0} }; @@ -227,7 +227,8 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow {0, 99, 1}, // ParameterReverbDiffusion {0, 99, 1}, // ParameterReverbLevel {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel - {0, NUM_PERFORMANCE_BANKS, 1} // ParameterPerformanceBank + {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank + {0, 127, 8, ToVolume}, // ParameterMasterVolume }; // must match CMiniDexed::TTGParameter @@ -590,7 +591,7 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - const char *pMenuName = + const char *pMenuName = pUIMenu->m_nCurrentMenuDepth == 1 ? "" : pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; @@ -2063,38 +2064,3 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) nValue > rParam.Minimum, nValue < rParam.Maximum); } - -void CUIMenu::EditMasterVolume(CUIMenu *pUIMenu, TMenuEvent Event) -{ - TParameter rParam = {0, 127, 8, ToVolume}; - int nValue = pUIMenu->m_pMiniDexed->GetMasterVolume127(); - switch (Event) - { - case MenuEventUpdate: - case MenuEventUpdateParameter: - break; - case MenuEventStepDown: - nValue -= rParam.Increment; - if (nValue < rParam.Minimum) nValue = rParam.Minimum; - pUIMenu->m_pMiniDexed->setMasterVolume(nValue / 127.0f); - break; - case MenuEventStepUp: - nValue += rParam.Increment; - if (nValue > rParam.Maximum) nValue = rParam.Maximum; - pUIMenu->m_pMiniDexed->setMasterVolume(nValue / 127.0f); - break; - default: - return; - } - unsigned lcdCols = pUIMenu->m_pConfig->GetLCDColumns(); - unsigned barLen = (lcdCols > 2) ? lcdCols - 2 : 0; - std::string valueStr(barLen, '.'); - if (barLen > 0) { - size_t filled = (nValue * barLen + 63) / 127; - for (unsigned i = 0; i < barLen; ++i) { - if (i < filled) valueStr[i] = (char)0xFF; - } - } - // Do NOT add < or > here; let DisplayWrite handle it - pUIMenu->m_pUI->DisplayWrite("Master Volume", "", valueStr.c_str(), true, true); -} diff --git a/src/uimenu.h b/src/uimenu.h index 6c72f36c6..6ff6571f6 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -96,7 +96,6 @@ class CUIMenu static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); - static void EditMasterVolume (CUIMenu *pUIMenu, TMenuEvent Event); static std::string GetGlobalValueString (unsigned nParameter, int nValue); static std::string GetTGValueString (unsigned nTGParameter, int nValue); From a56454b9332b575dadde5fe1863e82afca3dd34a Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 12:27:27 +0200 Subject: [PATCH 009/136] CMiniDexed: member initialize pointers to nullptr --- src/minidexed.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2b9108db3..41374456e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -50,13 +50,14 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_pConfig (pConfig), m_UI (this, pGPIOManager, pI2CMaster, pSPIMaster, pConfig), m_PerformanceConfig (pFileSystem), + m_pMIDIKeyboard {}, m_PCKeyboard (this, pConfig, &m_UI), m_SerialMIDI (this, pInterrupt, pConfig, &m_UI), m_fMasterVolume{}, m_fMasterVolumeW(0), m_bUseSerial (false), m_bQuadDAC8Chan (false), - m_pSoundDevice (0), + m_pSoundDevice (nullptr), m_bChannelsSwapped (pConfig->GetChannelsSwapped ()), #ifdef ARM_ALLOW_MULTI_CORE // m_nActiveTGsLog2 (0), @@ -64,6 +65,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), + reverb(nullptr), + tg_mixer(nullptr), + reverb_send_mixer(nullptr), m_pNet(nullptr), m_pNetDevice(nullptr), m_WLAN(nullptr), @@ -71,6 +75,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bNetworkReady(false), m_bNetworkInit(false), m_UDPMIDI(nullptr), + m_pFTPDaemon(nullptr), m_pmDNSPublisher (nullptr), m_bSavePerformance (false), m_bSavePerformanceNewFile (false), From 17396e0e9196639deca7d81627ab440ead2b1afd Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 14:23:47 +0200 Subject: [PATCH 010/136] CUIMenu: pass nWidth parameter to ToVolume functions Enable LCDColumn wide Volume and Pan adjustments and print value. --- src/config.cpp | 4 +- src/config.h | 5 +-- src/uimenu.cpp | 99 ++++++++++++++++++++++++++------------------------ src/uimenu.h | 42 ++++++++++----------- 4 files changed, 77 insertions(+), 73 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 1f817f612..e983dad78 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -144,8 +144,8 @@ void CConfig::Load (void) m_nST7789Rotation = m_Properties.GetNumber ("ST7789Rotation", 0); m_bST7789SmallFont = m_Properties.GetNumber ("ST7789SmallFont", 0) != 0; - m_nLCDColumns = m_Properties.GetNumber ("LCDColumns", 16); - m_nLCDRows = m_Properties.GetNumber ("LCDRows", 2); + m_nLCDColumns = std::max(MinLCDColumns, m_Properties.GetNumber ("LCDColumns", 16)); + m_nLCDRows = std::max(MinLCDRows, m_Properties.GetNumber ("LCDRows", 2)); m_nButtonPinPrev = m_Properties.GetNumber ("ButtonPinPrev", 0); m_nButtonPinNext = m_Properties.GetNumber ("ButtonPinNext", 0); diff --git a/src/config.h b/src/config.h index aaf247623..add609619 100644 --- a/src/config.h +++ b/src/config.h @@ -89,9 +89,8 @@ class CConfig // Configuration for MiniDexed static const unsigned MaxUSBMIDIDevices = 4; #endif - // TODO - Leave this for uimenu.cpp for now, but it will need to be dynamic at some point... - static const unsigned LCDColumns = 16; // HD44780 LCD - static const unsigned LCDRows = 2; + static const unsigned MinLCDColumns = 16; // HD44780 LCD + static const unsigned MinLCDRows = 2; public: CConfig (FATFS *pFileSystem); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index abf8bfeeb..13c50c6bb 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -595,7 +595,9 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - string Value = GetGlobalValueString (Param, pUIMenu->m_pMiniDexed->GetParameter (Param)); + string Value = GetGlobalValueString (Param, + pUIMenu->m_pMiniDexed->GetParameter (Param), + pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, @@ -780,7 +782,9 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) string TG ("TG"); TG += to_string (nTG+1); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, @@ -834,7 +838,9 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me string TG ("TG"); TG += to_string (nTG+1); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, @@ -888,7 +894,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) string TG ("TG"); TG += to_string (nTG+1); - string Value = GetVoiceValueString (nParam, nValue); + string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, @@ -991,7 +997,7 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) } else { - Value = GetOPValueString (nParam, nValue); + Value = GetOPValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); } pUIMenu->m_pUI->DisplayWrite (OP.c_str (), @@ -1021,7 +1027,7 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); } -string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue) +string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue, int nWidth) { string Result; @@ -1030,7 +1036,7 @@ string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue) CUIMenu::TToString *pToString = CUIMenu::s_GlobalParameter[nParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { @@ -1040,7 +1046,7 @@ string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue) return Result; } -string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue) +string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nWidth) { string Result; @@ -1049,7 +1055,7 @@ string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue) CUIMenu::TToString *pToString = CUIMenu::s_TGParameter[nTGParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { @@ -1059,7 +1065,7 @@ string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue) return Result; } -string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue) +string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth) { string Result; @@ -1068,7 +1074,7 @@ string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue) CUIMenu::TToString *pToString = CUIMenu::s_VoiceParameter[nVoiceParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { @@ -1078,7 +1084,7 @@ string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue) return Result; } -string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue) +string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue, int nWidth) { string Result; @@ -1087,7 +1093,7 @@ string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue) CUIMenu::TToString *pToString = CUIMenu::s_OPParameter[nOPParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { @@ -1097,34 +1103,31 @@ string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue) return Result; } -string CUIMenu::ToVolume (int nValue) +string CUIMenu::ToVolume (int nValue, int nWidth) { - constexpr size_t NumSquares = 14; - char VolumeBar[NumSquares + 1]; - size_t filled = (nValue * NumSquares + 63) / 127; - for (size_t i = 0; i < NumSquares; ++i) { - VolumeBar[i] = (i < filled) ? (char)0xFF : '.'; - } - VolumeBar[NumSquares] = '\0'; - return VolumeBar; + char buf[nWidth + 1]; + unsigned nBarWidth = nWidth - 3; + unsigned nFillWidth = (nValue * nBarWidth + 63) / 127; + unsigned nDotWidth = nBarWidth - nFillWidth; + std::fill_n(buf, nFillWidth, 0xFF); + std::fill_n(buf + nFillWidth, nDotWidth, '.'); + snprintf(buf + nFillWidth + nDotWidth, 4, "%3d", nValue); + return buf; } -string CUIMenu::ToPan (int nValue) +string CUIMenu::ToPan (int nValue, int nWidth) { - assert (CConfig::LCDColumns == 16); - static const size_t MaxChars = CConfig::LCDColumns-3; - char PanMarker[MaxChars+1] = "......:......"; - unsigned nIndex = nValue * MaxChars / 127; - if (nIndex == MaxChars) - { - nIndex--; - } - PanMarker[nIndex] = '\xFF'; // 0xFF is the block character - - return PanMarker; + char buf[nWidth + 1]; + unsigned nBarWidth = nWidth - 3; + unsigned nIndex = std::min(nValue * nBarWidth / 127, nBarWidth - 1); + std::fill_n(buf, nBarWidth, '.'); + buf[nBarWidth / 2] = ':'; + buf[nIndex] = 0xFF; // 0xFF is the block character + snprintf(buf + nBarWidth, 4, "%3d", nValue); + return buf; } -string CUIMenu::ToMIDIChannel (int nValue) +string CUIMenu::ToMIDIChannel (int nValue, int nWidth) { switch (nValue) { @@ -1134,12 +1137,12 @@ string CUIMenu::ToMIDIChannel (int nValue) } } -string CUIMenu::ToAlgorithm (int nValue) +string CUIMenu::ToAlgorithm (int nValue, int nWidth) { return to_string (nValue + 1); } -string CUIMenu::ToOnOff (int nValue) +string CUIMenu::ToOnOff (int nValue, int nWidth) { static const char *OnOff[] = {"Off", "On"}; @@ -1148,7 +1151,7 @@ string CUIMenu::ToOnOff (int nValue) return OnOff[nValue]; } -string CUIMenu::ToLFOWaveform (int nValue) +string CUIMenu::ToLFOWaveform (int nValue, int nWidth) { static const char *Waveform[] = {"Triangle", "Saw down", "Saw up", "Square", "Sine", "Sample/Hold"}; @@ -1158,7 +1161,7 @@ string CUIMenu::ToLFOWaveform (int nValue) return Waveform[nValue]; } -string CUIMenu::ToTransposeNote (int nValue) +string CUIMenu::ToTransposeNote (int nValue, int nWidth) { nValue += NoteC3 - 24; @@ -1167,14 +1170,14 @@ string CUIMenu::ToTransposeNote (int nValue) return s_NoteName[nValue]; } -string CUIMenu::ToBreakpointNote (int nValue) +string CUIMenu::ToBreakpointNote (int nValue, int nWidth) { assert ((unsigned) nValue < sizeof s_NoteName / sizeof s_NoteName[0]); return s_NoteName[nValue]; } -string CUIMenu::ToKeyboardCurve (int nValue) +string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) { static const char *Curve[] = {"-Lin", "-Exp", "+Exp", "+Lin"}; @@ -1183,7 +1186,7 @@ string CUIMenu::ToKeyboardCurve (int nValue) return Curve[nValue]; } -string CUIMenu::ToOscillatorMode (int nValue) +string CUIMenu::ToOscillatorMode (int nValue, int nWidth) { static const char *Mode[] = {"Ratio", "Fixed"}; @@ -1192,7 +1195,7 @@ string CUIMenu::ToOscillatorMode (int nValue) return Mode[nValue]; } -string CUIMenu::ToOscillatorDetune (int nValue) +string CUIMenu::ToOscillatorDetune (int nValue, int nWidth) { string Result; @@ -1210,7 +1213,7 @@ string CUIMenu::ToOscillatorDetune (int nValue) return Result; } -string CUIMenu::ToPortaMode (int nValue) +string CUIMenu::ToPortaMode (int nValue, int nWidth) { switch (nValue) { @@ -1220,7 +1223,7 @@ string CUIMenu::ToPortaMode (int nValue) } }; -string CUIMenu::ToPortaGlissando (int nValue) +string CUIMenu::ToPortaGlissando (int nValue, int nWidth) { switch (nValue) { @@ -1230,7 +1233,7 @@ string CUIMenu::ToPortaGlissando (int nValue) } }; -string CUIMenu::ToPolyMono (int nValue) +string CUIMenu::ToPolyMono (int nValue, int nWidth) { switch (nValue) { @@ -2056,7 +2059,9 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) string TG ("TG"); TG += to_string (nTG+1); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, diff --git a/src/uimenu.h b/src/uimenu.h index 6ff6571f6..a9d2e7bf5 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -72,7 +72,7 @@ class CUIMenu unsigned Parameter; }; - typedef std::string TToString (int nValue); + typedef std::string TToString (int nValue, int nWidth); struct TParameter { @@ -97,26 +97,26 @@ class CUIMenu static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); - static std::string GetGlobalValueString (unsigned nParameter, int nValue); - static std::string GetTGValueString (unsigned nTGParameter, int nValue); - static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue); - static std::string GetOPValueString (unsigned nOPParameter, int nValue); - - static std::string ToVolume (int nValue); - static std::string ToPan (int nValue); - static std::string ToMIDIChannel (int nValue); - - static std::string ToAlgorithm (int nValue); - static std::string ToOnOff (int nValue); - static std::string ToLFOWaveform (int nValue); - static std::string ToTransposeNote (int nValue); - static std::string ToBreakpointNote (int nValue); - static std::string ToKeyboardCurve (int nValue); - static std::string ToOscillatorMode (int nValue); - static std::string ToOscillatorDetune (int nValue); - static std::string ToPortaMode (int nValue); - static std::string ToPortaGlissando (int nValue); - static std::string ToPolyMono (int nValue); + static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); + static std::string GetTGValueString (unsigned nTGParameter, int nValue, int nWidth); + static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth); + static std::string GetOPValueString (unsigned nOPParameter, int nValue, int nWidth); + + static std::string ToVolume (int nValue, int nWidth); + static std::string ToPan (int nValue, int nWidth); + static std::string ToMIDIChannel (int nValue, int nWidth); + + static std::string ToAlgorithm (int nValue, int nWidth); + static std::string ToOnOff (int nValue, int nWidth); + static std::string ToLFOWaveform (int nValue, int nWidth); + static std::string ToTransposeNote (int nValue, int nWidth); + static std::string ToBreakpointNote (int nValue, int nWidth); + static std::string ToKeyboardCurve (int nValue, int nWidth); + static std::string ToOscillatorMode (int nValue, int nWidth); + static std::string ToOscillatorDetune (int nValue, int nWidth); + static std::string ToPortaMode (int nValue, int nWidth); + static std::string ToPortaGlissando (int nValue, int nWidth); + static std::string ToPolyMono (int nValue, int nWidth); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); From 40ba22e709fd8be09583bee070cfb4872dcca94c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 28 Jul 2025 12:42:20 +0200 Subject: [PATCH 011/136] UI: Set volume and pan increments to 1 if Encoder is enabled --- src/uimenu.cpp | 11 +++++++++-- src/uimenu.h | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 13c50c6bb..d98b1fc14 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -216,7 +216,7 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = }; // must match CMiniDexed::TParameter -const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = +CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = { {0, 1, 1, ToOnOff}, // ParameterCompessorEnable {0, 1, 1, ToOnOff}, // ParameterReverbEnable @@ -232,7 +232,7 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow }; // must match CMiniDexed::TTGParameter -const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = +CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = { {0, CSysExFileLoader::MaxVoiceBankID, 1}, // TGParameterVoiceBank {0, 0, 0}, // TGParameterVoiceBankMSB (not used in menus) @@ -379,6 +379,13 @@ CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) m_nMenuStackSelection[0] = 0; m_nMenuStackParameter[0] = 0; } + + if (m_pConfig->GetEncoderEnabled()) + { + s_GlobalParameter[CMiniDexed::ParameterMasterVolume].Increment = 1; + s_TGParameter[CMiniDexed::TGParameterVolume].Increment = 1; + s_TGParameter[CMiniDexed::TGParameterPan].Increment = 1; + } } void CUIMenu::EventHandler (TMenuEvent Event) diff --git a/src/uimenu.h b/src/uimenu.h index a9d2e7bf5..93978e1ef 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -165,8 +165,8 @@ class CUIMenu static const TMenuItem s_ModulationMenu[]; static const TMenuItem s_ModulationMenuParameters[]; - static const TParameter s_GlobalParameter[]; - static const TParameter s_TGParameter[]; + static TParameter s_GlobalParameter[]; + static TParameter s_TGParameter[]; static const TParameter s_VoiceParameter[]; static const TParameter s_OPParameter[]; From 0361bb30307f61c9bd09e1296cfae9f622297c01 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 14:32:42 +0200 Subject: [PATCH 012/136] CUIMenu: do not use the full std namespace The using namespace can cause confusions https://stackoverflow.com/questions/1452721/whats-the-problem-with-using-namespace-std --- src/uimenu.cpp | 121 ++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 61 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index d98b1fc14..76b86a99c 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -31,7 +31,6 @@ #include #include -using namespace std; LOGMODULE ("uimenu"); const CUIMenu::TMenuItem CUIMenu::s_MenuRoot[] = @@ -602,7 +601,7 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - string Value = GetGlobalValueString (Param, + std::string Value = GetGlobalValueString (Param, pUIMenu->m_pMiniDexed->GetParameter (Param), pUIMenu->m_pConfig->GetLCDColumns() - 2); @@ -645,10 +644,10 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); - string Value = to_string (nValue+1) + "=" + std::string Value = std::to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetBankName (nValue); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), @@ -704,7 +703,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) // Skip empty voices. // Use same criteria in PgmUpDownHandler() too. - string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); + std::string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); if (voiceName == "EMPTY " || voiceName == " " || voiceName == "----------" @@ -786,10 +785,10 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); - string Value = GetTGValueString (Param, + std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); @@ -842,10 +841,10 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); - string Value = GetTGValueString (Param, + std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); @@ -898,10 +897,10 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); - string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); + std::string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, @@ -952,10 +951,10 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string OP ("OP"); - OP += to_string (nOP+1); + std::string OP ("OP"); + OP += std::to_string (nOP+1); - string Value; + std::string Value; static const int FixedMultiplier[4] = {1, 10, 100, 1000}; if (nParam == DEXED_OP_FREQ_COARSE) @@ -969,14 +968,14 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) } else { - Value = to_string (nValue); + Value = std::to_string (nValue); Value += ".00"; } } else { // Fixed - Value = to_string (FixedMultiplier[nValue % 4]); + Value = std::to_string (FixedMultiplier[nValue % 4]); } } else if (nParam == DEXED_OP_FREQ_FINE) @@ -1034,9 +1033,9 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); } -string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue, int nWidth) +std::string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nParameter < sizeof CUIMenu::s_GlobalParameter / sizeof CUIMenu::s_GlobalParameter[0]); @@ -1047,15 +1046,15 @@ string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue, int nWidt } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nWidth) +std::string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nTGParameter < sizeof CUIMenu::s_TGParameter / sizeof CUIMenu::s_TGParameter[0]); @@ -1066,15 +1065,15 @@ string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nWidth) } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth) +std::string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nVoiceParameter < sizeof CUIMenu::s_VoiceParameter / sizeof CUIMenu::s_VoiceParameter[0]); @@ -1085,15 +1084,15 @@ string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int n } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue, int nWidth) +std::string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nOPParameter < sizeof CUIMenu::s_OPParameter / sizeof CUIMenu::s_OPParameter[0]); @@ -1104,13 +1103,13 @@ string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue, int nWidth) } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::ToVolume (int nValue, int nWidth) +std::string CUIMenu::ToVolume (int nValue, int nWidth) { char buf[nWidth + 1]; unsigned nBarWidth = nWidth - 3; @@ -1122,7 +1121,7 @@ string CUIMenu::ToVolume (int nValue, int nWidth) return buf; } -string CUIMenu::ToPan (int nValue, int nWidth) +std::string CUIMenu::ToPan (int nValue, int nWidth) { char buf[nWidth + 1]; unsigned nBarWidth = nWidth - 3; @@ -1134,22 +1133,22 @@ string CUIMenu::ToPan (int nValue, int nWidth) return buf; } -string CUIMenu::ToMIDIChannel (int nValue, int nWidth) +std::string CUIMenu::ToMIDIChannel (int nValue, int nWidth) { switch (nValue) { case CMIDIDevice::OmniMode: return "Omni"; case CMIDIDevice::Disabled: return "Off"; - default: return to_string (nValue+1); + default: return std::to_string (nValue+1); } } -string CUIMenu::ToAlgorithm (int nValue, int nWidth) +std::string CUIMenu::ToAlgorithm (int nValue, int nWidth) { - return to_string (nValue + 1); + return std::to_string (nValue + 1); } -string CUIMenu::ToOnOff (int nValue, int nWidth) +std::string CUIMenu::ToOnOff (int nValue, int nWidth) { static const char *OnOff[] = {"Off", "On"}; @@ -1158,7 +1157,7 @@ string CUIMenu::ToOnOff (int nValue, int nWidth) return OnOff[nValue]; } -string CUIMenu::ToLFOWaveform (int nValue, int nWidth) +std::string CUIMenu::ToLFOWaveform (int nValue, int nWidth) { static const char *Waveform[] = {"Triangle", "Saw down", "Saw up", "Square", "Sine", "Sample/Hold"}; @@ -1168,7 +1167,7 @@ string CUIMenu::ToLFOWaveform (int nValue, int nWidth) return Waveform[nValue]; } -string CUIMenu::ToTransposeNote (int nValue, int nWidth) +std::string CUIMenu::ToTransposeNote (int nValue, int nWidth) { nValue += NoteC3 - 24; @@ -1177,14 +1176,14 @@ string CUIMenu::ToTransposeNote (int nValue, int nWidth) return s_NoteName[nValue]; } -string CUIMenu::ToBreakpointNote (int nValue, int nWidth) +std::string CUIMenu::ToBreakpointNote (int nValue, int nWidth) { assert ((unsigned) nValue < sizeof s_NoteName / sizeof s_NoteName[0]); return s_NoteName[nValue]; } -string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) +std::string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) { static const char *Curve[] = {"-Lin", "-Exp", "+Exp", "+Lin"}; @@ -1193,7 +1192,7 @@ string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) return Curve[nValue]; } -string CUIMenu::ToOscillatorMode (int nValue, int nWidth) +std::string CUIMenu::ToOscillatorMode (int nValue, int nWidth) { static const char *Mode[] = {"Ratio", "Fixed"}; @@ -1202,51 +1201,51 @@ string CUIMenu::ToOscillatorMode (int nValue, int nWidth) return Mode[nValue]; } -string CUIMenu::ToOscillatorDetune (int nValue, int nWidth) +std::string CUIMenu::ToOscillatorDetune (int nValue, int nWidth) { - string Result; + std::string Result; nValue -= 7; if (nValue > 0) { - Result = "+" + to_string (nValue); + Result = "+" + std::to_string (nValue); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::ToPortaMode (int nValue, int nWidth) +std::string CUIMenu::ToPortaMode (int nValue, int nWidth) { switch (nValue) { case 0: return "Fingered"; case 1: return "Full time"; - default: return to_string (nValue); + default: return std::to_string (nValue); } }; -string CUIMenu::ToPortaGlissando (int nValue, int nWidth) +std::string CUIMenu::ToPortaGlissando (int nValue, int nWidth) { switch (nValue) { case 0: return "Off"; case 1: return "On"; - default: return to_string (nValue); + default: return std::to_string (nValue); } }; -string CUIMenu::ToPolyMono (int nValue, int nWidth) +std::string CUIMenu::ToPolyMono (int nValue, int nWidth) { switch (nValue) { case 0: return "Poly"; case 1: return "Mono"; - default: return to_string (nValue); + default: return std::to_string (nValue); } } @@ -1401,7 +1400,7 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) // Skip empty voices. // Use same criteria in EditProgramNumber () too. - string voiceName = m_pMiniDexed->GetVoiceName (nTG); + std::string voiceName = m_pMiniDexed->GetVoiceName (nTG); if (voiceName == "EMPTY " || voiceName == " " || voiceName == "----------" @@ -1859,7 +1858,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG=0; - string TG ("TG"); + std::string TG ("TG"); std::string MsgOk; std::string NoValidChars; @@ -1894,7 +1893,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) NoValidChars = {127}; MaxChars=10; MenuTitleL="Name"; - TG += to_string (nTG+1); + TG += std::to_string (nTG+1); MenuTitleR=TG; OkTitleL=""; OkTitleR=""; @@ -2000,7 +1999,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) // \E[?25l Cursor invisible std::string escCursor="\E[?25h\E[2;"; // this is to locate cursor - escCursor += to_string(nPosition + 2); + escCursor += std::to_string(nPosition + 2); escCursor += "H"; @@ -2063,10 +2062,10 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); - string Value = GetTGValueString (Param, + std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); From 9631cdb32e696a5479d88d6dd3988251026484a0 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 16:32:06 +0200 Subject: [PATCH 013/136] Add option to configure default screen Add DefaultScreen option to the minidexed.ini 0=Default 1=Performance Load Open the Performance>Load menu if Performance Load is set --- src/config.cpp | 2 ++ src/config.h | 4 ++++ src/minidexed.cpp | 2 ++ src/minidexed.ini | 3 +++ src/userinterface.cpp | 11 +++++++++++ src/userinterface.h | 2 ++ 6 files changed, 24 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index e983dad78..346a43f63 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -220,6 +220,8 @@ void CConfig::Load (void) } m_nMasterVolume = m_Properties.GetNumber ("MasterVolume", 64); + + m_nDefaultScreen = m_Properties.GetNumber ("DefaultScreen", 0); } unsigned CConfig::GetToneGenerators (void) const diff --git a/src/config.h b/src/config.h index add609619..d9fd29475 100644 --- a/src/config.h +++ b/src/config.h @@ -241,6 +241,8 @@ class CConfig // Configuration for MiniDexed unsigned GetMasterVolume() const { return m_nMasterVolume; } + unsigned GetDefaultScreen() const { return m_nDefaultScreen; } + // Network bool GetNetworkEnabled (void) const; bool GetNetworkDHCP (void) const; @@ -370,6 +372,8 @@ class CConfig // Configuration for MiniDexed unsigned m_bPerformanceSelectChannel; unsigned m_nMasterVolume; // Master volume 0-127 + + unsigned m_nDefaultScreen; // 0 Default, 1 Performance // Network bool m_bNetworkEnabled; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 41374456e..58e82855c 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -372,6 +372,8 @@ bool CMiniDexed::Initialize (void) m_pSoundDevice->Start (); + m_UI.LoadDefaultScreen (); + #ifdef ARM_ALLOW_MULTI_CORE // start secondary cores if (!CMultiCoreSupport::Initialize ()) diff --git a/src/minidexed.ini b/src/minidexed.ini index 4d0f3895c..9fd595085 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -16,6 +16,9 @@ QuadDAC8Chan=0 # Master Volume (0-127) MasterVolume=64 +# Default "Boot" Screen ( 0=TG1 (default); 1=Performance Load ) +DefaultScreen=0 + # MIDI MIDIBaudRate=31250 #MIDIThru=umidi1,ttyS1 diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 43a94ff46..be7242421 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -199,6 +199,17 @@ bool CUserInterface::Initialize (void) return true; } +void CUserInterface::LoadDefaultScreen () +{ + // performance load + if (m_pConfig->GetDefaultScreen() == 1) + { + m_Menu.EventHandler (CUIMenu::MenuEventStepDown); + m_Menu.EventHandler (CUIMenu::MenuEventSelect); + m_Menu.EventHandler (CUIMenu::MenuEventSelect); + } +} + void CUserInterface::Process (void) { if (m_pLCDBuffered) diff --git a/src/userinterface.h b/src/userinterface.h index 6290d865b..ba7daef96 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -42,6 +42,8 @@ class CUserInterface bool Initialize (void); + void LoadDefaultScreen (); + void Process (void); void ParameterChanged (void); From 0998d428549cdd8cbd85e80dcc7fd8696ae22136 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 27 Jul 2025 17:53:57 +0200 Subject: [PATCH 014/136] CMiniDexed: show Network Ready + IP instead of TG1 TG1 is misleading if the menu is not on it. Show only for for 3 seconds. --- src/minidexed.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 58e82855c..c2787e2a0 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -2278,6 +2278,14 @@ unsigned CMiniDexed::getModController (unsigned controller, unsigned parameter, } +static void UpdateScreen(TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + CUserInterface *pUI = static_cast (pContext); + assert (pUI); + + pUI->DisplayChanged (); +} + void CMiniDexed::UpdateNetwork() { if (!m_pNet) { @@ -2320,7 +2328,8 @@ void CMiniDexed::UpdateNetwork() LOGNOTE("FTP daemon not started (NetworkFTPEnabled=0)"); } - m_UI.DisplayWrite (IPString, "", "TG1", 0, 1); + m_UI.DisplayWrite (IPString, "", "Network ready", 0, 1); + CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), UpdateScreen, 0, &m_UI); m_pmDNSPublisher = new CmDNSPublisher (m_pNet); assert (m_pmDNSPublisher); From 726f25eb61651d324d04b7cd0b00db4b61919cba Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 29 Jul 2025 03:21:27 +0200 Subject: [PATCH 015/136] PerfTimer: add lastMicros Add ability to write the last measured time. --- src/perftimer.cpp | 16 ++++++++++++---- src/perftimer.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/perftimer.cpp b/src/perftimer.cpp index 5a21471b5..f1b1aae2d 100644 --- a/src/perftimer.cpp +++ b/src/perftimer.cpp @@ -36,11 +36,11 @@ void CPerformanceTimer::Start (void) void CPerformanceTimer::Stop (void) { unsigned nEndTicks = CTimer::GetClockTicks (); - unsigned nMicros = (nEndTicks - m_nStartTicks) / (CLOCKHZ / 1000000); + m_nLastMicros = (nEndTicks - m_nStartTicks) / (CLOCKHZ / 1000000); - if (nMicros > m_nMaximumMicros) + if (m_nLastMicros > m_nMaximumMicros) { - m_nMaximumMicros = nMicros; + m_nMaximumMicros = m_nLastMicros; } } @@ -53,8 +53,16 @@ void CPerformanceTimer::Dump (unsigned nIntervalTicks) m_nLastDumpTicks = nTicks; unsigned nMaximumMicros = m_nMaximumMicros; // may be overwritten from interrupt + unsigned nLastMicros = m_nLastMicros; - std::cout << m_Name << ": Maximum duration was " << nMaximumMicros << "us"; + std::cout << m_Name << ": Last duration was " << nLastMicros << "us"; + + if (m_nDeadlineMicros != 0) + { + std::cout << " (" << nLastMicros*100 / m_nDeadlineMicros << "%)"; + } + + std::cout << " Maximum was " << nMaximumMicros << "us"; if (m_nDeadlineMicros != 0) { diff --git a/src/perftimer.h b/src/perftimer.h index 537b6d0da..91c0ae4ab 100644 --- a/src/perftimer.h +++ b/src/perftimer.h @@ -38,6 +38,7 @@ class CPerformanceTimer unsigned m_nDeadlineMicros; unsigned m_nStartTicks; + unsigned m_nLastMicros; unsigned m_nMaximumMicros; unsigned m_nLastDumpTicks; From e5407ef18aa444d7999a456bd92282644fa390b6 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 29 Jul 2025 18:25:13 +0200 Subject: [PATCH 016/136] PerfTimer: add CPU information --- src/perftimer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/perftimer.cpp b/src/perftimer.cpp index f1b1aae2d..878642703 100644 --- a/src/perftimer.cpp +++ b/src/perftimer.cpp @@ -18,6 +18,7 @@ // along with this program. If not, see . // #include "perftimer.h" +#include #include CPerformanceTimer::CPerformanceTimer (const char *pName, unsigned nDeadlineMicros) @@ -69,6 +70,11 @@ void CPerformanceTimer::Dump (unsigned nIntervalTicks) std::cout << " (" << nMaximumMicros*100 / m_nDeadlineMicros << "%)"; } + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + std::cout << " (CPU " << pCPUT->GetClockRate () / 1000000 << "/" << pCPUT->GetMaxClockRate() / 1000000 << " MHz "; + std::cout << pCPUT->GetTemperature () << "/" << pCPUT->GetMaxTemperature () << " C)"; + std::cout << std::endl; } } From f51b617aab8075431ff7967e63a537e337141b5e Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 29 Jul 2025 18:26:01 +0200 Subject: [PATCH 017/136] kernel: RegisterSystemThrottledHandler --- src/kernel.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/kernel.cpp b/src/kernel.cpp index c6c86d9f2..add257801 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -50,6 +50,22 @@ CKernel::~CKernel(void) s_pThis = 0; } +static void SystemThrottledHandler (TSystemThrottledState CurrentState, void *pParam) +{ + LOGNOTE ("System Throttled"); + + if (CurrentState & SystemStateUnderVoltageOccurred) + LOGNOTE ("SystemStateUnderVoltageOccurred"); + if (CurrentState & SystemStateFrequencyCappingOccurred) + LOGNOTE ("SystemStateFrequencyCappingOccurred"); + if (CurrentState & SystemStateThrottlingOccurred) + LOGNOTE ("SystemStateThrottlingOccurred"); + if (CurrentState & SystemStateSoftTempLimitOccurred) + LOGNOTE ("SystemStateSoftTempLimitOccurred"); + + CCPUThrottle::Get ()->DumpStatus (); +} + bool CKernel::Initialize (void) { if (!CStdlibAppStdio::Initialize ()) @@ -70,6 +86,11 @@ bool CKernel::Initialize (void) } m_Config.Load (); + + m_CPUThrottle.DumpStatus (); + m_CPUThrottle.RegisterSystemThrottledHandler ( SystemStateUnderVoltageOccurred | + SystemStateFrequencyCappingOccurred | SystemStateThrottlingOccurred | + SystemStateSoftTempLimitOccurred, SystemThrottledHandler, 0); unsigned nSPIMaster = m_Config.GetSPIBus(); unsigned nSPIMode = m_Config.GetSPIMode(); From 0ecdeb1fef897553b8fc0585bd89952e9a49efbf Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 1 Aug 2025 20:29:33 +0200 Subject: [PATCH 018/136] config: add LogThrottling option Add an option to enable logging of throttling events. --- src/config.cpp | 7 +++++++ src/config.h | 5 ++++- src/minidexed.ini | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/config.cpp b/src/config.cpp index 346a43f63..d8a9d7717 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -198,6 +198,8 @@ void CConfig::Load (void) m_bMIDIDumpEnabled = m_Properties.GetNumber ("MIDIDumpEnabled", 0) != 0; m_bProfileEnabled = m_Properties.GetNumber ("ProfileEnabled", 0) != 0; + m_bLogThrottling = m_Properties.GetNumber("LogThrottling", 0); + m_bPerformanceSelectToLoad = m_Properties.GetNumber ("PerformanceSelectToLoad", 0) != 0; m_bPerformanceSelectChannel = m_Properties.GetNumber ("PerformanceSelectChannel", 0); @@ -735,6 +737,11 @@ bool CConfig::GetProfileEnabled (void) const return m_bProfileEnabled; } +bool CConfig::GetLogThrottling (void) const +{ + return m_bLogThrottling; +} + bool CConfig::GetPerformanceSelectToLoad (void) const { return m_bPerformanceSelectToLoad; diff --git a/src/config.h b/src/config.h index d9fd29475..1bb900ba7 100644 --- a/src/config.h +++ b/src/config.h @@ -234,7 +234,8 @@ class CConfig // Configuration for MiniDexed // Debug bool GetMIDIDumpEnabled (void) const; bool GetProfileEnabled (void) const; - + bool GetLogThrottling (void) const; + // Load performance mode. 0 for load just rotating encoder, 1 load just when Select is pushed bool GetPerformanceSelectToLoad (void) const; unsigned GetPerformanceSelectChannel (void) const; @@ -387,6 +388,8 @@ class CConfig // Configuration for MiniDexed bool m_bSyslogEnabled; CIPAddress m_INetworkSyslogServerIPAddress; bool m_bNetworkFTPEnabled; + + bool m_bLogThrottling; }; #endif diff --git a/src/minidexed.ini b/src/minidexed.ini index 9fd595085..fd5c99e65 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -153,6 +153,7 @@ EncoderPinData=9 # Debug MIDIDumpEnabled=0 ProfileEnabled=0 +LogThrottling=0 # Network NetworkEnabled=0 From 8103d18ed5a4be20986077dee1d185b17131cf82 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 1 Aug 2025 20:35:54 +0200 Subject: [PATCH 019/136] kernel: register systemThrottledHandler if the LogThrottling config option is enabled Logging can negativel impact the sound path. This can also occur in otherwise functional setups, so it's better not to have it enabled in all cases. --- src/kernel.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index add257801..a47fd846e 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -88,10 +88,13 @@ bool CKernel::Initialize (void) m_Config.Load (); m_CPUThrottle.DumpStatus (); - m_CPUThrottle.RegisterSystemThrottledHandler ( SystemStateUnderVoltageOccurred | - SystemStateFrequencyCappingOccurred | SystemStateThrottlingOccurred | - SystemStateSoftTempLimitOccurred, SystemThrottledHandler, 0); - + if (m_Config.GetLogThrottling ()) + { + m_CPUThrottle.RegisterSystemThrottledHandler ( SystemStateUnderVoltageOccurred | + SystemStateFrequencyCappingOccurred | SystemStateThrottlingOccurred | + SystemStateSoftTempLimitOccurred, SystemThrottledHandler, 0); + } + unsigned nSPIMaster = m_Config.GetSPIBus(); unsigned nSPIMode = m_Config.GetSPIMode(); unsigned long nSPIClock = 1000 * m_Config.GetSPIClockKHz(); From f9887570d236083e7523fd7bafd8c2d4b6c68f05 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 30 Jul 2025 00:23:57 +0200 Subject: [PATCH 020/136] move compressor into the TG menu --- src/minidexed.cpp | 36 ++++++++++++++++++++-------------- src/minidexed.h | 7 ++++++- src/performanceconfig.cpp | 41 ++++++++++++++++++++++++++------------- src/performanceconfig.h | 11 +++++++---- src/uimenu.cpp | 14 ++++++++++--- src/uimenu.h | 1 + 6 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index c2787e2a0..7d81db4ef 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -125,6 +125,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nReverbSend[i] = 0; + m_bCompressorEnable[i] = 1; + // Active the required number of active TGs if (iGetPerformanceSelectChannel()); SetParameter (ParameterPerformanceBank, 0); @@ -1011,14 +1011,6 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) switch (Parameter) { - case ParameterCompressorEnable: - for (unsigned nTG = 0; nTG < m_nToneGenerators; nTG++) - { - assert (m_pTG[nTG]); - m_pTG[nTG]->setCompressor (!!nValue); - } - break; - case ParameterReverbEnable: nValue=constrain((int)nValue,0,1); m_ReverbSpinLock.Acquire (); @@ -1145,6 +1137,8 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT case TGParameterReverbSend: SetReverbSend (nValue, nTG); break; + case TGParameterCompressorEnable: SetCompressorEnable (nValue, nTG); break; + default: assert (0); break; @@ -1195,7 +1189,8 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterATAmplitude: return getModController(3, 2, nTG); case TGParameterATEGBias: return getModController(3, 3, nTG); - + case TGParameterCompressorEnable: return m_bCompressorEnable[nTG]; + default: assert (0); return 0; @@ -1569,9 +1564,10 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetAftertouchTarget (m_nAftertouchTarget[nTG], nTG); m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG); + + m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); } - m_PerformanceConfig.SetCompressorEnable (!!m_nParameter[ParameterCompressorEnable]); m_PerformanceConfig.SetReverbEnable (!!m_nParameter[ParameterReverbEnable]); m_PerformanceConfig.SetReverbSize (m_nParameter[ParameterReverbSize]); m_PerformanceConfig.SetReverbHighDamp (m_nParameter[ParameterReverbHighDamp]); @@ -1589,6 +1585,17 @@ bool CMiniDexed::DoSavePerformance (void) return m_PerformanceConfig.Save (); } +void CMiniDexed::SetCompressorEnable(bool compressor, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_bCompressorEnable[nTG] = compressor; + m_pTG[nTG]->setCompressor (compressor); + m_UI.ParameterChanged (); +} + void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -2059,12 +2066,11 @@ void CMiniDexed::LoadPerformanceParameters(void) setBreathControllerTarget (m_PerformanceConfig.GetBreathControlTarget (nTG), nTG); setAftertouchRange (m_PerformanceConfig.GetAftertouchRange (nTG), nTG); setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); - - + + SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); } // Effects - SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0); SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); diff --git a/src/minidexed.h b/src/minidexed.h index 22fd5eff0..af7e07e42 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -106,6 +106,8 @@ class CMiniDexed void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127 + void SetCompressorEnable (bool compressor, unsigned nTG); + void setMonoMode(uint8_t mono, uint8_t nTG); void setPitchbendRange(uint8_t range, uint8_t nTG); void setPitchbendStep(uint8_t step, uint8_t nTG); @@ -158,7 +160,6 @@ class CMiniDexed // Must match the order in CUIMenu::TParameter enum TParameter { - ParameterCompressorEnable, ParameterReverbEnable, ParameterReverbSize, ParameterReverbHighDamp, @@ -221,6 +222,8 @@ class CMiniDexed TGParameterATPitch, TGParameterATAmplitude, TGParameterATEGBias, + + TGParameterCompressorEnable, TGParameterUnknown }; @@ -304,6 +307,8 @@ class CMiniDexed int m_nNoteShift[CConfig::AllToneGenerators]; unsigned m_nReverbSend[CConfig::AllToneGenerators]; + + bool m_bCompressorEnable[CConfig::AllToneGenerators]; uint8_t m_nRawVoiceData[156]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index dfff8a9cc..6dd1d46c8 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -208,11 +208,12 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("AftertouchTarget%u", nTG+1); m_nAftertouchTarget[nTG] = m_Properties.GetNumber (PropertyName, 0); + + PropertyName.Format ("CompressorEnable%u", nTG+1); + m_bCompressorEnable[nTG] = m_Properties.GetNumber (PropertyName, 1); } - m_bCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1) != 0; - m_bReverbEnable = m_Properties.GetNumber ("ReverbEnable", 1) != 0; m_nReverbSize = m_Properties.GetNumber ("ReverbSize", 70); m_nReverbHighDamp = m_Properties.GetNumber ("ReverbHighDamp", 50); @@ -221,6 +222,15 @@ bool CPerformanceConfig::Load (void) m_nReverbDiffusion = m_Properties.GetNumber ("ReverbDiffusion", 65); m_nReverbLevel = m_Properties.GetNumber ("ReverbLevel", 99); + // Compatibility + if (m_Properties.IsSet ("CompressorEnable") && m_Properties.GetNumber ("CompressorEnable", 1) == 0) + { + for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) + { + m_bCompressorEnable[nTG] = 0; + } + } + return bResult; } @@ -327,9 +337,10 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("AftertouchTarget%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nAftertouchTarget[nTG]); - } + PropertyName.Format ("CompressorEnable%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_bCompressorEnable[nTG]); - m_Properties.SetNumber ("CompressorEnable", m_bCompressorEnable ? 1 : 0); + } m_Properties.SetNumber ("ReverbEnable", m_bReverbEnable ? 1 : 0); m_Properties.SetNumber ("ReverbSize", m_nReverbSize); @@ -486,11 +497,6 @@ void CPerformanceConfig::SetReverbSend (unsigned nValue, unsigned nTG) m_nReverbSend[nTG] = nValue; } -bool CPerformanceConfig::GetCompressorEnable (void) const -{ - return m_bCompressorEnable; -} - bool CPerformanceConfig::GetReverbEnable (void) const { return m_bReverbEnable; @@ -526,11 +532,6 @@ unsigned CPerformanceConfig::GetReverbLevel (void) const return m_nReverbLevel; } -void CPerformanceConfig::SetCompressorEnable (bool bValue) -{ - m_bCompressorEnable = bValue; -} - void CPerformanceConfig::SetReverbEnable (bool bValue) { m_bReverbEnable = bValue; @@ -737,6 +738,18 @@ unsigned CPerformanceConfig::GetAftertouchTarget (unsigned nTG) const return m_nAftertouchTarget[nTG]; } +void CPerformanceConfig::SetCompressorEnable (bool bValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_bCompressorEnable[nTG] = bValue; +} + +bool CPerformanceConfig::GetCompressorEnable (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_bCompressorEnable[nTG]; +} + void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 916a2eec0..bb4db9b96 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -71,6 +71,8 @@ class CPerformanceConfig // Performance configuration unsigned GetAftertouchRange (unsigned nTG) const; // 0 .. 99 unsigned GetAftertouchTarget (unsigned nTG) const; // 0 .. 7 + bool GetCompressorEnable (unsigned nTG) const; // 0 .. 1 + void SetBankNumber (unsigned nValue, unsigned nTG); void SetVoiceNumber (unsigned nValue, unsigned nTG); void SetMIDIChannel (unsigned nValue, unsigned nTG); @@ -101,8 +103,9 @@ class CPerformanceConfig // Performance configuration void SetAftertouchRange (unsigned nValue, unsigned nTG); void SetAftertouchTarget (unsigned nValue, unsigned nTG); + void SetCompressorEnable (bool bCompressor, unsigned nTG); + // Effects - bool GetCompressorEnable (void) const; bool GetReverbEnable (void) const; unsigned GetReverbSize (void) const; // 0 .. 99 unsigned GetReverbHighDamp (void) const; // 0 .. 99 @@ -111,7 +114,6 @@ class CPerformanceConfig // Performance configuration unsigned GetReverbDiffusion (void) const; // 0 .. 99 unsigned GetReverbLevel (void) const; // 0 .. 99 - void SetCompressorEnable (bool bValue); void SetReverbEnable (bool bValue); void SetReverbSize (unsigned nValue); void SetReverbHighDamp (unsigned nValue); @@ -181,7 +183,9 @@ class CPerformanceConfig // Performance configuration unsigned m_nBreathControlRange[CConfig::AllToneGenerators]; unsigned m_nBreathControlTarget[CConfig::AllToneGenerators]; unsigned m_nAftertouchRange[CConfig::AllToneGenerators]; - unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; + unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; + + bool m_bCompressorEnable[CConfig::AllToneGenerators]; unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; @@ -196,7 +200,6 @@ class CPerformanceConfig // Performance configuration std::string NewPerformanceName=""; - bool m_bCompressorEnable; bool m_bReverbEnable; unsigned m_nReverbSize; unsigned m_nReverbHighDamp; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 76b86a99c..6c359d425 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -62,7 +62,9 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG16", MenuHandler, s_TGMenu, 15}, #endif #endif +#ifdef ARM_ALLOW_MULTI_CORE {"Effects", MenuHandler, s_EffectsMenu}, +#endif {"Master Volume", EditGlobalParameter, 0, CMiniDexed::ParameterMasterVolume}, {"Performance", MenuHandler, s_PerformanceMenu}, {0} @@ -85,13 +87,19 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, + {"Compressor", MenuHandler, s_EditCompressorMenu}, {"Edit Voice", MenuHandler, s_EditVoiceMenu}, {0} }; +const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = +{ + {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { - {"Compress", EditGlobalParameter, 0, CMiniDexed::ParameterCompressorEnable}, #ifdef ARM_ALLOW_MULTI_CORE {"Reverb", MenuHandler, s_ReverbMenu}, #endif @@ -217,7 +225,6 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = // must match CMiniDexed::TParameter CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = { - {0, 1, 1, ToOnOff}, // ParameterCompessorEnable {0, 1, 1, ToOnOff}, // ParameterReverbEnable {0, 99, 1}, // ParameterReverbSize {0, 99, 1}, // ParameterReverbHighDamp @@ -265,7 +272,8 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 99, 1}, //AT Range {0, 1, 1, ToOnOff}, //AT Pitch {0, 1, 1, ToOnOff}, //AT Amp - {0, 1, 1, ToOnOff} //AT EGBias + {0, 1, 1, ToOnOff}, //AT EGBias + {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable }; // must match DexedVoiceParameters in Synth_Dexed diff --git a/src/uimenu.h b/src/uimenu.h index 93978e1ef..b6a90e1f0 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -155,6 +155,7 @@ class CUIMenu static const TMenuItem s_TGMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_ReverbMenu[]; + static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; static const TMenuItem s_SaveMenu[]; From 4dd235fa7d275e33f5c8d2bb6162b99ede8961dd Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 30 Jul 2025 03:37:34 +0200 Subject: [PATCH 021/136] add compressor parameters --- src/minidexed.cpp | 85 ++++++++++++++++++++++++++++++++++++ src/minidexed.h | 17 +++++++- src/performanceconfig.cpp | 91 +++++++++++++++++++++++++++++++++++++++ src/performanceconfig.h | 17 +++++++- src/uimenu.cpp | 30 +++++++++++++ src/uimenu.h | 4 ++ 6 files changed, 242 insertions(+), 2 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 7d81db4ef..dc903e1bf 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -126,6 +126,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nReverbSend[i] = 0; m_bCompressorEnable[i] = 1; + m_nCompressorPreGain[i] = 0; + m_nCompressorAttack[i] = 5; + m_nCompressorRelease[i] = 200; + m_nCompressorThresh[i] = -20; + m_nCompressorRatio[i] = 5; // Active the required number of active TGs if (i= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorPreGain[nTG] = preGain; + m_pTG[nTG]->setCompressorPreGain_dB (preGain); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) +{ + attack = constrain (attack, 0u, 1000u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorAttack[nTG] = attack; + m_pTG[nTG]->setCompressorAttack_sec (attack / 1000.0); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) +{ + release = constrain (release, 0u, 1000u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorRelease[nTG] = release; + m_pTG[nTG]->setCompressorRelease_sec (release / 1000.0); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) +{ + thresh = constrain (thresh, -60, 0); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorThresh[nTG] = thresh; + m_pTG[nTG]->setCompressorThresh_dBFS (thresh); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) +{ + ratio = constrain (ratio, 1u, 20u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorRatio[nTG] = ratio; + m_pTG[nTG]->setCompressionRatio (ratio); + m_UI.ParameterChanged (); +} + void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -2068,6 +2148,11 @@ void CMiniDexed::LoadPerformanceParameters(void) setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); + SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); + SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; + SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); + SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); + SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); } // Effects diff --git a/src/minidexed.h b/src/minidexed.h index af7e07e42..0f5b34796 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -106,7 +106,12 @@ class CMiniDexed void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127 - void SetCompressorEnable (bool compressor, unsigned nTG); + void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) + void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) + void SetCompressorAttack (unsigned attack, unsigned nTG); // 0 .. 1000 ms (default 5) + void SetCompressorRelease (unsigned release, unsigned nTG); // 0 .. 1000 ms (default 200) + void SetCompressorThresh (int thresh, unsigned nTG); // -60 .. 0 dBFS (default -20) + void SetCompressorRatio (unsigned ratio, unsigned nTG); // 1 .. 20 (default 5) void setMonoMode(uint8_t mono, uint8_t nTG); void setPitchbendRange(uint8_t range, uint8_t nTG); @@ -224,6 +229,11 @@ class CMiniDexed TGParameterATEGBias, TGParameterCompressorEnable, + TGParameterCompressorPreGain, + TGParameterCompressorAttack, + TGParameterCompressorRelease, + TGParameterCompressorThresh, + TGParameterCompressorRatio, TGParameterUnknown }; @@ -309,6 +319,11 @@ class CMiniDexed unsigned m_nReverbSend[CConfig::AllToneGenerators]; bool m_bCompressorEnable[CConfig::AllToneGenerators]; + int m_nCompressorPreGain[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorThresh[CConfig::AllToneGenerators]; + unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; uint8_t m_nRawVoiceData[156]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 6dd1d46c8..35b5a4768 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -212,6 +212,21 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("CompressorEnable%u", nTG+1); m_bCompressorEnable[nTG] = m_Properties.GetNumber (PropertyName, 1); + PropertyName.Format ("CompressorPreGain%u", nTG+1); + m_nCompressorPreGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("CompressorAttack%u", nTG+1); + m_nCompressorAttack[nTG] = m_Properties.GetNumber (PropertyName, 5); + + PropertyName.Format ("CompressorRelease%u", nTG+1); + m_nCompressorRelease[nTG] = m_Properties.GetNumber (PropertyName, 200); + + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_nCompressorThresh[nTG] = m_Properties.GetSignedNumber (PropertyName, -20); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_nCompressorRatio[nTG] = m_Properties.GetNumber (PropertyName, 5); + } m_bReverbEnable = m_Properties.GetNumber ("ReverbEnable", 1) != 0; @@ -340,6 +355,21 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("CompressorEnable%u", nTG+1); m_Properties.SetNumber (PropertyName, m_bCompressorEnable[nTG]); + PropertyName.Format ("CompressorPreGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorPreGain[nTG]); + + PropertyName.Format ("CompressorAttack%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorAttack[nTG]); + + PropertyName.Format ("CompressorRelease%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorRelease[nTG]); + + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorThresh[nTG]); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorRatio[nTG]); + } m_Properties.SetNumber ("ReverbEnable", m_bReverbEnable ? 1 : 0); @@ -750,6 +780,67 @@ bool CPerformanceConfig::GetCompressorEnable (unsigned nTG) const return m_bCompressorEnable[nTG]; } +void CPerformanceConfig::SetCompressorPreGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorPreGain[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorPreGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorPreGain[nTG]; +} + +void CPerformanceConfig::SetCompressorAttack (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorAttack[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorAttack (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorAttack[nTG]; +} + +void CPerformanceConfig::SetCompressorRelease (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorRelease[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorRelease (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorRelease[nTG]; +} + +void CPerformanceConfig::SetCompressorThresh (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorThresh[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorThresh (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorThresh[nTG]; +} + +void CPerformanceConfig::SetCompressorRatio (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorRatio[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorRatio (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorRatio[nTG]; +} + + void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); diff --git a/src/performanceconfig.h b/src/performanceconfig.h index bb4db9b96..b1227dd60 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -72,6 +72,11 @@ class CPerformanceConfig // Performance configuration unsigned GetAftertouchTarget (unsigned nTG) const; // 0 .. 7 bool GetCompressorEnable (unsigned nTG) const; // 0 .. 1 + int GetCompressorPreGain (unsigned nTG) const; + unsigned GetCompressorAttack (unsigned nTG) const; + unsigned GetCompressorRelease (unsigned nTG) const; + int GetCompressorThresh (unsigned nTG) const; + unsigned GetCompressorRatio (unsigned nTG) const; void SetBankNumber (unsigned nValue, unsigned nTG); void SetVoiceNumber (unsigned nValue, unsigned nTG); @@ -103,7 +108,12 @@ class CPerformanceConfig // Performance configuration void SetAftertouchRange (unsigned nValue, unsigned nTG); void SetAftertouchTarget (unsigned nValue, unsigned nTG); - void SetCompressorEnable (bool bCompressor, unsigned nTG); + void SetCompressorEnable (bool nValue, unsigned nTG); + void SetCompressorPreGain (int nValue, unsigned nTG); + void SetCompressorAttack (unsigned nValue, unsigned nTG); + void SetCompressorRelease (unsigned nValue, unsigned nTG); + void SetCompressorThresh (int nValue, unsigned nTG); + void SetCompressorRatio (unsigned nValue, unsigned nTG); // Effects bool GetReverbEnable (void) const; @@ -186,6 +196,11 @@ class CPerformanceConfig // Performance configuration unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; bool m_bCompressorEnable[CConfig::AllToneGenerators]; + int m_nCompressorPreGain[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorThresh[CConfig::AllToneGenerators]; + unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 6c359d425..fcfd45428 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -95,6 +95,11 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = { {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable}, + {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain}, + {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack}, + {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease}, + {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh}, + {"Ratio", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRatio}, {0} }; @@ -274,6 +279,11 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1, 1, ToOnOff}, //AT Amp {0, 1, 1, ToOnOff}, //AT EGBias {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable + {-20, 20, 1, TodB}, // TGParameterCompressorPreGain + {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack + {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease + {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh + {1, 20, 1, ToRatio}, // TGParameterCompressorRatio }; // must match DexedVoiceParameters in Synth_Dexed @@ -1257,6 +1267,26 @@ std::string CUIMenu::ToPolyMono (int nValue, int nWidth) } } +std::string CUIMenu::TodB (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dB"; +} + +std::string CUIMenu::TodBFS (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dBFS"; +} + +std::string CUIMenu::ToMillisec (int nValue, int nWidth) +{ + return std::to_string (nValue) + " ms"; +} + +std::string CUIMenu::ToRatio (int nValue, int nWidth) +{ + return std::to_string (nValue) + ":1"; +} + void CUIMenu::TGShortcutHandler (TMenuEvent Event) { assert (m_nCurrentMenuDepth >= 2); diff --git a/src/uimenu.h b/src/uimenu.h index b6a90e1f0..f099d1b8f 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -117,6 +117,10 @@ class CUIMenu static std::string ToPortaMode (int nValue, int nWidth); static std::string ToPortaGlissando (int nValue, int nWidth); static std::string ToPolyMono (int nValue, int nWidth); + static std::string TodB (int nValue, int nWidth); + static std::string TodBFS (int nValue, int nWidth); + static std::string ToMillisec (int nValue, int nWidth); + static std::string ToRatio (int nValue, int nWidth); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); From 5a147118f86c0e13ee97f08d7d91f1e2fc96ca26 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 5 Aug 2025 19:53:16 +0200 Subject: [PATCH 022/136] add limiter --- src/minidexed.cpp | 83 +++++++++++++++++++++++++++++++++++++ src/minidexed.h | 11 +++++ src/performanceconfig.cpp | 87 +++++++++++++++++++++++++++++++++++++++ src/performanceconfig.h | 24 +++++++++++ src/uimenu.cpp | 20 +++++++++ src/uimenu.h | 1 + 6 files changed, 226 insertions(+) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index dc903e1bf..59987ab87 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -68,6 +68,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, reverb(nullptr), tg_mixer(nullptr), reverb_send_mixer(nullptr), + m_Limiter {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), m_pNetDevice(nullptr), m_WLAN(nullptr), @@ -266,6 +267,14 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetParameter (ParameterReverbLevel, 99); // END setup reverb + SetParameter (ParameterLimiterEnable, 1); + SetParameter (ParameterLimiterPreGain, 0); + SetParameter (ParameterLimiterAttack, 5); + SetParameter (ParameterLimiterRelease, 5); + SetParameter (ParameterLimiterThresh, -3); + SetParameter (ParameterLimiterRatio, 20); + SetParameter (ParameterLimiterHPFilterEnable, 0); + SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); SetParameter (ParameterPerformanceBank, 0); @@ -1079,6 +1088,56 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_UI.ParameterChanged (); break; + case ParameterLimiterEnable: + break; + + case ParameterLimiterPreGain: + nValue=constrain(nValue,-20,20); + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].setPreGain_dB(nValue); + m_LimiterSpinLock.Release (); + break; + + case ParameterLimiterAttack: + nValue=constrain(nValue,0,1000); + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_LimiterSpinLock.Release (); + break; + + case ParameterLimiterRelease: + nValue=constrain(nValue,0,1000); + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_LimiterSpinLock.Release (); + break; + + case ParameterLimiterThresh: + nValue=constrain(nValue,-60,0); + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].setThresh_dBFS(nValue); + m_LimiterSpinLock.Release (); + break; + + case ParameterLimiterRatio: + nValue=constrain(nValue,1,20); + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].setCompressionRatio(nValue); + m_LimiterSpinLock.Release (); + break; + + case ParameterLimiterHPFilterEnable: + m_LimiterSpinLock.Acquire (); + for (int i=0; i<2; ++i) + m_Limiter[i].enableHPFilter(nValue); + m_LimiterSpinLock.Release (); + break; + default: assert (0); break; @@ -1457,6 +1516,14 @@ void CMiniDexed::ProcessSound (void) } // END adding reverb + if (m_nParameter[ParameterLimiterEnable]) + { + m_LimiterSpinLock.Acquire (); + m_Limiter[0].doCompression (SampleBuffer[0], nFrames); + m_Limiter[1].doCompression (SampleBuffer[1], nFrames); + m_LimiterSpinLock.Release (); + } + // swap stereo channels if needed prior to writing back out if (m_bChannelsSwapped) { @@ -1596,6 +1663,14 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetReverbDiffusion (m_nParameter[ParameterReverbDiffusion]); m_PerformanceConfig.SetReverbLevel (m_nParameter[ParameterReverbLevel]); + m_PerformanceConfig.SetLimiterEnable (m_nParameter[ParameterLimiterEnable]); + m_PerformanceConfig.SetLimiterPreGain (m_nParameter[ParameterLimiterPreGain]); + m_PerformanceConfig.SetLimiterAttack (m_nParameter[ParameterLimiterAttack]); + m_PerformanceConfig.SetLimiterRelease (m_nParameter[ParameterLimiterRelease]); + m_PerformanceConfig.SetLimiterThresh (m_nParameter[ParameterLimiterThresh]); + m_PerformanceConfig.SetLimiterRatio (m_nParameter[ParameterLimiterRatio]); + m_PerformanceConfig.SetLimiterHPFilterEnable (m_nParameter[ParameterLimiterHPFilterEnable]); + if(m_bSaveAsDeault) { m_PerformanceConfig.SetNewPerformanceBank(0); @@ -2164,6 +2239,14 @@ void CMiniDexed::LoadPerformanceParameters(void) SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); + SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); + SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); + SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); + SetParameter (ParameterLimiterThresh, m_PerformanceConfig.GetLimiterThresh ()); + SetParameter (ParameterLimiterRatio, m_PerformanceConfig.GetLimiterRatio ()); + SetParameter (ParameterLimiterHPFilterEnable, m_PerformanceConfig.GetLimiterHPFilterEnable ()); + m_UI.DisplayChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index 0f5b34796..ce2be7759 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -50,6 +50,7 @@ #include "effect_platervbstereo.h" #include "udpmididevice.h" #include "net/ftpdaemon.h" +#include "../Synth_Dexed/src/compressor.h" class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE @@ -175,6 +176,13 @@ class CMiniDexed ParameterPerformanceSelectChannel, ParameterPerformanceBank, ParameterMasterVolume, + ParameterLimiterEnable, + ParameterLimiterPreGain, + ParameterLimiterAttack, + ParameterLimiterRelease, + ParameterLimiterThresh, + ParameterLimiterRatio, + ParameterLimiterHPFilterEnable, ParameterUnknown }; @@ -360,6 +368,9 @@ class CMiniDexed CSpinLock m_ReverbSpinLock; + Compressor m_Limiter[2]; + CSpinLock m_LimiterSpinLock; + // Network CNetSubSystem* m_pNet; CNetDevice* m_pNetDevice; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 35b5a4768..c2a332d11 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -237,6 +237,14 @@ bool CPerformanceConfig::Load (void) m_nReverbDiffusion = m_Properties.GetNumber ("ReverbDiffusion", 65); m_nReverbLevel = m_Properties.GetNumber ("ReverbLevel", 99); + m_bLimiterEnable = m_Properties.GetNumber ("LimiterEnable", 1); + m_nLimiterPreGain = m_Properties.GetSignedNumber ("LimiterPreGain", 0); + m_nLimiterAttack = m_Properties.GetNumber ("LimiterAttack", 5); + m_nLimiterRelease = m_Properties.GetNumber ("LimiterRelease", 5); + m_nLimiterThresh = m_Properties.GetSignedNumber ("LimiterThresh", -3); + m_nLimiterRatio = m_Properties.GetNumber ("LimiterRatio", 20); + m_bLimiterHPFilterEnable = m_Properties.GetNumber ("LimiterHPFilterEnable", 0); + // Compatibility if (m_Properties.IsSet ("CompressorEnable") && m_Properties.GetNumber ("CompressorEnable", 1) == 0) { @@ -380,6 +388,14 @@ bool CPerformanceConfig::Save (void) m_Properties.SetNumber ("ReverbDiffusion", m_nReverbDiffusion); m_Properties.SetNumber ("ReverbLevel", m_nReverbLevel); + m_Properties.SetNumber ("LimiterEnable", m_bLimiterEnable); + m_Properties.SetSignedNumber ("LimiterPreGain", m_nLimiterPreGain); + m_Properties.SetNumber ("LimiterAttack", m_nLimiterAttack); + m_Properties.SetNumber ("LimiterRelease", m_nLimiterRelease); + m_Properties.SetSignedNumber ("LimiterThresh", m_nLimiterThresh); + m_Properties.SetNumber ("LimiterRatio", m_nLimiterRatio); + m_Properties.SetNumber ("LimiterHPFilterEnable", m_bLimiterHPFilterEnable); + return m_Properties.Save (); } @@ -596,6 +612,77 @@ void CPerformanceConfig::SetReverbLevel (unsigned nValue) { m_nReverbLevel = nValue; } + +bool CPerformanceConfig::GetLimiterEnable () const +{ + return m_bLimiterEnable; +} + +int CPerformanceConfig::GetLimiterPreGain () const +{ + return m_nLimiterPreGain; +} + +unsigned CPerformanceConfig::GetLimiterAttack () const +{ + return m_nLimiterAttack; +} + +unsigned CPerformanceConfig::GetLimiterRelease () const +{ + return m_nLimiterRelease; +} + +int CPerformanceConfig::GetLimiterThresh () const +{ + return m_nLimiterThresh; +} + +unsigned CPerformanceConfig::GetLimiterRatio () const +{ + return m_nLimiterRatio; +} + +bool CPerformanceConfig::GetLimiterHPFilterEnable () const +{ + return m_bLimiterHPFilterEnable; +} + +void CPerformanceConfig::SetLimiterEnable (bool nValue) +{ + m_bLimiterEnable = nValue; +} + +void CPerformanceConfig::SetLimiterPreGain (int nValue) +{ + m_nLimiterPreGain= nValue; +} + +void CPerformanceConfig::SetLimiterAttack (unsigned nValue) +{ + m_nLimiterAttack = nValue; +} + +void CPerformanceConfig::SetLimiterRelease (unsigned nValue) +{ + m_nLimiterRelease = nValue; +} + +void CPerformanceConfig::SetLimiterThresh (int nValue) +{ + m_nLimiterThresh = nValue; +} + +void CPerformanceConfig::SetLimiterRatio (unsigned nValue) +{ + m_nLimiterRatio = nValue; +} + +void CPerformanceConfig::SetLimiterHPFilterEnable (bool nValue) +{ + m_bLimiterHPFilterEnable = nValue; +} + // Pitch bender and portamento: void CPerformanceConfig::SetPitchBendRange (unsigned nValue, unsigned nTG) { diff --git a/src/performanceconfig.h b/src/performanceconfig.h index b1227dd60..18f9de25d 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -132,6 +132,22 @@ class CPerformanceConfig // Performance configuration void SetReverbDiffusion (unsigned nValue); void SetReverbLevel (unsigned nValue); + bool GetLimiterEnable () const; + int GetLimiterPreGain () const; + unsigned GetLimiterAttack () const; + unsigned GetLimiterRelease () const; + int GetLimiterThresh () const; + unsigned GetLimiterRatio () const; + bool GetLimiterHPFilterEnable () const; + + void SetLimiterEnable (bool nValue); + void SetLimiterPreGain (int nValue); + void SetLimiterAttack (unsigned nValue); + void SetLimiterRelease (unsigned nValue); + void SetLimiterThresh (int nValue); + void SetLimiterRatio (unsigned nValue); + void SetLimiterHPFilterEnable (bool nValue); + bool VoiceDataFilled(unsigned nTG); bool ListPerformances(); //std::string m_DirName; @@ -222,6 +238,14 @@ class CPerformanceConfig // Performance configuration unsigned m_nReverbLowPass; unsigned m_nReverbDiffusion; unsigned m_nReverbLevel; + + bool m_bLimiterEnable; + int m_nLimiterPreGain; + unsigned m_nLimiterAttack; + unsigned m_nLimiterRelease; + int m_nLimiterThresh; + unsigned m_nLimiterRatio; + bool m_bLimiterHPFilterEnable; }; #endif diff --git a/src/uimenu.cpp b/src/uimenu.cpp index fcfd45428..92d8737a3 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -107,6 +107,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { #ifdef ARM_ALLOW_MULTI_CORE {"Reverb", MenuHandler, s_ReverbMenu}, + {"Limiter", MenuHandler, s_LimiterMenu}, #endif {0} }; @@ -158,6 +159,18 @@ const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_LimiterMenu[] = +{ + {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterEnable}, + {"Pre Gain", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterPreGain}, + {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterAttack}, + {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRelease}, + {"Threshold", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterThresh}, + {"Ratio", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRatio}, + {"HPFilter", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterHPFilterEnable}, + {0} +}; + #endif // inserting menu items before "OP1" affect OPShortcutHandler() @@ -240,6 +253,13 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank {0, 127, 8, ToVolume}, // ParameterMasterVolume + {0, 1, 1, ToOnOff}, // ParameterLimiterEnable + {-20, 20, 1, TodB}, // ParameterLimiterPreGain + {0, 1000, 5, ToMillisec}, // ParameterLimiterAttack + {0, 1000, 5, ToMillisec}, // ParameterLimiterRelease + {-60, 0, 1, TodBFS}, // ParameterLimiterThresh + {1, 20, 1, ToRatio}, // ParameterLimiterRatio + {0, 1, 1, ToOnOff}, // ParameterLimiterHPFilterEnable }; // must match CMiniDexed::TTGParameter diff --git a/src/uimenu.h b/src/uimenu.h index f099d1b8f..a53f1e7ab 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -159,6 +159,7 @@ class CUIMenu static const TMenuItem s_TGMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_ReverbMenu[]; + static const TMenuItem s_LimiterMenu[]; static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; From 738cf6d1e73b510aa1b97c3c862e69f33d0ccca4 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 3 Aug 2025 21:24:24 +0200 Subject: [PATCH 023/136] uimenu: use math.h instead of cmath the cmath include doesn't work with arm_math.h with gcc13.3 --- src/uimenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 92d8737a3..a3cb919b8 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -26,7 +26,7 @@ #include "userinterface.h" #include "sysexfileloader.h" #include "config.h" -#include +#include #include #include #include From 29630c5c5cef2265bbbc526567374d07e562d64b Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 3 Aug 2025 21:21:16 +0200 Subject: [PATCH 024/136] performanceconfig: fix warnings from newer compilers calling std::string::operator= with nullptr is invalid, so clear it instead. --- src/performanceconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index c2a332d11..0224e647c 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -1144,13 +1144,13 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) FRESULT Result = f_open (&File, nFileName.c_str(), FA_WRITE | FA_CREATE_ALWAYS); if (Result != FR_OK) { - m_PerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance].clear(); return false; } if (f_close (&File) != FR_OK) { - m_PerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance].clear(); return false; } From 931854fcf6954de2c472c272266b4b058cfa5b6f Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 3 Aug 2025 21:32:40 +0200 Subject: [PATCH 025/136] remove the unused CStdlibAppNetwork this suppress warning about the incompatible overloaded Initialize() function --- src/circle_stdlib_app.h | 68 ----------------------------------------- 1 file changed, 68 deletions(-) diff --git a/src/circle_stdlib_app.h b/src/circle_stdlib_app.h index 8a69c8280..35ddee0fc 100644 --- a/src/circle_stdlib_app.h +++ b/src/circle_stdlib_app.h @@ -225,72 +225,4 @@ class CStdlibAppStdio: public CStdlibAppScreen CConsole mConsole; }; -/** - * Stdlib application that adds network functionality - * to the CStdlibAppStdio features. - */ -class CStdlibAppNetwork: public CStdlibAppStdio -{ -public: - #define CSTDLIBAPP_WLAN_FIRMWARE_PATH CSTDLIBAPP_DEFAULT_PARTITION "/firmware/" - #define CSTDLIBAPP_WLAN_CONFIG_FILE CSTDLIBAPP_DEFAULT_PARTITION "/wpa_supplicant.conf" - - CStdlibAppNetwork (const char *kernel, - const char *pPartitionName = CSTDLIBAPP_DEFAULT_PARTITION, - const u8 *pIPAddress = 0, // use DHCP if pIPAddress == 0 - const u8 *pNetMask = 0, - const u8 *pDefaultGateway = 0, - const u8 *pDNSServer = 0, - TNetDeviceType DeviceType = NetDeviceTypeEthernet) - : CStdlibAppStdio(kernel, pPartitionName), - mDeviceType (DeviceType), - mWLAN (CSTDLIBAPP_WLAN_FIRMWARE_PATH), - mNet(pIPAddress, pNetMask, pDefaultGateway, pDNSServer, DEFAULT_HOSTNAME, DeviceType), - mWPASupplicant (CSTDLIBAPP_WLAN_CONFIG_FILE) - { - } - - virtual bool Initialize (bool const bWaitForActivate = true) - { - if (!CStdlibAppStdio::Initialize ()) - { - return false; - } - - if (mDeviceType == NetDeviceTypeWLAN) - { - if (!mWLAN.Initialize ()) - { - return false; - } - } - - if (!mNet.Initialize (false)) - { - return false; - } - - if (mDeviceType == NetDeviceTypeWLAN) - { - if (!mWPASupplicant.Initialize ()) - { - return false; - } - } - - while (bWaitForActivate && !mNet.IsRunning ()) - { - mScheduler.Yield (); - } - - return true; - } - -protected: - CScheduler mScheduler; - TNetDeviceType mDeviceType; - CBcm4343Device mWLAN; - CNetSubSystem mNet; - CWPASupplicant mWPASupplicant; -}; #endif From a82ecc753a6951cce9629d9a7751b5d8acf04abc Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 3 Aug 2025 21:34:09 +0200 Subject: [PATCH 026/136] gitignore: add the new arm-gnu-* toolchain prefix --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 18989bd46..a60bf4581 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ # Toolchain gcc-* +arm-gnu-* # Build artifacts kernel* From 07b61a51f1c09913d370f9da0d5e0450a8597592 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 4 Aug 2025 01:34:46 +0200 Subject: [PATCH 027/136] Makefile: add $(OBJS) and $(DEPS) to EXTRACLEAN and use the existing clean --- src/Makefile | 9 ++------- src/Synth_Dexed.mk | 2 -- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Makefile b/src/Makefile index 36a49377b..b6232edf8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,14 +13,9 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ arm_float_to_q23.o arm_scale_zc_ramp_f32.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o +EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) + OPTIMIZE = -O3 include ./Synth_Dexed.mk include ./Rules.mk - -# Clean target -.PHONY: clean - -clean: - @echo "Cleaning up..." - rm -f $(OBJS) *.o *.d *~ core diff --git a/src/Synth_Dexed.mk b/src/Synth_Dexed.mk index 4d42e6707..baea70844 100644 --- a/src/Synth_Dexed.mk +++ b/src/Synth_Dexed.mk @@ -45,5 +45,3 @@ DEFINE += -DARM_MATH_NEON DEFINE += -DARM_MATH_NEON_EXPERIMENTAL DEFINE += -DHAVE_NEON endif - -EXTRACLEAN = $(SYNTH_DEXED_DIR)/*.[od] $(CMSIS_DSP_SOURCE_DIR)/SupportFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/SupportFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/BasicMathFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/FastMathFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/FilteringFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/CommonTables/*.[od] $(CMSIS_DSP_COMPUTELIB_SRC_DIR)/*.[od] From da449356db4643f5c15660e45a2dce701e92b4cb Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 4 Aug 2025 03:38:04 +0200 Subject: [PATCH 028/136] remove the obsolete USE_FX from Synth_Dexed Makefile this has already been removed from Synth_dexed https://codeberg.org/dcoredump/Synth_Dexed/commit/b75b95986ac1f116809f1445e05e557f4ae79384 --- src/Synth_Dexed.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Synth_Dexed.mk b/src/Synth_Dexed.mk index baea70844..2b83a0427 100644 --- a/src/Synth_Dexed.mk +++ b/src/Synth_Dexed.mk @@ -38,8 +38,6 @@ INCLUDE += -I $(CMSIS_DSP_INCLUDE_DIR) INCLUDE += -I $(CMSIS_DSP_PRIVATE_INCLUDE_DIR) INCLUDE += -I $(CMSIS_DSP_COMPUTELIB_INCLUDE_DIR) -DEFINE += -DUSE_FX - ifeq ($(RPI), $(filter $(RPI), 3 4 5)) DEFINE += -DARM_MATH_NEON DEFINE += -DARM_MATH_NEON_EXPERIMENTAL From 90ab49e89b4b12efc9d62bdb998eccf08518e699 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 4 Aug 2025 02:31:24 +0200 Subject: [PATCH 029/136] gh build: use gcc13.3 --- .github/workflows/build.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f3a2fd78..c85c21bb1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,34 +36,34 @@ jobs: - name: Install 64-bit toolchain run: | set -ex - 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 + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz + tar xf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz - name: Build for Raspberry Pi 5 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=5 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 4 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=4 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 3 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=3 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Prepare SD card content for 64-bit run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH cd ./circle-stdlib/libs/circle/boot make make armstub64 @@ -121,20 +121,20 @@ jobs: - name: Install 32-bit toolchain run: | set -ex - 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 + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz + tar xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz - name: Build for Raspberry Pi 2 (32-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-arm-none-eabi/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=2 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 1 (32-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-arm-none-eabi/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=1 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ From 85b1d87a40560e105c69478e82e81c07852a9f45 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 8 Aug 2025 18:41:11 +0200 Subject: [PATCH 030/136] config: return CIPAddress as const reference returning by value calls CIPAddress::CIPAddress (const CIPAddress &rAddress) which assert (rAddress.m_bValid) so any unset ip will fail in debug builds --- src/config.cpp | 10 +++++----- src/config.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index d8a9d7717..c450a57db 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -773,22 +773,22 @@ const char *CConfig::GetNetworkHostname (void) const return m_NetworkHostname.c_str(); } -CIPAddress CConfig::GetNetworkIPAddress (void) const +const CIPAddress& CConfig::GetNetworkIPAddress (void) const { return m_INetworkIPAddress; } -CIPAddress CConfig::GetNetworkSubnetMask (void) const +const CIPAddress& CConfig::GetNetworkSubnetMask (void) const { return m_INetworkSubnetMask; } -CIPAddress CConfig::GetNetworkDefaultGateway (void) const +const CIPAddress& CConfig::GetNetworkDefaultGateway (void) const { return m_INetworkDefaultGateway; } -CIPAddress CConfig::GetNetworkDNSServer (void) const +const CIPAddress& CConfig::GetNetworkDNSServer (void) const { return m_INetworkDNSServer; } @@ -798,7 +798,7 @@ bool CConfig::GetSyslogEnabled (void) const return m_bSyslogEnabled; } -CIPAddress CConfig::GetNetworkSyslogServerIPAddress (void) const +const CIPAddress& CConfig::GetNetworkSyslogServerIPAddress (void) const { return m_INetworkSyslogServerIPAddress; } diff --git a/src/config.h b/src/config.h index 1bb900ba7..ce89d7d91 100644 --- a/src/config.h +++ b/src/config.h @@ -249,12 +249,12 @@ class CConfig // Configuration for MiniDexed bool GetNetworkDHCP (void) const; const char *GetNetworkType (void) const; const char *GetNetworkHostname (void) const; - CIPAddress GetNetworkIPAddress (void) const; - CIPAddress GetNetworkSubnetMask (void) const; - CIPAddress GetNetworkDefaultGateway (void) const; - CIPAddress GetNetworkDNSServer (void) const; + const CIPAddress& GetNetworkIPAddress (void) const; + const CIPAddress& GetNetworkSubnetMask (void) const; + const CIPAddress& GetNetworkDefaultGateway (void) const; + const CIPAddress& GetNetworkDNSServer (void) const; bool GetSyslogEnabled (void) const; - CIPAddress GetNetworkSyslogServerIPAddress (void) const; + const CIPAddress& GetNetworkSyslogServerIPAddress (void) const; bool GetNetworkFTPEnabled (void) const; private: From eb5d455fd151ddb390cd03242fd53f76afe5013b Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 8 Aug 2025 18:41:40 +0200 Subject: [PATCH 031/136] config: set ip addresses only if they are valid --- src/config.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index c450a57db..ec5b36100 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -208,18 +208,13 @@ void CConfig::Load (void) m_bNetworkDHCP = m_Properties.GetNumber ("NetworkDHCP", 0) != 0; m_NetworkType = m_Properties.GetString ("NetworkType", "wlan"); m_NetworkHostname = m_Properties.GetString ("NetworkHostname", "MiniDexed"); - m_INetworkIPAddress = m_Properties.GetIPAddress("NetworkIPAddress") != 0; - m_INetworkSubnetMask = m_Properties.GetIPAddress("NetworkSubnetMask") != 0; - m_INetworkDefaultGateway = m_Properties.GetIPAddress("NetworkDefaultGateway") != 0; + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkIPAddress")) m_INetworkIPAddress.Set (pIP); + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkSubnetMask")) m_INetworkSubnetMask.Set (pIP); + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkDefaultGateway")) m_INetworkDefaultGateway.Set (pIP); m_bSyslogEnabled = m_Properties.GetNumber ("NetworkSyslogEnabled", 0) != 0; - m_INetworkDNSServer = m_Properties.GetIPAddress("NetworkDNSServer") != 0; + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkDNSServer")) m_INetworkDNSServer.Set (pIP); m_bNetworkFTPEnabled = m_Properties.GetNumber("NetworkFTPEnabled", 0) != 0; - - const u8 *pSyslogServerIP = m_Properties.GetIPAddress ("NetworkSyslogServerIPAddress"); - if (pSyslogServerIP) - { - m_INetworkSyslogServerIPAddress.Set (pSyslogServerIP); - } + if (const u8 *pIP = m_Properties.GetIPAddress ("NetworkSyslogServerIPAddress")) m_INetworkSyslogServerIPAddress.Set (pIP); m_nMasterVolume = m_Properties.GetNumber ("MasterVolume", 64); From 8e674c97b5416d94dd37aa5fa61f7dce1e59d456 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 8 Aug 2025 18:44:11 +0200 Subject: [PATCH 032/136] InitNetwork: check IP addresses properly --- src/minidexed.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 59987ab87..b8cf63732 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -2524,7 +2524,7 @@ void CMiniDexed::UpdateNetwork() if (m_pConfig->GetSyslogEnabled()) { LOGNOTE ("Syslog server is enabled in configuration"); - CIPAddress ServerIP = m_pConfig->GetNetworkSyslogServerIPAddress(); + const CIPAddress& ServerIP = m_pConfig->GetNetworkSyslogServerIPAddress(); if (ServerIP.IsSet () && !ServerIP.IsNull ()) { static const u16 usServerPort = 8514; @@ -2621,18 +2621,31 @@ bool CMiniDexed::InitNetwork() if (NetDeviceType != NetDeviceTypeUnknown) { - LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem"); if (m_pConfig->GetNetworkDHCP()) + { + LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem with DHCP (Hostname: %s)", m_pConfig->GetNetworkHostname()); m_pNet = new CNetSubSystem(0, 0, 0, 0, m_pConfig->GetNetworkHostname(), NetDeviceType); - else + } + else if (m_pConfig->GetNetworkIPAddress().IsSet() && m_pConfig->GetNetworkSubnetMask().IsSet()) + { + CString IPString, SubnetString; + m_pConfig->GetNetworkIPAddress().Format (&IPString); + m_pConfig->GetNetworkSubnetMask().Format (&SubnetString); + LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem with IP: %s / %s", (const char*)IPString, (const char*)SubnetString); m_pNet = new CNetSubSystem( m_pConfig->GetNetworkIPAddress().Get(), m_pConfig->GetNetworkSubnetMask().Get(), - m_pConfig->GetNetworkDefaultGateway().Get(), - m_pConfig->GetNetworkDNSServer().Get(), + m_pConfig->GetNetworkDefaultGateway().IsSet() ? m_pConfig->GetNetworkDefaultGateway().Get() : 0, + m_pConfig->GetNetworkDNSServer().IsSet() ? m_pConfig->GetNetworkDNSServer().Get() : 0, m_pConfig->GetNetworkHostname(), - NetDeviceType - ); + NetDeviceType); + } + else + { + LOGNOTE ("CMiniDexed::InitNetwork: Neither DHCP nor IP address/subnet mask is set, using DHCP (Hostname: %s)", m_pConfig->GetNetworkHostname()); + m_pNet = new CNetSubSystem(0, 0, 0, 0, m_pConfig->GetNetworkHostname(), NetDeviceType); + } + if (!m_pNet || !m_pNet->Initialize(false)) // Check if m_pNet allocation succeeded { LOGERR("CMiniDexed::InitNetwork: Failed to initialize network subsystem"); From 314720de5c3b77c8fd69c94040a7ebceb676a7b0 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 12 Aug 2025 23:36:34 +0200 Subject: [PATCH 033/136] gh build: create DreamDexed zips --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c85c21bb1..6000a1025 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,7 +93,7 @@ jobs: id: upload64 uses: actions/upload-artifact@v4 with: - name: MiniDexed_${{ github.run_number }}_${{ steps.gitinfo.outputs.git_info }}_64bit + name: DreamDexed_${{ github.run_number }}_${{ steps.gitinfo.outputs.git_info }}_64bit path: sdcard/* build32: @@ -142,7 +142,7 @@ jobs: id: upload32 uses: actions/upload-artifact@v4 with: - name: MiniDexed_${{ github.run_number }}_${{ env.GIT_INFO }}_32bit + name: DreamDexed_${{ github.run_number }}_${{ env.GIT_INFO }}_32bit path: sdcard/* combine: @@ -153,14 +153,14 @@ jobs: - name: Download artifacts uses: actions/download-artifact@v4 with: - pattern: MiniDexed_* + pattern: DreamDexed_* merge-multiple: true path: combined - name: Create combined ZIP file run: | cd combined - zip -r ../MiniDexed_${{ github.run_number }}_${{ needs.build64.outputs.git_info }}.zip . + zip -r ../DreamDexed_${{ github.run_number }}_${{ needs.build64.outputs.git_info }}.zip . cd .. - name: Upload to GitHub Releases (only when building from main branch) @@ -171,4 +171,4 @@ jobs: export UPLOADTOOL_PR_BODY="This is a continuous build. Feedback is appreciated." export UPLOADTOOL_BODY="This is a continuous build. Feedback is appreciated." wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh - bash ./upload.sh ./MiniDexed*.zip + bash ./upload.sh ./DreamDexed*.zip From 62937bbf96341ab7bfde14dc932e852eaddda5d7 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 00:18:35 +0200 Subject: [PATCH 034/136] README: update to DreamDexed [ci skip] --- README.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cf33d173b..a77b92f8d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,21 @@ -# MiniDexed ![Github Build Status](https://github.com/probonopd/MiniDexed/actions/workflows/build.yml/badge.svg) +# DreamDexed ![Github Build Status](https://github.com/DreamDexed/DreamDexed/actions/workflows/build.yml/badge.svg) + +DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with the following additional features: + +- [x] Configurable default screen +- [x] Noiseless volume change +- [x] Configurable TG compressors +- [x] Limiter +- [ ] 3-band EQ +- [ ] Two Effect Send with Chrous, Delay, Reverb +- [ ] 8 channel mixer (Rpi4+) +- [ ] Multiple parts (RPi4+) +- [ ] Overlay Menu for easier parameter changes +- [ ] MIDI Controller DAW integration ![minidexed](https://user-images.githubusercontent.com/2480569/161813414-bb156a1c-efec-44c0-802a-8926412a08e0.jpg) -MiniDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). +DreamDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). ## Demo songs @@ -101,6 +114,3 @@ This project stands on the shoulders of giants. Special thanks to: - [dwhinham/mt32-pi](https://github.com/dwhinham/mt32-pi) for creating networking support for Circle - [omersiar](https://github.com/omersiar) for porting networking support to MiniDexed - [soyersoyer](https://github.com/soyersoyer) for sound and other improvements, and for debugging - -## Stargazers over time -[![Stargazers over time](https://starchart.cc/probonopd/MiniDexed.svg?variant=adaptive)](https://starchart.cc/probonopd/MiniDexed) From e35fe9fb42c19e13e8ea30aba51cbc779773080b Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 00:39:12 +0200 Subject: [PATCH 035/136] README: update wiki links [ci skip] --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a77b92f8d..40e8f7a75 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Listen to some examples made with MiniDexed by Banana71 [here](https://soundclou - [x] Uses [Synth_Dexed](https://codeberg.org/dcoredump/Synth_Dexed) with [circle-stdlib](https://github.com/smuehlst/circle-stdlib) - [x] SD card contents can be downloaded from [GitHub Releases](../../releases) - [x] Runs on all Raspberry Pi models (except Pico); see below for details -- [x] Produces sound on the headphone jack, HDMI display or [audio extractor](https://github.com/probonopd/MiniDexed/wiki/Hardware#hdmi-to-audio) (better), or a [dedicated DAC](https://github.com/probonopd/MiniDexed/wiki/Hardware#i2s-dac) (best) +- [x] Produces sound on the headphone jack, HDMI display or [audio extractor](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#hdmi-to-audio) (better), or a [dedicated DAC](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#i2s-dac) (best) - [x] Supports multiple voices through Program Change and Bank Change LSB/MSB MIDI messages - [x] Loads voices from `.syx` files from SD card (e.g., using `getsysex.sh` or from [Dexed_cart_1.0.zip](http://hsjp.eu/downloads/Dexed/Dexed_cart_1.0.zip)) - [x] Menu structure on optional [HD44780 display](https://www.berrybase.de/sensoren-module/displays/alphanumerische-displays/alphanumerisches-lcd-16x2-gr-252-n/gelb) and rotary encoder @@ -35,7 +35,7 @@ Listen to some examples made with MiniDexed by Banana71 [here](https://soundclou - [x] Allows to configure multiple Dexed instances through `performance.ini` files (e.g., [converted](https://github.com/BobanSpasic/MDX_Vault) from DX1, DX5, TX816, DX7II, TX802) - [x] Compressor effect - [x] Reverb effect -- [x] Voices can be edited over MIDI, e.g., using the [synthmata](https://synthmata.github.io/volca-fm/) online editor (requires [additional hardware](https://github.com/probonopd/MiniDexed/wiki/Hardware#usb-midi-devices)) +- [x] Voices can be edited over MIDI, e.g., using the [synthmata](https://synthmata.github.io/volca-fm/) online editor (requires [additional hardware](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#usb-midi-devices)) ## Introduction @@ -46,8 +46,8 @@ Video about this project by [Floyd Steinberg](https://www.youtube.com/watch?v=Z3 ## System Requirements - Raspberry Pi 1, 2, 3, 4, or 400. Raspberry Pi Zero and Zero 2 can be used but need HDMI or a supported i2s DAC for audio out. On Raspberry Pi 1 and on Raspberry Pi Zero there will be severely limited functionality (only one tone generator instead of 8) -- Raspberry Pi 5 can be used but currently support is experimental: HDMI sound and USB Gadget mode are not available yet, and it is not clear if there are implications for cooling from running MiniDexed. Also, MiniDexed is currently not taking advantage of the higher processing power of the Raspberry Pi 5 yet. *Hence, you may consider using one of the less expensive, older Raspberry Pi boards for your first build.* -- A [PCM5102A or PCM5122 based DAC](https://github.com/probonopd/MiniDexed/wiki/Hardware#i2s-dac), HDMI display or [audio extractor](https://github.com/probonopd/MiniDexed/wiki/Hardware#hdmi-to-audio) for good sound quality. If you don't have this, you can use the headphone jack on the Raspberry Pi but on anything but the Raspberry 4 the sound quality will be seriously limited +- Raspberry Pi 5 can be used but currently support is experimental: HDMI sound and USB Gadget mode are not available yet, and it is not clear if there are implications for cooling from running DreamDexed. Also, DreamDexed is currently not taking advantage of the higher processing power of the Raspberry Pi 5 yet. *Hence, you may consider using one of the less expensive, older Raspberry Pi boards for your first build.* +- A [PCM5102A or PCM5122 based DAC](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#i2s-dac), HDMI display or [audio extractor](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#hdmi-to-audio) for good sound quality. If you don't have this, you can use the headphone jack on the Raspberry Pi but on anything but the Raspberry 4 the sound quality will be seriously limited - Optionally (but highly recommended), an [LCDC1602 Display](https://www.berrybase.de/en/sensors-modules/displays/alphanumeric-displays/alphanumerisches-lcd-16x2-gr-252-n/gelb) (with or without i2c "backpack" board) and a [KY-040 rotary encoder](https://www.berrybase.de/en/components/passive-components/potentiometer/rotary-encoder/drehregler/rotary-encoder-mit-breakoutboard-ohne-gewinde-und-mutter) ## Usage @@ -66,10 +66,10 @@ Video about this project by [Floyd Steinberg](https://www.youtube.com/watch?v=Z3 - Start playing - If the system seems to become unresponsive after a few seconds, remove `usbspeed=full` from `cmdline.txt` and repeat ([details](https://github.com/probonopd/MiniDexed/issues/39)) - Optionally, put voices in `.syx` files onto the SD card (e.g., using `getsysex.sh`) -- See the Wiki for [Menu](https://github.com/probonopd/MiniDexed/wiki/Menu) operation +- See the Wiki for [Menu](https://github.com/DreamDexed/DreamDexed/wiki/Menu) operation - For voice programming, use any DX series editor (using MIDI sysex), including Dexed - For library management, use the dedicated [MiniDexedLibrarian](https://github.com/BobanSpasic/MiniDexedLibrarian) software -- If something is unclear or does not work, don't hesitate to [ask](https://github.com/probonopd/MiniDexed/discussions/)! +- If something is unclear or does not work, don't hesitate to [ask](https://github.com/DreamDexed/DreamDexed/discussions/)! ## Pinout @@ -77,7 +77,7 @@ All devices on Raspberry Pi GPIOs are **optional**. ![Raspberry Pi Pinout/GPIO Diagram](https://user-images.githubusercontent.com/2480569/166105580-da11481c-8fc7-4375-8ab1-3031ab5c6ad0.png) -Please see the [wiki](https://github.com/probonopd/MiniDexed/wiki) for more information. +Please see the [wiki](https://github.com/DreamDexed/DreamDexed/wiki) for more information. ## Downloading @@ -85,19 +85,19 @@ Compiled versions are available on [GitHub Releases](../../releases). Just downl ## Building -Please see the [wiki](https://github.com/probonopd/MiniDexed/wiki/Development#building-locally) on how to compile the code yourself. +Please see the [wiki](https://github.com/DreamDexed/DreamDexed/wiki/Development#building-locally) on how to compile the code yourself. ## Contributing -This project lives from the contributions of skilled C++ developers, testers, writers, etc. Please see . +This project lives from the contributions of skilled C++ developers, testers, writers, etc. Please see . ## Discussions -We are happy to hear from you. Please join the discussions on . +We are happy to hear from you. Please join the discussions on . ## Documentation -Project documentation is at . +Project documentation is at . ## Acknowledgements @@ -110,7 +110,7 @@ This project stands on the shoulders of giants. Special thanks to: - [smuehlst](https://github.com/smuehlst) for [circle-stdlib](https://github.com/smuehlst/circle-stdlib), a version with Standard C and C++ library support - [Banana71](https://github.com/Banana71) for the sound design of the [Soundplantage](https://github.com/Banana71/Soundplantage) performances shipped with MiniDexed - [BobanSpasic](https://github.com/BobanSpasic) for the [MiniDexedLibrarian](https://github.com/BobanSpasic/MiniDexedLibrarian) software, [MiniDexed performance converter](https://github.com/BobanSpasic/MDX_PerfConv) and [collection of performances for MiniDexed](https://github.com/BobanSpasic/MDX_Vault) -- [diyelectromusic](https://github.com/diyelectromusic/) for many [contributions](https://github.com/probonopd/MiniDexed/commits?author=diyelectromusic) +- [diyelectromusic](https://github.com/diyelectromusic/) for many [contributions](https://github.com/DreamDexed/DreamDexed/commits?author=diyelectromusic) - [dwhinham/mt32-pi](https://github.com/dwhinham/mt32-pi) for creating networking support for Circle - [omersiar](https://github.com/omersiar) for porting networking support to MiniDexed - [soyersoyer](https://github.com/soyersoyer) for sound and other improvements, and for debugging From f4125f9c87b77b729c542521ead487d19133727d Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 3 Jan 2025 02:58:08 +0100 Subject: [PATCH 036/136] add synchronization for multcore operations --- src/minidexed.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/minidexed.h b/src/minidexed.h index ce2be7759..0dd9f0047 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -30,6 +30,7 @@ #include "serialmididevice.h" #include "perftimer.h" #include +#include #include #include #include @@ -354,8 +355,8 @@ class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE // unsigned m_nActiveTGsLog2; - volatile TCoreStatus m_CoreStatus[CORES]; - volatile unsigned m_nFramesToProcess; + std::atomic m_CoreStatus[CORES]; + std::atomic m_nFramesToProcess; float32_t m_OutputLevel[CConfig::AllToneGenerators][CConfig::MaxChunkSize]; #endif From 58686116cbcbfe16d81fdedb18d31780d4e65eb2 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 3 Jan 2025 03:00:00 +0100 Subject: [PATCH 037/136] suspend cores while waiting It works with WaitForEvent, without disabling IRQs. Before this the WaitForInterrupt was used, and these findigs were useful: Before checking the atomic variable, disable IRQs to avoid missing the wake-up event. https://marc.info/?l=linux-arm-kernel&m=114684008423863&w=2 https://electronics.stackexchange.com/questions/12601/best-pattern-for-wfi-wait-for-interrupt-on-cortex-arm-microcontrolers add dsb before wfi https://github.com/torvalds/linux/commit/8553cb67d2318db327071018fc81084cbabccc46 https://github.com/torvalds/linux/blob/master/arch/arm/mm/proc-v7.S https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/idle.c https://github.com/torvalds/linux/commit/9cce7a435f89c9e60f244d44da2cf1cf4ed094ac --- src/minidexed.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b8cf63732..db3774a88 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -504,7 +504,7 @@ void CMiniDexed::Run (unsigned nCore) { while (m_CoreStatus[nCore] != CoreStatusIdle) { - // just wait + WaitForEvent (); } } @@ -518,9 +518,11 @@ void CMiniDexed::Run (unsigned nCore) while (1) { m_CoreStatus[nCore] = CoreStatusIdle; // ready to be kicked + SendIPI (1, IPI_USER); + while (m_CoreStatus[nCore] == CoreStatusIdle) { - // just wait + WaitForEvent (); } // now kicked from core 1 @@ -1404,6 +1406,7 @@ void CMiniDexed::ProcessSound (void) { assert (m_CoreStatus[nCore] == CoreStatusIdle); m_CoreStatus[nCore] = CoreStatusBusy; + SendIPI (nCore, IPI_USER); } // process the TGs assigned to core 1 @@ -1419,7 +1422,7 @@ void CMiniDexed::ProcessSound (void) { while (m_CoreStatus[nCore] != CoreStatusIdle) { - // just wait + WaitForEvent (); } } From 6f604b267d2447e148af3c8ae6da8390575ea707 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 03:14:54 +0200 Subject: [PATCH 038/136] CMiniDexed: fix LoadPerformanceParameters indent --- src/minidexed.cpp | 116 +++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index db3774a88..415d76526 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -2187,70 +2187,70 @@ bool CMiniDexed::DoSavePerformanceNewFile (void) void CMiniDexed::LoadPerformanceParameters(void) { for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) + { + BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG); + ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); + SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); + SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); + SetPan (m_PerformanceConfig.GetPan (nTG), nTG); + SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); + SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); + SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); + setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); + setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); + setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); + setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); + setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); + + m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); + m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); + m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); + + if(m_PerformanceConfig.VoiceDataFilled(nTG)) { - - BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG); - ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); - SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); - SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); - SetPan (m_PerformanceConfig.GetPan (nTG), nTG); - SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); - SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); - SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); - setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); - setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); - setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); - setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); - setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); - - m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); - m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); - m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); - - if(m_PerformanceConfig.VoiceDataFilled(nTG)) - { uint8_t* tVoiceData = m_PerformanceConfig.GetVoiceDataFromTxt(nTG); m_pTG[nTG]->loadVoiceParameters(tVoiceData); setOPMask(0b111111, nTG); - } - setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); - SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); - - setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); - setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); - setFootControllerRange (m_PerformanceConfig.GetFootControlRange (nTG), nTG); - setFootControllerTarget (m_PerformanceConfig.GetFootControlTarget (nTG), nTG); - setBreathControllerRange (m_PerformanceConfig.GetBreathControlRange (nTG), nTG); - setBreathControllerTarget (m_PerformanceConfig.GetBreathControlTarget (nTG), nTG); - setAftertouchRange (m_PerformanceConfig.GetAftertouchRange (nTG), nTG); - setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); - - SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); - SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); - SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; - SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); - SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); - SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); } - // Effects - SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); - SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); - SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); - SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); - SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); - SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); - SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); - - SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); - SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); - SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); - SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); - SetParameter (ParameterLimiterThresh, m_PerformanceConfig.GetLimiterThresh ()); - SetParameter (ParameterLimiterRatio, m_PerformanceConfig.GetLimiterRatio ()); - SetParameter (ParameterLimiterHPFilterEnable, m_PerformanceConfig.GetLimiterHPFilterEnable ()); - - m_UI.DisplayChanged (); + setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); + SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); + + setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); + setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); + setFootControllerRange (m_PerformanceConfig.GetFootControlRange (nTG), nTG); + setFootControllerTarget (m_PerformanceConfig.GetFootControlTarget (nTG), nTG); + setBreathControllerRange (m_PerformanceConfig.GetBreathControlRange (nTG), nTG); + setBreathControllerTarget (m_PerformanceConfig.GetBreathControlTarget (nTG), nTG); + setAftertouchRange (m_PerformanceConfig.GetAftertouchRange (nTG), nTG); + setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); + + SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); + SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); + SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; + SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); + SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); + SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); + } + + // Effects + SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); + SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); + SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); + SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); + SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); + SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); + SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + + SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); + SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); + SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); + SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); + SetParameter (ParameterLimiterThresh, m_PerformanceConfig.GetLimiterThresh ()); + SetParameter (ParameterLimiterRatio, m_PerformanceConfig.GetLimiterRatio ()); + SetParameter (ParameterLimiterHPFilterEnable, m_PerformanceConfig.GetLimiterHPFilterEnable ()); + + m_UI.DisplayChanged (); } std::string CMiniDexed::GetNewPerformanceDefaultName(void) From 3bc3fba397159c266d156101abcd18e324465f32 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 03:11:45 +0200 Subject: [PATCH 039/136] CMiniDexed: fix crash when a performance file has more TGs than m_nToneGenerators --- src/minidexed.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 415d76526..8e3e5dfbf 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -2033,6 +2033,7 @@ void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG) void CMiniDexed::setOPMask(uint8_t uchOPMask, uint8_t nTG) { + if (nTG >= m_nToneGenerators) return; // Not an active TG m_uchOPMask[nTG] = uchOPMask; m_pTG[nTG]->setOPAll (m_uchOPMask[nTG]); } @@ -2206,7 +2207,7 @@ void CMiniDexed::LoadPerformanceParameters(void) m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); - if(m_PerformanceConfig.VoiceDataFilled(nTG)) + if(m_PerformanceConfig.VoiceDataFilled(nTG) && nTG < m_nToneGenerators) { uint8_t* tVoiceData = m_PerformanceConfig.GetVoiceDataFromTxt(nTG); m_pTG[nTG]->loadVoiceParameters(tVoiceData); From 4f6eb4bc204f9d0d20731f47c512329ea9b452ed Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 05:14:11 +0200 Subject: [PATCH 040/136] README: update to DreamDexed --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40e8f7a75..4335462c4 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,9 @@ This project stands on the shoulders of giants. Special thanks to: - [raphlinus](https://github.com/raphlinus) for the [MSFA](https://github.com/google/music-synthesizer-for-android) sound engine - [asb2m10](https://github.com/asb2m10/dexed) for the [Dexed](https://github.com/asb2m10/dexed) software - [dcoredump](https://github.com/dcoredump) for [Synth Dexed](https://codeberg.org/dcoredump/Synth_Dexed), a port of Dexed for embedded systems -- [rsta2](https://github.com/rsta2) for [Circle](https://github.com/rsta2/circle), the library to run code on bare metal Raspberry Pi (without a Linux kernel or operating system) and for the bulk of the MiniDexed code +- [rsta2](https://github.com/rsta2) for [Circle](https://github.com/rsta2/circle), the library to run code on bare metal Raspberry Pi (without a Linux kernel or operating system) and for the bulk of the DreamDexed code - [smuehlst](https://github.com/smuehlst) for [circle-stdlib](https://github.com/smuehlst/circle-stdlib), a version with Standard C and C++ library support -- [Banana71](https://github.com/Banana71) for the sound design of the [Soundplantage](https://github.com/Banana71/Soundplantage) performances shipped with MiniDexed +- [Banana71](https://github.com/Banana71) for the sound design of the [Soundplantage](https://github.com/Banana71/Soundplantage) performances shipped with DreamDexed - [BobanSpasic](https://github.com/BobanSpasic) for the [MiniDexedLibrarian](https://github.com/BobanSpasic/MiniDexedLibrarian) software, [MiniDexed performance converter](https://github.com/BobanSpasic/MDX_PerfConv) and [collection of performances for MiniDexed](https://github.com/BobanSpasic/MDX_Vault) - [diyelectromusic](https://github.com/diyelectromusic/) for many [contributions](https://github.com/DreamDexed/DreamDexed/commits?author=diyelectromusic) - [dwhinham/mt32-pi](https://github.com/dwhinham/mt32-pi) for creating networking support for Circle From ceadb83bb7363c84561abf26b7c5af78e58822aa Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 17:01:12 +0200 Subject: [PATCH 041/136] add 3 Band EQ per tg --- src/effect_3bandeq.h | 130 ++++++++++++++++++++++++++++++++++++++ src/midi.h | 10 +++ src/minidexed.cpp | 116 ++++++++++++++++++++++++++++++++++ src/minidexed.h | 27 +++++++- src/performanceconfig.cpp | 112 +++++++++++++++++++++++++++++++- src/performanceconfig.h | 23 ++++++- src/uimenu.cpp | 32 ++++++++++ src/uimenu.h | 2 + 8 files changed, 448 insertions(+), 4 deletions(-) create mode 100644 src/effect_3bandeq.h diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h new file mode 100644 index 000000000..3590da9aa --- /dev/null +++ b/src/effect_3bandeq.h @@ -0,0 +1,130 @@ +/* + * DISTHRO 3 Band EQ + * Ported from https://github.com/DISTRHO/Mini-Series/blob/master/plugins/3BandEQ + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include + +#include "midi.h" + +class AudioEffect3BandEQ +{ +public: + static constexpr float kDC_ADD = 1e-30f; // Why do we need to add a small DC? + + AudioEffect3BandEQ(unsigned samplerate): + samplerate{samplerate}, + fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, + nLowMidFreq{24}, /* 315Hz */ + nMidHighFreq{44}, /* 3.2kHz */ + tmpLP{}, tmpHP{} + { + setLow_dB(fLow); + setMid_dB(fMid); + setHigh_dB(fHigh); + setGain_dB(fGain); + setLowMidFreq_n(nLowMidFreq); + setMidHighFreq_n(nMidHighFreq); + } + + void setLow_dB(float value) + { + fLow = value; + lowVol = pow(10.0f, fLow / 20.0f); + } + + void setMid_dB(float value) + { + fMid = value; + midVol = pow(10.0f, fMid / 20.0f); + } + + void setHigh_dB(float value) + { + fHigh = value; + highVol = pow(10.0f, fHigh / 20.0f); + } + + void setGain_dB(float value) + { + fGain = value; + outVol = pow(10.0f, fGain / 20.0f); + } + + float setLowMidFreq(float value) + { + fLowMidFreq = std::min(value, fMidHighFreq); + xLP = exp(-2.0f * M_PI * fLowMidFreq / samplerate); + a0LP = 1.0f - xLP; + b1LP = -xLP; + return fLowMidFreq; + } + + float setMidHighFreq(float value) + { + fMidHighFreq = std::max(value, fLowMidFreq); + xHP = exp(-2.0f * M_PI * fMidHighFreq / samplerate); + a0HP = 1.0f - xHP; + b1HP = -xHP; + return fMidHighFreq; + } + + unsigned setLowMidFreq_n(unsigned value) + { + nLowMidFreq = std::min(value, nMidHighFreq); + setLowMidFreq(MIDI_EQ_HZ[nLowMidFreq]); + return nLowMidFreq; + } + + unsigned setMidHighFreq_n(unsigned value) + { + nMidHighFreq = std::max(value, nLowMidFreq); + setMidHighFreq(MIDI_EQ_HZ[nMidHighFreq]); + return nMidHighFreq; + } + + float getLow_dB() const { return fLow; } + float getMid_dB() const { return fMid; } + float getHigh_dB() const { return fHigh; } + float getGain_dB() const { return fGain; } + float getLowMidFreq() const { return fLowMidFreq; } + float getMidHighFreq() const { return fMidHighFreq; } + unsigned getLowMidFreq_n() const { return nLowMidFreq; } + unsigned getMidHighFreq_n() const { return nMidHighFreq; } + + void process(float32_t* block, uint16_t len) + { + float outLP, outHP; + + if (!fLow && !fMid && !fHigh && !fGain) return; + + for (uint16_t i=0; i < len; ++i) + { + float inValue = isnan(block[i]) ? 0.0f : block[i]; + + tmpLP = a0LP * inValue - b1LP * tmpLP + kDC_ADD; + outLP = tmpLP - kDC_ADD; + + tmpHP = a0HP * inValue - b1HP * tmpHP + kDC_ADD; + outHP = inValue - tmpHP - kDC_ADD; + + block[i] = (outLP*lowVol + (inValue - outLP - outHP)*midVol + outHP*highVol) * outVol; + } + } + +private: + unsigned samplerate; + + float fLow, fMid, fHigh, fGain, fLowMidFreq, fMidHighFreq; + unsigned nLowMidFreq, nMidHighFreq; + + float lowVol, midVol, highVol, outVol; + + float xLP, a0LP, b1LP; + float xHP, a0HP, b1HP; + + float tmpLP, tmpHP; +}; diff --git a/src/midi.h b/src/midi.h index 76e106d0c..4155616f1 100644 --- a/src/midi.h +++ b/src/midi.h @@ -53,4 +53,14 @@ #define MIDI_PROGRAM_CHANGE 0b1100 #define MIDI_PITCH_BEND 0b1110 +static const uint16_t MIDI_EQ_HZ[] = { + 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, + 63, 70, 80, 90, 100, 110, 125, 140, 160, 180, + 200, 225, 250, 280, 315, 355, 400, 450, 500, 560, + 630, 700, 800, 900, 1000, 1100, 1200, 1400, 1600, 1800, + 2000, 2200, 2500, 2800, 3200, 3600, 4000, 4500, 5000, 5600, + 6300, 7000, 8000, 9000, 10000, 11000, 12000, 14000, 16000, 18000, + 20000 +}; + #endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 8e3e5dfbf..5d0877057 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -68,6 +68,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, reverb(nullptr), tg_mixer(nullptr), reverb_send_mixer(nullptr), + m_pEQ {}, m_Limiter {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), m_pNetDevice(nullptr), @@ -133,6 +134,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nCompressorThresh[i] = -20; m_nCompressorRatio[i] = 5; + m_nEQLow[i] = 0; + m_nEQMid[i] = 0; + m_nEQHigh[i] = 0; + m_nEQGain[i] = 0; + m_nEQLowMidFreq[i] = 24; + m_nEQMidHighFreq[i] = 44; + // Active the required number of active TGs if (isetEngineType(pConfig->GetEngineType ()); m_pTG[i]->activate (); + + m_pEQ[i] = new AudioEffect3BandEQ (pConfig->GetSampleRate ()); + assert (m_pEQ[i]); } } @@ -1210,6 +1221,13 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT case TGParameterCompressorThresh: SetCompressorThresh (nValue, nTG); break; case TGParameterCompressorRatio: SetCompressorRatio (nValue, nTG); break; + case TGParameterEQLow: SetEQLow (nValue, nTG); break; + case TGParameterEQMid: SetEQMid (nValue, nTG); break; + case TGParameterEQHigh: SetEQHigh (nValue, nTG); break; + case TGParameterEQGain: SetEQGain (nValue, nTG); break; + case TGParameterEQLowMidFreq: SetEQLowMidFreq (nValue, nTG); break; + case TGParameterEQMidHighFreq: SetEQMidHighFreq (nValue, nTG); break; + default: assert (0); break; @@ -1267,6 +1285,13 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCompressorThresh: return m_nCompressorThresh[nTG]; case TGParameterCompressorRatio: return m_nCompressorRatio[nTG]; + case TGParameterEQLow: return m_nEQLow[nTG]; break; + case TGParameterEQMid: return m_nEQMid[nTG]; break; + case TGParameterEQHigh: return m_nEQHigh[nTG]; break; + case TGParameterEQGain: return m_nEQGain[nTG]; break; + case TGParameterEQLowMidFreq: return m_nEQLowMidFreq[nTG]; break; + case TGParameterEQMidHighFreq: return m_nEQMidHighFreq[nTG]; break; + default: assert (0); return 0; @@ -1483,6 +1508,13 @@ void CMiniDexed::ProcessSound (void) tg_mixer->zeroFill(); + m_EQSpinLock.Acquire(); + for (uint8_t i = 0; i < m_nToneGenerators; i++) + { + m_pEQ[i]->process(m_OutputLevel[i], nFrames); + } + m_EQSpinLock.Release(); + for (uint8_t i = 0; i < m_nToneGenerators; i++) { tg_mixer->doAddMix(i,m_OutputLevel[i]); @@ -1656,6 +1688,13 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetCompressorRelease (m_nCompressorRelease[nTG], nTG); m_PerformanceConfig.SetCompressorThresh (m_nCompressorThresh[nTG], nTG); m_PerformanceConfig.SetCompressorRatio (m_nCompressorRatio[nTG], nTG); + + m_PerformanceConfig.SetEQLow (m_nEQLow[nTG], nTG); + m_PerformanceConfig.SetEQMid (m_nEQMid[nTG], nTG); + m_PerformanceConfig.SetEQHigh (m_nEQHigh[nTG], nTG); + m_PerformanceConfig.SetEQGain (m_nEQGain[nTG], nTG); + m_PerformanceConfig.SetEQLowMidFreq (m_nEQLowMidFreq[nTG], nTG); + m_PerformanceConfig.SetEQMidHighFreq (m_nEQMidHighFreq[nTG], nTG); } m_PerformanceConfig.SetReverbEnable (!!m_nParameter[ParameterReverbEnable]); @@ -1754,6 +1793,76 @@ void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) m_UI.ParameterChanged (); } +void CMiniDexed::SetEQLow (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQLow[nTG] = nValue; + m_EQSpinLock.Acquire(); + m_pEQ[nTG]->setLow_dB(nValue); + m_EQSpinLock.Release(); +} + +void CMiniDexed::SetEQMid (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQMid[nTG] = nValue; + m_EQSpinLock.Acquire(); + m_pEQ[nTG]->setMid_dB(nValue); + m_EQSpinLock.Release(); +} + +void CMiniDexed::SetEQHigh (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQHigh[nTG] = nValue; + m_EQSpinLock.Acquire(); + m_pEQ[nTG]->setHigh_dB(nValue); + m_EQSpinLock.Release(); +} + +void CMiniDexed::SetEQGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQGain[nTG] = nValue; + m_EQSpinLock.Acquire(); + m_pEQ[nTG]->setGain_dB(nValue); + m_EQSpinLock.Release(); +} + +void CMiniDexed::SetEQLowMidFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, 0u, 46u); + m_EQSpinLock.Acquire(); + m_nEQLowMidFreq[nTG] = m_pEQ[nTG]->setLowMidFreq_n(nValue); + m_EQSpinLock.Release(); +} + +void CMiniDexed::SetEQMidHighFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, 28u, 59u); + m_EQSpinLock.Acquire(); + m_nEQMidHighFreq[nTG] = m_pEQ[nTG]->setMidHighFreq_n(nValue); + m_EQSpinLock.Release(); +} + void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -2232,6 +2341,13 @@ void CMiniDexed::LoadPerformanceParameters(void) SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); + + SetEQLow (m_PerformanceConfig.GetEQLow (nTG), nTG); + SetEQMid (m_PerformanceConfig.GetEQMid (nTG), nTG); + SetEQHigh (m_PerformanceConfig.GetEQHigh (nTG), nTG); + SetEQGain (m_PerformanceConfig.GetEQGain (nTG), nTG); + SetEQLowMidFreq (m_PerformanceConfig.GetEQLowMidFreq (nTG), nTG); + SetEQMidHighFreq (m_PerformanceConfig.GetEQMidHighFreq (nTG), nTG); } // Effects diff --git a/src/minidexed.h b/src/minidexed.h index 0dd9f0047..6e04ee021 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -52,7 +52,8 @@ #include "udpmididevice.h" #include "net/ftpdaemon.h" #include "../Synth_Dexed/src/compressor.h" - +#include "effect_3bandeq.h" + class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE : public CMultiCoreSupport @@ -115,6 +116,13 @@ class CMiniDexed void SetCompressorThresh (int thresh, unsigned nTG); // -60 .. 0 dBFS (default -20) void SetCompressorRatio (unsigned ratio, unsigned nTG); // 1 .. 20 (default 5) + void SetEQLow (int nValue, unsigned nTG); + void SetEQMid (int nValue, unsigned nTG); + void SetEQHigh (int nValue, unsigned nTG); + void SetEQGain (int nValue, unsigned nTG); + void SetEQLowMidFreq (unsigned nValue, unsigned nTG); + void SetEQMidHighFreq (unsigned nValue, unsigned nTG); + void setMonoMode(uint8_t mono, uint8_t nTG); void setPitchbendRange(uint8_t range, uint8_t nTG); void setPitchbendStep(uint8_t step, uint8_t nTG); @@ -244,6 +252,13 @@ class CMiniDexed TGParameterCompressorThresh, TGParameterCompressorRatio, + TGParameterEQLow, + TGParameterEQMid, + TGParameterEQHigh, + TGParameterEQGain, + TGParameterEQLowMidFreq, + TGParameterEQMidHighFreq, + TGParameterUnknown }; @@ -334,6 +349,13 @@ class CMiniDexed int m_nCompressorThresh[CConfig::AllToneGenerators]; unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + int m_nEQLow[CConfig::AllToneGenerators]; + int m_nEQMid[CConfig::AllToneGenerators]; + int m_nEQHigh[CConfig::AllToneGenerators]; + int m_nEQGain[CConfig::AllToneGenerators]; + unsigned m_nEQLowMidFreq[CConfig::AllToneGenerators]; + unsigned m_nEQMidHighFreq[CConfig::AllToneGenerators]; + uint8_t m_nRawVoiceData[156]; @@ -369,6 +391,9 @@ class CMiniDexed CSpinLock m_ReverbSpinLock; + AudioEffect3BandEQ *m_pEQ[CConfig::AllToneGenerators]; + CSpinLock m_EQSpinLock; + Compressor m_Limiter[2]; CSpinLock m_LimiterSpinLock; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 0224e647c..cea4b0e72 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -227,7 +227,24 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("CompressorRatio%u", nTG+1); m_nCompressorRatio[nTG] = m_Properties.GetNumber (PropertyName, 5); - } + PropertyName.Format ("EQLow%u", nTG+1); + m_nEQLow[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQMid%u", nTG+1); + m_nEQMid[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQHigh%u", nTG+1); + m_nEQHigh[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQGain%u", nTG+1); + m_nEQGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQLowMidFreq%u", nTG+1); + m_nEQLowMidFreq[nTG] = m_Properties.GetNumber (PropertyName, 24); + + PropertyName.Format ("EQMidHighFreq%u", nTG+1); + m_nEQMidHighFreq[nTG] = m_Properties.GetNumber (PropertyName, 44); + } m_bReverbEnable = m_Properties.GetNumber ("ReverbEnable", 1) != 0; m_nReverbSize = m_Properties.GetNumber ("ReverbSize", 70); @@ -378,7 +395,25 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("CompressorRatio%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nCompressorRatio[nTG]); - } + PropertyName.Format ("EQLow%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQLow[nTG]); + + PropertyName.Format ("EQMid%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQMid[nTG]); + + PropertyName.Format ("EQHigh%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQHigh[nTG]); + + PropertyName.Format ("EQGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQGain[nTG]); + + PropertyName.Format ("EQLowMidFreq%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nEQLowMidFreq[nTG]); + + PropertyName.Format ("EQMidHighFreq%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nEQMidHighFreq[nTG]); + + } m_Properties.SetNumber ("ReverbEnable", m_bReverbEnable ? 1 : 0); m_Properties.SetNumber ("ReverbSize", m_nReverbSize); @@ -543,6 +578,79 @@ void CPerformanceConfig::SetReverbSend (unsigned nValue, unsigned nTG) m_nReverbSend[nTG] = nValue; } +int CPerformanceConfig::GetEQLow (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQLow[nTG]; +} + +int CPerformanceConfig::GetEQMid (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQMid[nTG]; +} + +int CPerformanceConfig::GetEQHigh (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQHigh[nTG]; +} + +int CPerformanceConfig::GetEQGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQGain[nTG]; +} + +unsigned CPerformanceConfig::GetEQLowMidFreq (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQLowMidFreq[nTG]; +} + +unsigned CPerformanceConfig::GetEQMidHighFreq (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQMidHighFreq[nTG]; +} + +void CPerformanceConfig::SetEQLow (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQLow[nTG] = nValue; +} + +void CPerformanceConfig::SetEQMid (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQMid[nTG] = nValue; +} + +void CPerformanceConfig::SetEQHigh (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQHigh[nTG] = nValue; +} + +void CPerformanceConfig::SetEQGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQGain[nTG] = nValue; +} + +void CPerformanceConfig::SetEQLowMidFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQLowMidFreq[nTG] = nValue; +} + +void CPerformanceConfig::SetEQMidHighFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nEQMidHighFreq[nTG] = nValue; +} + + bool CPerformanceConfig::GetReverbEnable (void) const { return m_bReverbEnable; diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 18f9de25d..63fc9f06b 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -115,6 +115,20 @@ class CPerformanceConfig // Performance configuration void SetCompressorThresh (int nValue, unsigned nTG); void SetCompressorRatio (unsigned nValue, unsigned nTG); + int GetEQLow (unsigned nTG) const; + int GetEQMid (unsigned nTG) const; + int GetEQHigh (unsigned nTG) const; + int GetEQGain (unsigned nTG) const; + unsigned GetEQLowMidFreq (unsigned nTG) const; + unsigned GetEQMidHighFreq (unsigned nTG) const; + + void SetEQLow (int nValue, unsigned nTG); + void SetEQMid (int nValue, unsigned nTG); + void SetEQHigh (int nValue, unsigned nTG); + void SetEQGain (int nValue, unsigned nTG); + void SetEQLowMidFreq (unsigned nValue, unsigned nTG); + void SetEQMidHighFreq (unsigned nValue, unsigned nTG); + // Effects bool GetReverbEnable (void) const; unsigned GetReverbSize (void) const; // 0 .. 99 @@ -218,6 +232,13 @@ class CPerformanceConfig // Performance configuration int m_nCompressorThresh[CConfig::AllToneGenerators]; unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + int m_nEQLow[CConfig::AllToneGenerators]; + int m_nEQMid[CConfig::AllToneGenerators]; + int m_nEQHigh[CConfig::AllToneGenerators]; + int m_nEQGain[CConfig::AllToneGenerators]; + unsigned m_nEQLowMidFreq[CConfig::AllToneGenerators]; + unsigned m_nEQMidHighFreq[CConfig::AllToneGenerators]; + unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; unsigned m_nActualPerformanceBank = 0; @@ -230,7 +251,7 @@ class CPerformanceConfig // Performance configuration FATFS *m_pFileSystem; std::string NewPerformanceName=""; - + bool m_bReverbEnable; unsigned m_nReverbSize; unsigned m_nReverbHighDamp; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index a3cb919b8..02a66bcec 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -88,6 +88,9 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, {"Compressor", MenuHandler, s_EditCompressorMenu}, +#ifdef ARM_ALLOW_MULTI_CORE + {"EQ", MenuHandler, s_EQMenu}, +#endif {"Edit Voice", MenuHandler, s_EditVoiceMenu}, {0} }; @@ -147,6 +150,17 @@ const CUIMenu::TMenuItem CUIMenu::s_ModulationMenuParameters[] = #ifdef ARM_ALLOW_MULTI_CORE +const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = +{ + {"Low Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQLow}, + {"Mid Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQMid}, + {"High Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQHigh}, + {"Gain", EditTGParameter2, 0, CMiniDexed::TGParameterEQGain}, + {"Low-Mid Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQLowMidFreq}, + {"Mid-High Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQMidHighFreq}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = { {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterReverbEnable}, @@ -304,6 +318,12 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh {1, 20, 1, ToRatio}, // TGParameterCompressorRatio + {-24, 24, 1, TodB}, // TGParameterEQLow + {-24, 24, 1, TodB}, // TGParameterEQMid + {-24, 24, 1, TodB}, // TGParameterEQHigh + {-24, 24, 1, TodB}, // TGParameterEQGain + {0, 46, 1, ToHz}, // TGParameterEQLowMidFreq + {28, 59, 1, ToHz}, // TGParameterEQMidHighFreq }; // must match DexedVoiceParameters in Synth_Dexed @@ -1307,6 +1327,18 @@ std::string CUIMenu::ToRatio (int nValue, int nWidth) return std::to_string (nValue) + ":1"; } +std::string CUIMenu::ToHz (int nValue, int nWidth) +{ + uint16_t hz = MIDI_EQ_HZ[nValue]; + char buf[20] = {}; + + if (hz < 1000) + return std::to_string (hz) + " Hz"; + + std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); + return buf; +} + void CUIMenu::TGShortcutHandler (TMenuEvent Event) { assert (m_nCurrentMenuDepth >= 2); diff --git a/src/uimenu.h b/src/uimenu.h index a53f1e7ab..2b917e2f3 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -121,6 +121,7 @@ class CUIMenu static std::string TodBFS (int nValue, int nWidth); static std::string ToMillisec (int nValue, int nWidth); static std::string ToRatio (int nValue, int nWidth); + static std::string ToHz (int nValue, int nWidth); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); @@ -158,6 +159,7 @@ class CUIMenu static const TMenuItem s_MainMenu[]; static const TMenuItem s_TGMenu[]; static const TMenuItem s_EffectsMenu[]; + static const TMenuItem s_EQMenu[]; static const TMenuItem s_ReverbMenu[]; static const TMenuItem s_LimiterMenu[]; static const TMenuItem s_EditCompressorMenu[]; From 9422498b5e42ccc6b31be685ddfd6dbb508732f2 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 13 Aug 2025 18:02:26 +0200 Subject: [PATCH 042/136] 3BandEQ: remove the unneeded denormal fix Why it was there: https://ldesoras.fr/doc/articles/denormal-en.pdf but we don't need because Circle enables the flush to zero mode https://github.com/rsta2/circle/blob/927941cec722f530a23d0f636f03480dd9972056/lib/sysinit.cpp#L224 --- src/effect_3bandeq.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h index 3590da9aa..1fbd7818c 100644 --- a/src/effect_3bandeq.h +++ b/src/effect_3bandeq.h @@ -13,8 +13,6 @@ class AudioEffect3BandEQ { public: - static constexpr float kDC_ADD = 1e-30f; // Why do we need to add a small DC? - AudioEffect3BandEQ(unsigned samplerate): samplerate{samplerate}, fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, @@ -105,11 +103,11 @@ class AudioEffect3BandEQ { float inValue = isnan(block[i]) ? 0.0f : block[i]; - tmpLP = a0LP * inValue - b1LP * tmpLP + kDC_ADD; - outLP = tmpLP - kDC_ADD; + tmpLP = a0LP * inValue - b1LP * tmpLP; + outLP = tmpLP; - tmpHP = a0HP * inValue - b1HP * tmpHP + kDC_ADD; - outHP = inValue - tmpHP - kDC_ADD; + tmpHP = a0HP * inValue - b1HP * tmpHP; + outHP = inValue - tmpHP; block[i] = (outLP*lowVol + (inValue - outLP - outHP)*midVol + outHP*highVol) * outVol; } From 5002ccb80f887d6b580ae3e32b9568b24c4e0a07 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 14 Aug 2025 00:03:54 +0200 Subject: [PATCH 043/136] CMiniDexed: zero initialize m_pTG --- src/minidexed.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 5d0877057..931cbdf7d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -48,6 +48,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, CMultiCoreSupport (CMemorySystem::Get ()), #endif m_pConfig (pConfig), + m_pTG {}, m_UI (this, pGPIOManager, pI2CMaster, pSPIMaster, pConfig), m_PerformanceConfig (pFileSystem), m_pMIDIKeyboard {}, From 49f5df5f845508c2ca1abc17322b5994c15c88f6 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 14 Aug 2025 21:57:42 +0200 Subject: [PATCH 044/136] add master EQ --- src/minidexed.cpp | 75 +++++++++++++++++++++++++++++++++++++++ src/minidexed.h | 7 ++++ src/performanceconfig.cpp | 74 ++++++++++++++++++++++++++++++++++++++ src/performanceconfig.h | 21 +++++++++++ src/uimenu.cpp | 18 ++++++++++ src/uimenu.h | 1 + 6 files changed, 196 insertions(+) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 931cbdf7d..3f2f034c9 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -70,6 +70,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, tg_mixer(nullptr), reverb_send_mixer(nullptr), m_pEQ {}, + m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_Limiter {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), m_pNetDevice(nullptr), @@ -268,6 +269,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); + SetParameter (ParameterMasterEQLow, 0); + SetParameter (ParameterMasterEQMid, 0); + SetParameter (ParameterMasterEQHigh, 0); + SetParameter (ParameterMasterEQGain, 0); + SetParameter (ParameterMasterEQLowMidFreq, 24); + SetParameter (ParameterMasterEQMidHighFreq, 44); + SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); SetParameter (ParameterReverbEnable, 1); @@ -1152,6 +1160,54 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_LimiterSpinLock.Release (); break; + case ParameterMasterEQLow: + nValue = constrain(nValue, -24, 24); + m_EQSpinLock.Acquire(); + m_MasterEQ[0].setLow_dB(nValue); + m_MasterEQ[1].setLow_dB(nValue); + m_EQSpinLock.Release(); + break; + + case ParameterMasterEQMid: + nValue = constrain(nValue, -24, 24); + m_EQSpinLock.Acquire(); + m_MasterEQ[0].setMid_dB(nValue); + m_MasterEQ[1].setMid_dB(nValue); + m_EQSpinLock.Release(); + break; + + case ParameterMasterEQHigh: + nValue = constrain(nValue, -24, 24); + m_EQSpinLock.Acquire(); + m_MasterEQ[0].setHigh_dB(nValue); + m_MasterEQ[1].setHigh_dB(nValue); + m_EQSpinLock.Release(); + break; + + case ParameterMasterEQGain: + nValue = constrain(nValue, -24, 24); + m_EQSpinLock.Acquire(); + m_MasterEQ[0].setGain_dB(nValue); + m_MasterEQ[1].setGain_dB(nValue); + m_EQSpinLock.Release(); + break; + + case ParameterMasterEQLowMidFreq: + nValue = constrain(nValue, 0, 46); + m_EQSpinLock.Acquire(); + m_nParameter[ParameterMasterEQLowMidFreq] = m_MasterEQ[0].setLowMidFreq_n(nValue); + m_MasterEQ[1].setLowMidFreq_n(nValue); + m_EQSpinLock.Release(); + break; + + case ParameterMasterEQMidHighFreq: + nValue = constrain(nValue, 28, 59); + m_EQSpinLock.Acquire(); + m_nParameter[ParameterMasterEQMidHighFreq] = m_MasterEQ[0].setMidHighFreq_n(nValue); + m_MasterEQ[1].setMidHighFreq_n(nValue); + m_EQSpinLock.Release(); + break; + default: assert (0); break; @@ -1552,6 +1608,11 @@ void CMiniDexed::ProcessSound (void) } // END adding reverb + m_EQSpinLock.Acquire(); + m_MasterEQ[0].process(SampleBuffer[0], nFrames); + m_MasterEQ[1].process(SampleBuffer[1], nFrames); + m_EQSpinLock.Release(); + if (m_nParameter[ParameterLimiterEnable]) { m_LimiterSpinLock.Acquire (); @@ -1706,6 +1767,13 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetReverbDiffusion (m_nParameter[ParameterReverbDiffusion]); m_PerformanceConfig.SetReverbLevel (m_nParameter[ParameterReverbLevel]); + m_PerformanceConfig.SetMasterEQLow (m_nParameter[ParameterMasterEQLow]); + m_PerformanceConfig.SetMasterEQMid (m_nParameter[ParameterMasterEQMid]); + m_PerformanceConfig.SetMasterEQHigh (m_nParameter[ParameterMasterEQHigh]); + m_PerformanceConfig.SetMasterEQGain (m_nParameter[ParameterMasterEQGain]); + m_PerformanceConfig.SetMasterEQLowMidFreq (m_nParameter[ParameterMasterEQLowMidFreq]); + m_PerformanceConfig.SetMasterEQMidHighFreq (m_nParameter[ParameterMasterEQMidHighFreq]); + m_PerformanceConfig.SetLimiterEnable (m_nParameter[ParameterLimiterEnable]); m_PerformanceConfig.SetLimiterPreGain (m_nParameter[ParameterLimiterPreGain]); m_PerformanceConfig.SetLimiterAttack (m_nParameter[ParameterLimiterAttack]); @@ -2360,6 +2428,13 @@ void CMiniDexed::LoadPerformanceParameters(void) SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + SetParameter (ParameterMasterEQLow, m_PerformanceConfig.GetMasterEQLow ()); + SetParameter (ParameterMasterEQMid, m_PerformanceConfig.GetMasterEQMid ()); + SetParameter (ParameterMasterEQHigh, m_PerformanceConfig.GetMasterEQHigh ()); + SetParameter (ParameterMasterEQGain, m_PerformanceConfig.GetMasterEQGain ()); + SetParameter (ParameterMasterEQLowMidFreq, m_PerformanceConfig.GetMasterEQLowMidFreq ()); + SetParameter (ParameterMasterEQMidHighFreq, m_PerformanceConfig.GetMasterEQMidHighFreq ()); + SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); diff --git a/src/minidexed.h b/src/minidexed.h index 6e04ee021..daed9f53e 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -192,6 +192,12 @@ class CMiniDexed ParameterLimiterThresh, ParameterLimiterRatio, ParameterLimiterHPFilterEnable, + ParameterMasterEQLow, + ParameterMasterEQMid, + ParameterMasterEQHigh, + ParameterMasterEQGain, + ParameterMasterEQLowMidFreq, + ParameterMasterEQMidHighFreq, ParameterUnknown }; @@ -392,6 +398,7 @@ class CMiniDexed CSpinLock m_ReverbSpinLock; AudioEffect3BandEQ *m_pEQ[CConfig::AllToneGenerators]; + AudioEffect3BandEQ m_MasterEQ[2]; CSpinLock m_EQSpinLock; Compressor m_Limiter[2]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index cea4b0e72..f4dd2a291 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -254,6 +254,13 @@ bool CPerformanceConfig::Load (void) m_nReverbDiffusion = m_Properties.GetNumber ("ReverbDiffusion", 65); m_nReverbLevel = m_Properties.GetNumber ("ReverbLevel", 99); + m_nMasterEQLow = m_Properties.GetSignedNumber ("MasterEQLow", 0); + m_nMasterEQMid = m_Properties.GetSignedNumber ("MasterEQMid", 0); + m_nMasterEQHigh = m_Properties.GetSignedNumber ("MasterEQHigh", 0); + m_nMasterEQGain = m_Properties.GetSignedNumber ("MasterEQGain", 0); + m_nMasterEQLowMidFreq = m_Properties.GetNumber ("MasterEQLowMidFreq", 24); + m_nMasterEQMidHighFreq = m_Properties.GetNumber ("MasterEQMidHighFreq", 44); + m_bLimiterEnable = m_Properties.GetNumber ("LimiterEnable", 1); m_nLimiterPreGain = m_Properties.GetSignedNumber ("LimiterPreGain", 0); m_nLimiterAttack = m_Properties.GetNumber ("LimiterAttack", 5); @@ -423,6 +430,13 @@ bool CPerformanceConfig::Save (void) m_Properties.SetNumber ("ReverbDiffusion", m_nReverbDiffusion); m_Properties.SetNumber ("ReverbLevel", m_nReverbLevel); + m_Properties.SetSignedNumber ("MasterEQLow", m_nMasterEQLow); + m_Properties.SetSignedNumber ("MasterEQMid", m_nMasterEQMid); + m_Properties.SetSignedNumber ("MasterEQHigh", m_nMasterEQHigh); + m_Properties.SetSignedNumber ("MasterEQGain", m_nMasterEQGain); + m_Properties.SetNumber ("MasterEQLowMidFreq", m_nMasterEQLowMidFreq); + m_Properties.SetNumber ("MasterEQMidHighFreq", m_nMasterEQMidHighFreq); + m_Properties.SetNumber ("LimiterEnable", m_bLimiterEnable); m_Properties.SetSignedNumber ("LimiterPreGain", m_nLimiterPreGain); m_Properties.SetNumber ("LimiterAttack", m_nLimiterAttack); @@ -721,6 +735,66 @@ void CPerformanceConfig::SetReverbLevel (unsigned nValue) m_nReverbLevel = nValue; } +int CPerformanceConfig::GetMasterEQLow () const +{ + return m_nMasterEQLow; +} + +int CPerformanceConfig::GetMasterEQMid () const +{ + return m_nMasterEQMid; +} + +int CPerformanceConfig::GetMasterEQHigh () const +{ + return m_nMasterEQHigh; +} + +int CPerformanceConfig::GetMasterEQGain () const +{ + return m_nMasterEQGain; +} + +unsigned CPerformanceConfig::GetMasterEQLowMidFreq () const +{ + return m_nMasterEQLowMidFreq; +} + +unsigned CPerformanceConfig::GetMasterEQMidHighFreq () const +{ + return m_nMasterEQMidHighFreq; +} + +void CPerformanceConfig::SetMasterEQLow (int nValue) +{ + m_nMasterEQLow = nValue; +} + +void CPerformanceConfig::SetMasterEQMid (int nValue) +{ + m_nMasterEQMid = nValue; +} + +void CPerformanceConfig::SetMasterEQHigh (int nValue) +{ + m_nMasterEQHigh = nValue; +} + +void CPerformanceConfig::SetMasterEQGain (int nValue) +{ + m_nMasterEQGain = nValue; +} + +void CPerformanceConfig::SetMasterEQLowMidFreq (unsigned nValue) +{ + m_nMasterEQLowMidFreq = nValue; +} + +void CPerformanceConfig::SetMasterEQMidHighFreq (unsigned nValue) +{ + m_nMasterEQMidHighFreq = nValue; +} + bool CPerformanceConfig::GetLimiterEnable () const { return m_bLimiterEnable; diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 63fc9f06b..b831030ae 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -146,6 +146,20 @@ class CPerformanceConfig // Performance configuration void SetReverbDiffusion (unsigned nValue); void SetReverbLevel (unsigned nValue); + int GetMasterEQLow () const; + int GetMasterEQMid () const; + int GetMasterEQHigh () const; + int GetMasterEQGain () const; + unsigned GetMasterEQLowMidFreq () const; + unsigned GetMasterEQMidHighFreq () const; + + void SetMasterEQLow (int nValue); + void SetMasterEQMid (int nValue); + void SetMasterEQHigh (int nValue); + void SetMasterEQGain (int nValue); + void SetMasterEQLowMidFreq (unsigned nValue); + void SetMasterEQMidHighFreq (unsigned nValue); + bool GetLimiterEnable () const; int GetLimiterPreGain () const; unsigned GetLimiterAttack () const; @@ -260,6 +274,13 @@ class CPerformanceConfig // Performance configuration unsigned m_nReverbDiffusion; unsigned m_nReverbLevel; + int m_nMasterEQLow; + int m_nMasterEQMid; + int m_nMasterEQHigh; + int m_nMasterEQGain; + unsigned m_nMasterEQLowMidFreq; + unsigned m_nMasterEQMidHighFreq; + bool m_bLimiterEnable; int m_nLimiterPreGain; unsigned m_nLimiterAttack; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 02a66bcec..291d50a74 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -110,6 +110,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { #ifdef ARM_ALLOW_MULTI_CORE {"Reverb", MenuHandler, s_ReverbMenu}, + {"EQ", MenuHandler, s_MasterEQMenu}, {"Limiter", MenuHandler, s_LimiterMenu}, #endif {0} @@ -173,6 +174,17 @@ const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = +{ + {"Low Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLow}, + {"Mid Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQMid}, + {"High Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQHigh}, + {"Gain", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQGain}, + {"Low-Mid Freq", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLowMidFreq}, + {"Mid-High Freq", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQMidHighFreq}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_LimiterMenu[] = { {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterEnable}, @@ -274,6 +286,12 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {-60, 0, 1, TodBFS}, // ParameterLimiterThresh {1, 20, 1, ToRatio}, // ParameterLimiterRatio {0, 1, 1, ToOnOff}, // ParameterLimiterHPFilterEnable + {-24, 24, 1, TodB}, // ParameterMasterEQLow + {-24, 24, 1, TodB}, // ParameterMasterEQMid + {-24, 24, 1, TodB}, // ParameterMasterEQHigh + {-24, 24, 1, TodB}, // ParameterMasterEQGain + {0, 46, 1, ToHz}, // ParameterMasterEQLowMidFreq + {28, 59, 1, ToHz}, // ParameterMasterEQMidHighFreq }; // must match CMiniDexed::TTGParameter diff --git a/src/uimenu.h b/src/uimenu.h index 2b917e2f3..21048c351 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -161,6 +161,7 @@ class CUIMenu static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_EQMenu[]; static const TMenuItem s_ReverbMenu[]; + static const TMenuItem s_MasterEQMenu[]; static const TMenuItem s_LimiterMenu[]; static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; From 3c8748ef47278b517e7dce3de014dad5d3c79edd Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 14 Aug 2025 23:15:15 +0200 Subject: [PATCH 045/136] put Compressor after TG EQ Do not use the compressor in Dexed instances, use the same one, but instantiate in MiniDexed --- src/dexedadapter.h | 26 +++++++++++++++++++++++-- src/minidexed.cpp | 47 ++++++++++++---------------------------------- src/minidexed.h | 1 - src/uimenu.cpp | 8 +++----- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 573e80ef2..124b8240e 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -25,6 +25,9 @@ #include #include +#include "effect_3bandeq.h" +#include "compressor.h" + #define DEXED_OP_ENABLE (DEXED_OP_OSC_DETUNE + 1) // Some Dexed methods require to be guarded from being interrupted @@ -33,8 +36,11 @@ class CDexedAdapter : public Dexed { public: - CDexedAdapter (uint8_t maxnotes, int rate) - : Dexed (maxnotes, rate) + CDexedAdapter (uint8_t maxnotes, unsigned samplerate): + Dexed (maxnotes, samplerate), + EQ {samplerate}, + Compr {(float)samplerate}, + m_bCompressorEnable {true} { } @@ -63,6 +69,11 @@ class CDexedAdapter : public Dexed { m_SpinLock.Acquire (); Dexed::getSamples (buffer, n_samples); + EQ.process(buffer, n_samples); + if (m_bCompressorEnable) + { + Compr.doCompression (buffer, n_samples); + } m_SpinLock.Release (); } @@ -80,8 +91,19 @@ class CDexedAdapter : public Dexed m_SpinLock.Release (); } + void setCompressorEnable(bool enable) + { + m_SpinLock.Acquire (); + m_bCompressorEnable = enable; + m_SpinLock.Release (); + } + + AudioEffect3BandEQ EQ; + Compressor Compr; + private: CSpinLock m_SpinLock; + bool m_bCompressorEnable; }; #endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 3f2f034c9..d63010b4e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -69,7 +69,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, reverb(nullptr), tg_mixer(nullptr), reverb_send_mixer(nullptr), - m_pEQ {}, m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_Limiter {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), @@ -153,9 +152,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_pTG[i]->setEngineType(pConfig->GetEngineType ()); m_pTG[i]->activate (); - - m_pEQ[i] = new AudioEffect3BandEQ (pConfig->GetSampleRate ()); - assert (m_pEQ[i]); } } @@ -1565,13 +1561,6 @@ void CMiniDexed::ProcessSound (void) tg_mixer->zeroFill(); - m_EQSpinLock.Acquire(); - for (uint8_t i = 0; i < m_nToneGenerators; i++) - { - m_pEQ[i]->process(m_OutputLevel[i], nFrames); - } - m_EQSpinLock.Release(); - for (uint8_t i = 0; i < m_nToneGenerators; i++) { tg_mixer->doAddMix(i,m_OutputLevel[i]); @@ -1798,7 +1787,7 @@ void CMiniDexed::SetCompressorEnable(bool compressor, unsigned nTG) assert (m_pTG[nTG]); m_bCompressorEnable[nTG] = compressor; - m_pTG[nTG]->setCompressor (compressor); + m_pTG[nTG]->setCompressorEnable (compressor); m_UI.ParameterChanged (); } @@ -1810,7 +1799,7 @@ void CMiniDexed::SetCompressorPreGain (int preGain, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorPreGain[nTG] = preGain; - m_pTG[nTG]->setCompressorPreGain_dB (preGain); + m_pTG[nTG]->Compr.setPreGain_dB (preGain); m_UI.ParameterChanged (); } @@ -1822,7 +1811,7 @@ void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorAttack[nTG] = attack; - m_pTG[nTG]->setCompressorAttack_sec (attack / 1000.0); + m_pTG[nTG]->Compr.setAttack_sec (attack / 1000.0, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } @@ -1834,7 +1823,7 @@ void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorRelease[nTG] = release; - m_pTG[nTG]->setCompressorRelease_sec (release / 1000.0); + m_pTG[nTG]->Compr.setRelease_sec (release / 1000.0, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } @@ -1846,7 +1835,7 @@ void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorThresh[nTG] = thresh; - m_pTG[nTG]->setCompressorThresh_dBFS (thresh); + m_pTG[nTG]->Compr.setThresh_dBFS (thresh); m_UI.ParameterChanged (); } @@ -1858,7 +1847,7 @@ void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorRatio[nTG] = ratio; - m_pTG[nTG]->setCompressionRatio (ratio); + m_pTG[nTG]->Compr.setCompressionRatio (ratio); m_UI.ParameterChanged (); } @@ -1869,9 +1858,7 @@ void CMiniDexed::SetEQLow (int nValue, unsigned nTG) nValue = constrain(nValue, -24, 24); m_nEQLow[nTG] = nValue; - m_EQSpinLock.Acquire(); - m_pEQ[nTG]->setLow_dB(nValue); - m_EQSpinLock.Release(); + m_pTG[nTG]->EQ.setLow_dB(nValue); } void CMiniDexed::SetEQMid (int nValue, unsigned nTG) @@ -1881,9 +1868,7 @@ void CMiniDexed::SetEQMid (int nValue, unsigned nTG) nValue = constrain(nValue, -24, 24); m_nEQMid[nTG] = nValue; - m_EQSpinLock.Acquire(); - m_pEQ[nTG]->setMid_dB(nValue); - m_EQSpinLock.Release(); + m_pTG[nTG]->EQ.setMid_dB(nValue); } void CMiniDexed::SetEQHigh (int nValue, unsigned nTG) @@ -1893,9 +1878,7 @@ void CMiniDexed::SetEQHigh (int nValue, unsigned nTG) nValue = constrain(nValue, -24, 24); m_nEQHigh[nTG] = nValue; - m_EQSpinLock.Acquire(); - m_pEQ[nTG]->setHigh_dB(nValue); - m_EQSpinLock.Release(); + m_pTG[nTG]->EQ.setHigh_dB(nValue); } void CMiniDexed::SetEQGain (int nValue, unsigned nTG) @@ -1905,9 +1888,7 @@ void CMiniDexed::SetEQGain (int nValue, unsigned nTG) nValue = constrain(nValue, -24, 24); m_nEQGain[nTG] = nValue; - m_EQSpinLock.Acquire(); - m_pEQ[nTG]->setGain_dB(nValue); - m_EQSpinLock.Release(); + m_pTG[nTG]->EQ.setGain_dB(nValue); } void CMiniDexed::SetEQLowMidFreq (unsigned nValue, unsigned nTG) @@ -1916,9 +1897,7 @@ void CMiniDexed::SetEQLowMidFreq (unsigned nValue, unsigned nTG) if (nTG >= m_nToneGenerators) return; // Not an active TG nValue = constrain(nValue, 0u, 46u); - m_EQSpinLock.Acquire(); - m_nEQLowMidFreq[nTG] = m_pEQ[nTG]->setLowMidFreq_n(nValue); - m_EQSpinLock.Release(); + m_nEQLowMidFreq[nTG] = m_pTG[nTG]->EQ.setLowMidFreq_n(nValue); } void CMiniDexed::SetEQMidHighFreq (unsigned nValue, unsigned nTG) @@ -1927,9 +1906,7 @@ void CMiniDexed::SetEQMidHighFreq (unsigned nValue, unsigned nTG) if (nTG >= m_nToneGenerators) return; // Not an active TG nValue = constrain(nValue, 28u, 59u); - m_EQSpinLock.Acquire(); - m_nEQMidHighFreq[nTG] = m_pEQ[nTG]->setMidHighFreq_n(nValue); - m_EQSpinLock.Release(); + m_nEQMidHighFreq[nTG] = m_pTG[nTG]->EQ.setMidHighFreq_n(nValue); } void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) diff --git a/src/minidexed.h b/src/minidexed.h index daed9f53e..1945775de 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -397,7 +397,6 @@ class CMiniDexed CSpinLock m_ReverbSpinLock; - AudioEffect3BandEQ *m_pEQ[CConfig::AllToneGenerators]; AudioEffect3BandEQ m_MasterEQ[2]; CSpinLock m_EQSpinLock; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 291d50a74..6448d6818 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -87,10 +87,8 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, - {"Compressor", MenuHandler, s_EditCompressorMenu}, -#ifdef ARM_ALLOW_MULTI_CORE {"EQ", MenuHandler, s_EQMenu}, -#endif + {"Compressor", MenuHandler, s_EditCompressorMenu}, {"Edit Voice", MenuHandler, s_EditVoiceMenu}, {0} }; @@ -149,8 +147,6 @@ const CUIMenu::TMenuItem CUIMenu::s_ModulationMenuParameters[] = {0} }; -#ifdef ARM_ALLOW_MULTI_CORE - const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = { {"Low Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQLow}, @@ -162,6 +158,8 @@ const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = {0} }; +#ifdef ARM_ALLOW_MULTI_CORE + const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = { {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterReverbEnable}, From b03df086f6e03d1051f19be20c4938079896d2ad Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 14:18:43 +0200 Subject: [PATCH 046/136] README: add 3-band EQ to feature list [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4335462c4..3f849a4b4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with th - [x] Noiseless volume change - [x] Configurable TG compressors - [x] Limiter -- [ ] 3-band EQ +- [x] 3-band EQ (per TG and Master) - [ ] Two Effect Send with Chrous, Delay, Reverb - [ ] 8 channel mixer (Rpi4+) - [ ] Multiple parts (RPi4+) From 3c3609456be0468a957360877e8151162d498f80 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 21 Aug 2025 12:50:51 +0200 Subject: [PATCH 047/136] Update to circle-stdlib v17 (circle50) --- circle-stdlib | 2 +- submod.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/circle-stdlib b/circle-stdlib index 61cf3a47b..a957cd7d9 160000 --- a/circle-stdlib +++ b/circle-stdlib @@ -1 +1 @@ -Subproject commit 61cf3a47bf93628039078b7c840e44432e52343e +Subproject commit a957cd7d9c5d68ada943bb776ed8da71fea25ef1 diff --git a/submod.sh b/submod.sh index 5c5580e90..4b584c06a 100755 --- a/submod.sh +++ b/submod.sh @@ -5,14 +5,14 @@ set -ex git submodule update --init --recursive -f # Use fixed master branch of circle-stdlib then re-update -cd circle-stdlib/ -git checkout -f --recurse-submodules 1111eee # Matches Circle Step49 -cd - +#cd circle-stdlib/ +#git checkout -f --recurse-submodules 1111eee # Matches Circle Step49 +#cd - # Optional update submodules explicitly -cd circle-stdlib/libs/circle -git checkout -f --recurse-submodules f18c60fa38042ea7132533e658abfafd5bd63435 -cd - +#cd circle-stdlib/libs/circle +#git checkout -f --recurse-submodules f18c60fa38042ea7132533e658abfafd5bd63435 +#cd - #cd circle-stdlib/libs/circle-newlib #git checkout develop #cd - From 39483466c4611072dda39289e7b0572b63dfdd20 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 21 Aug 2025 12:53:26 +0200 Subject: [PATCH 048/136] update toolchain to ARM GNU 14.3.Rel1 --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6000a1025..924068f3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,8 +36,8 @@ jobs: - name: Install 64-bit toolchain run: | set -ex - wget -q https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz - tar xf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz + tar xf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz - name: Build for Raspberry Pi 5 (64-bit) run: | @@ -121,8 +121,8 @@ jobs: - name: Install 32-bit toolchain run: | set -ex - wget -q https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz - tar xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz + tar xf arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz - name: Build for Raspberry Pi 2 (32-bit) run: | From d0ec242a978a7da0dae5953fa59d80c6b0f34088 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 17 Aug 2025 19:48:55 +0200 Subject: [PATCH 049/136] CMiniDexed: SetParameter: save the parameter after limiting it to the limits --- src/minidexed.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index d63010b4e..a00c63f4c 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1039,7 +1039,6 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) assert (reverb); assert (Parameter < ParameterUnknown); - m_nParameter[Parameter] = nValue; switch (Parameter) { @@ -1208,6 +1207,8 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) assert (0); break; } + + m_nParameter[Parameter] = nValue; } int CMiniDexed::GetParameter (TParameter Parameter) From eff5d56726cb7173740b5d1d4d6ddff2ead5f815 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 00:06:02 +0200 Subject: [PATCH 050/136] use the c++ version of c includes --- src/dexedadapter.h | 2 +- src/effect_3bandeq.h | 16 ++++++++-------- src/effect_mixer.hpp | 4 ++-- src/effect_platervbstereo.cpp | 4 ++-- src/effect_platervbstereo.h | 2 +- src/kernel.cpp | 2 +- src/midipin.cpp | 1 - src/minidexed.cpp | 6 +++--- src/minidexed.h | 2 +- src/pckeyboard.cpp | 2 +- src/serialmididevice.cpp | 2 +- src/sysexfileloader.cpp | 8 ++++---- src/udpmididevice.cpp | 2 +- src/uibuttons.cpp | 4 ++-- src/uimenu.cpp | 2 +- src/usbminidexedmidigadget.h | 2 +- src/userinterface.cpp | 4 ++-- 17 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 124b8240e..9631b7dbf 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include "effect_3bandeq.h" #include "compressor.h" diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h index 1fbd7818c..7585ad143 100644 --- a/src/effect_3bandeq.h +++ b/src/effect_3bandeq.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #include "midi.h" @@ -31,31 +31,31 @@ class AudioEffect3BandEQ void setLow_dB(float value) { fLow = value; - lowVol = pow(10.0f, fLow / 20.0f); + lowVol = std::pow(10.0f, fLow / 20.0f); } void setMid_dB(float value) { fMid = value; - midVol = pow(10.0f, fMid / 20.0f); + midVol = std::pow(10.0f, fMid / 20.0f); } void setHigh_dB(float value) { fHigh = value; - highVol = pow(10.0f, fHigh / 20.0f); + highVol = std::pow(10.0f, fHigh / 20.0f); } void setGain_dB(float value) { fGain = value; - outVol = pow(10.0f, fGain / 20.0f); + outVol = std::pow(10.0f, fGain / 20.0f); } float setLowMidFreq(float value) { fLowMidFreq = std::min(value, fMidHighFreq); - xLP = exp(-2.0f * M_PI * fLowMidFreq / samplerate); + xLP = std::exp(-2.0f * M_PI * fLowMidFreq / samplerate); a0LP = 1.0f - xLP; b1LP = -xLP; return fLowMidFreq; @@ -64,7 +64,7 @@ class AudioEffect3BandEQ float setMidHighFreq(float value) { fMidHighFreq = std::max(value, fLowMidFreq); - xHP = exp(-2.0f * M_PI * fMidHighFreq / samplerate); + xHP = std::exp(-2.0f * M_PI * fMidHighFreq / samplerate); a0HP = 1.0f - xHP; b1HP = -xHP; return fMidHighFreq; @@ -101,7 +101,7 @@ class AudioEffect3BandEQ for (uint16_t i=0; i < len; ++i) { - float inValue = isnan(block[i]) ? 0.0f : block[i]; + float inValue = std::isnan(block[i]) ? 0.0f : block[i]; tmpLP = a0LP * inValue - b1LP * tmpLP; outLP = tmpLP; diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index f229ed35d..754fc882a 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -5,8 +5,8 @@ #define effect_mixer_h_ #include -#include -#include "arm_math.h" +#include +#include #include "arm_scale_zc_ramp_f32.h" #define UNITY_GAIN 1.0f diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index ce2af1e48..6cae1287f 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -31,9 +31,9 @@ */ -#include +#include #include -#include +#include #include "effect_platervbstereo.h" #define INP_ALLP_COEFF (0.65f) // default input allpass coeff diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 23538c460..8d3716c45 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -44,7 +44,7 @@ #ifndef _EFFECT_PLATERVBSTEREO_H #define _EFFECT_PLATERVBSTEREO_H -#include +#include #include #include "common.h" diff --git a/src/kernel.cpp b/src/kernel.cpp index a47fd846e..1d71b5d3b 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "usbminidexedmidigadget.h" diff --git a/src/midipin.cpp b/src/midipin.cpp index d03d73aa3..0c41dea07 100644 --- a/src/midipin.cpp +++ b/src/midipin.cpp @@ -19,7 +19,6 @@ // #include "midipin.h" #include -#include LOGMODULE ("midipin"); diff --git a/src/minidexed.cpp b/src/minidexed.cpp index a00c63f4c..aa7e5ae05 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -26,9 +26,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "arm_float_to_q23.h" #include "arm_scale_zc_ramp_f32.h" #include "arm_scale_zip_f32.h" diff --git a/src/minidexed.h b/src/minidexed.h index 1945775de..c43472693 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -31,7 +31,7 @@ #include "perftimer.h" #include #include -#include +#include #include #include #include diff --git a/src/pckeyboard.cpp b/src/pckeyboard.cpp index 79fe92c76..2c7cd3e36 100644 --- a/src/pckeyboard.cpp +++ b/src/pckeyboard.cpp @@ -20,7 +20,7 @@ #include "pckeyboard.h" #include #include -#include +#include struct TKeyInfo { diff --git a/src/serialmididevice.cpp b/src/serialmididevice.cpp index 3fe01e8f9..42ffcd2cf 100644 --- a/src/serialmididevice.cpp +++ b/src/serialmididevice.cpp @@ -24,7 +24,7 @@ #include #include #include "serialmididevice.h" -#include +#include LOGMODULE("serialmididevice"); diff --git a/src/sysexfileloader.cpp b/src/sysexfileloader.cpp index 6b83f5b50..5e2634d78 100644 --- a/src/sysexfileloader.cpp +++ b/src/sysexfileloader.cpp @@ -18,12 +18,12 @@ // along with this program. If not, see . // #include "sysexfileloader.h" -#include +#include #include -#include -#include +#include +#include #include -#include +#include #include #include "voices.c" diff --git a/src/udpmididevice.cpp b/src/udpmididevice.cpp index 000bc3d1e..f78d5581e 100644 --- a/src/udpmididevice.cpp +++ b/src/udpmididevice.cpp @@ -24,7 +24,7 @@ #include #include #include "udpmididevice.h" -#include +#include #include #include diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 06eb85762..de831cae5 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -19,9 +19,9 @@ // #include "uibuttons.h" #include -#include +#include #include -#include +#include #include "midi.h" LOGMODULE ("uibuttons"); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 6448d6818..1045d5df8 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -26,7 +26,7 @@ #include "userinterface.h" #include "sysexfileloader.h" #include "config.h" -#include +#include #include #include #include diff --git a/src/usbminidexedmidigadget.h b/src/usbminidexedmidigadget.h index 851354955..977d53622 100644 --- a/src/usbminidexedmidigadget.h +++ b/src/usbminidexedmidigadget.h @@ -24,7 +24,7 @@ #if RASPPI==5 #include -#include +#include #warning No support for USB Gadget Mode on RPI 5 yet class CUSBMiniDexedMIDIGadget diff --git a/src/userinterface.cpp b/src/userinterface.cpp index be7242421..d65c9d30c 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -22,8 +22,8 @@ #include #include #include -#include -#include +#include +#include LOGMODULE ("ui"); From 16224885a08711457bfe5ab92071f743e356bb48 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 08:54:18 +0200 Subject: [PATCH 051/136] CUIMenu: add note limits and shift --- src/minidexed.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++--- src/minidexed.h | 6 +++++ src/uimenu.cpp | 50 +++++++++++++++++++++++++++++++++++++++++ src/uimenu.h | 5 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index aa7e5ae05..10e1258f7 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1238,6 +1238,9 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT case TGParameterPortamentoMode: setPortamentoMode (nValue, nTG); break; case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, nTG); break; case TGParameterPortamentoTime: setPortamentoTime (nValue, nTG); break; + case TGParameterNoteLimitLow: setNoteLimitLow (nValue, nTG); break; + case TGParameterNoteLimitHigh: setNoteLimitHigh (nValue, nTG); break; + case TGParameterNoteShift: setNoteShift (nValue, nTG); break; case TGParameterMonoMode: setMonoMode (nValue , nTG); break; case TGParameterMWRange: setModController(0, 0, nValue, nTG); break; @@ -1310,6 +1313,9 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterPortamentoMode: return m_nPortamentoMode[nTG]; case TGParameterPortamentoGlissando: return m_nPortamentoGlissando[nTG]; case TGParameterPortamentoTime: return m_nPortamentoTime[nTG]; + case TGParameterNoteLimitLow: return m_nNoteLimitLow[nTG]; + case TGParameterNoteLimitHigh: return m_nNoteLimitHigh[nTG]; + case TGParameterNoteShift: return m_nNoteShift[nTG]; case TGParameterMonoMode: return m_bMonoMode[nTG] ? 1 : 0; case TGParameterMWRange: return getModController(0, 0, nTG); @@ -1993,6 +1999,51 @@ void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG) m_UI.ParameterChanged (); } +void CMiniDexed::setNoteLimitLow(unsigned limit, uint8_t nTG) +{ + limit = constrain (limit, 0u, 127u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteLimitLow[nTG] = limit; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + +void CMiniDexed::setNoteLimitHigh(unsigned limit, uint8_t nTG) +{ + limit = constrain (limit, 0u, 127u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteLimitHigh[nTG] = limit; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + +void CMiniDexed::setNoteShift(int shift, uint8_t nTG) +{ + shift = constrain (shift, -24, 24); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteShift[nTG] = shift; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -2359,9 +2410,9 @@ void CMiniDexed::LoadPerformanceParameters(void) setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); - m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); - m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); - m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); + setNoteLimitLow(m_PerformanceConfig.GetNoteLimitLow (nTG), nTG); + setNoteLimitHigh(m_PerformanceConfig.GetNoteLimitHigh (nTG), nTG); + setNoteShift(m_PerformanceConfig.GetNoteShift (nTG), nTG); if(m_PerformanceConfig.VoiceDataFilled(nTG) && nTG < m_nToneGenerators) { diff --git a/src/minidexed.h b/src/minidexed.h index c43472693..6b3331505 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -129,6 +129,9 @@ class CMiniDexed void setPortamentoMode(uint8_t mode, uint8_t nTG); void setPortamentoGlissando(uint8_t glissando, uint8_t nTG); void setPortamentoTime(uint8_t time, uint8_t nTG); + void setNoteLimitLow(unsigned limit, uint8_t nTG); + void setNoteLimitHigh(unsigned limit, uint8_t nTG); + void setNoteShift(int shift, uint8_t nTG); void setModWheelRange(uint8_t range, uint8_t nTG); void setModWheelTarget(uint8_t target, uint8_t nTG); void setFootControllerRange(uint8_t range, uint8_t nTG); @@ -229,6 +232,9 @@ class CMiniDexed TGParameterPortamentoMode, TGParameterPortamentoGlissando, TGParameterPortamentoTime, + TGParameterNoteLimitLow, + TGParameterNoteLimitHigh, + TGParameterNoteShift, TGParameterMonoMode, TGParameterMWRange, diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 1045d5df8..ba62ead4e 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -84,6 +84,7 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Resonance", EditTGParameter, 0, CMiniDexed::TGParameterResonance}, {"Pitch Bend", MenuHandler, s_EditPitchBendMenu}, {"Portamento", MenuHandler, s_EditPortamentoMenu}, + {"Note Limit", MenuHandler, s_EditNoteLimitMenu}, {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, @@ -129,6 +130,14 @@ const CUIMenu::TMenuItem CUIMenu::s_EditPortamentoMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_EditNoteLimitMenu[] = +{ + {"Limit Low", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitLow}, + {"Limit High", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitHigh}, + {"Shift", EditTGParameter2, 0, CMiniDexed::TGParameterNoteShift}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_ModulationMenu[] = { {"Mod. Wheel", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterMWRange}, @@ -311,6 +320,9 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1, 1, ToPortaMode}, // TGParameterPortamentoMode {0, 1, 1, ToPortaGlissando}, // TGParameterPortamentoGlissando {0, 99, 1}, // TGParameterPortamentoTime + {0, 127, 1, ToMIDINote}, // TGParameterNoteLimitLow + {0, 127, 1, ToMIDINote}, // TGParameterNoteLimitHigh + {-24, 24, 1, ToMIDINoteShift}, // TGParameterNoteShift {0, 1, 1, ToPolyMono}, // TGParameterMonoMode {0, 99, 1}, //MW Range {0, 1, 1, ToOnOff}, //MW Pitch @@ -407,6 +419,30 @@ const char CUIMenu::s_NoteName[100][5] = "A7", "A#7", "B7", "C8" }; +const char CUIMenu::s_MIDINoteName[128][9] = +{ +"0 C-2", "1 C#-2", "2 D-2", "3 D#-2", "4 E-2", "5 F-2", "6 F#-2", "7 G-2", "8 G#-2", "9 A-2", "10 A#-2", "11 B-2", +"12 C-1", "13 C#-1", "14 D-1", "15 D#-1", "16 E-1", "17 F-1", "18 F#-1", "19 G-1", "20 G#-1", "21 A-1", "22 A#-1", "23 B-1", +"24 C0", "25 C#0", "26 D0", "27 D#0", "28 E0", "29 F0", "30 F#0", "31 G0", "32 G#0", "33 A0", "34 A#0", "35 B0", +"36 C1", "37 C#1", "38 D1", "39 D#1", "40 E1", "41 F1", "42 F#1", "43 G1", "44 G#1", "45 A1", "46 A#1", "47 B1", +"48 C2", "49 C#2", "50 D2", "51 D#2", "52 E2", "53 F2", "54 F#2", "55 G2", "56 G#2", "57 A2", "58 A#2", "59 B2", +"60 C3", "61 C#3", "62 D3", "63 D#3", "64 E3", "65 F3", "66 F#3", "67 G3", "68 G#3", "69 A3", "70 A#3", "71 B3", +"72 C4", "73 C#4", "74 D4", "75 D#4", "76 E4", "77 F4", "78 F#4", "79 G4", "80 G#4", "81 A4", "82 A#4", "83 B4", +"84 C5", "85 C#5", "86 D5", "87 D#5", "88 E5", "89 F5", "90 F#5", "91 G5", "92 G#5", "93 A5", "94 A#5", "95 B5", +"96 C6", "97 C#6", "98 D6", "99 D#6", "100 E6", "101 F6", "102 F#6", "103 G6", "104 G#6", "105 A6", "106 A#6", "107 B6", +"108 C7", "109 C#7", "110 D7", "111 D#7", "112 E7", "113 F7", "114 F#7", "115 G7", "116 G#7", "117 A7", "118 A#7", "119 B7", +"120 C8", "121 C#8", "122 D8", "123 D#8", "124 E8", "125 F8", "126 F#8", "127 G8" +}; + +const char CUIMenu::s_MIDINoteShift[49][8] = +{ +"-24 C1", "-23 C#1", "-22 D1", "-21 D#1", "-20 E1", "-19 F1", "-18 F#1", "-17 G1", "-16 G#1", "-15 A1", "-14 A#1", "-13 B1", +"-12 C2", "-11 C#2", "-10 D2", "-9 D#2", "-8 E2", "-7 F2", "-6 F#2", "-5 G2", "-4 G#2", "-3 A2", "-2 A#2", "-1 B2", +"0 C3", "+1 C#3", "+2 D3", "+3 D#3", "+4 E3", "+5 F3", "+6 F#3", "+7 G3", "+8 G#3", "+9 A3", "+10 A#3", "+11 B3", +"+12 C4", "+13 C#4", "+14 D4", "+15 D#4", "+16 E4", "+17 F4", "+18 F#4", "+19 G4", "+20 G#4", "+21 A4", "+22 A#4", "+23 B4", +"+24 C5" +}; + static const unsigned NoteC3 = 39; const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = @@ -1257,6 +1293,20 @@ std::string CUIMenu::ToBreakpointNote (int nValue, int nWidth) return s_NoteName[nValue]; } +std::string CUIMenu::ToMIDINote (int nValue, int nWidth) +{ + assert ((unsigned) nValue < sizeof s_MIDINoteName / sizeof *s_MIDINoteName); + + return s_MIDINoteName[nValue]; +} + +std::string CUIMenu::ToMIDINoteShift (int nValue, int nWidth) +{ + assert ((unsigned) nValue + 24 < sizeof s_MIDINoteShift / sizeof *s_MIDINoteShift); + + return s_MIDINoteShift[nValue + 24]; +} + std::string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) { static const char *Curve[] = {"-Lin", "-Exp", "+Exp", "+Lin"}; diff --git a/src/uimenu.h b/src/uimenu.h index 21048c351..4d35ef895 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -111,6 +111,8 @@ class CUIMenu static std::string ToLFOWaveform (int nValue, int nWidth); static std::string ToTransposeNote (int nValue, int nWidth); static std::string ToBreakpointNote (int nValue, int nWidth); + static std::string ToMIDINote (int nValue, int nWidth); + static std::string ToMIDINoteShift (int nValue, int nWidth); static std::string ToKeyboardCurve (int nValue, int nWidth); static std::string ToOscillatorMode (int nValue, int nWidth); static std::string ToOscillatorDetune (int nValue, int nWidth); @@ -169,6 +171,7 @@ class CUIMenu static const TMenuItem s_SaveMenu[]; static const TMenuItem s_EditPitchBendMenu[]; static const TMenuItem s_EditPortamentoMenu[]; + static const TMenuItem s_EditNoteLimitMenu[]; static const TMenuItem s_PerformanceMenu[]; static const TMenuItem s_ModulationMenu[]; @@ -180,6 +183,8 @@ class CUIMenu static const TParameter s_OPParameter[]; static const char s_NoteName[100][5]; + static const char s_MIDINoteName[128][9]; + static const char s_MIDINoteShift[49][8]; std::string m_InputText="1234567890ABCD"; unsigned m_InputTextPosition=0; From 8cb4eeadec132b6de8a36881b5189d813bfcfa9f Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 15:47:09 +0200 Subject: [PATCH 052/136] CUIMenu: add OnSelect for EditTGParameter2 --- src/uimenu.cpp | 6 +++++- src/uimenu.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index ba62ead4e..2b344cad9 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -924,6 +924,11 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me case MenuEventUpdateParameter: break; + case MenuEventSelect: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect) + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect(pUIMenu, Event); + break; + case MenuEventStepDown: nValue -= rParam.Increment; if (nValue < rParam.Minimum) @@ -962,7 +967,6 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); - } void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) diff --git a/src/uimenu.h b/src/uimenu.h index 4d35ef895..62b2f9ab2 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -70,6 +70,7 @@ class CUIMenu TMenuHandler *Handler; const TMenuItem *MenuItem; unsigned Parameter; + TMenuHandler* OnSelect; }; typedef std::string TToString (int nValue, int nWidth); From 6c7188c86739f9c3bde1694995d7ff4c360a535e Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 15:47:46 +0200 Subject: [PATCH 053/136] CMiniDexed: add lastKeyDown getting functionality --- src/minidexed.cpp | 8 ++++++++ src/minidexed.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 10e1258f7..7d500e153 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -63,6 +63,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, #ifdef ARM_ALLOW_MULTI_CORE // m_nActiveTGsLog2 (0), #endif + m_nLastKeyDown{}, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), @@ -901,6 +902,8 @@ void CMiniDexed::keydown (int16_t pitch, uint8_t velocity, unsigned nTG) assert (m_pTG[nTG]); + m_nLastKeyDown = pitch; + pitch = ApplyNoteLimits (pitch, nTG); if (pitch >= 0) { @@ -2495,6 +2498,11 @@ bool CMiniDexed::IsValidPerformanceBank(unsigned nBankID) return m_PerformanceConfig.IsValidPerformanceBank(nBankID); } +int CMiniDexed::GetLastKeyDown() +{ + return m_nLastKeyDown; +} + void CMiniDexed::SetVoiceName (const std::string &VoiceName, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); diff --git a/src/minidexed.h b/src/minidexed.h index 6b3331505..39f5e1054 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -175,6 +175,8 @@ class CMiniDexed bool IsValidPerformance(unsigned nID); bool IsValidPerformanceBank(unsigned nBankID); + int GetLastKeyDown(); + // Must match the order in CUIMenu::TParameter enum TParameter { @@ -394,6 +396,8 @@ class CMiniDexed float32_t m_OutputLevel[CConfig::AllToneGenerators][CConfig::MaxChunkSize]; #endif + int m_nLastKeyDown; + CPerformanceTimer m_GetChunkTimer; bool m_bProfileEnabled; From d7777c77efb732e74f5929415984191736761007 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 15:48:53 +0200 Subject: [PATCH 054/136] CUIMenu: call InputKeyDown for note limits --- src/uimenu.cpp | 14 ++++++++++++-- src/uimenu.h | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 2b344cad9..4eebf057e 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -132,8 +132,8 @@ const CUIMenu::TMenuItem CUIMenu::s_EditPortamentoMenu[] = const CUIMenu::TMenuItem CUIMenu::s_EditNoteLimitMenu[] = { - {"Limit Low", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitLow}, - {"Limit High", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitHigh}, + {"Limit Low", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitLow, .OnSelect=InputKeyDown}, + {"Limit High", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitHigh, .OnSelect=InputKeyDown}, {"Shift", EditTGParameter2, 0, CMiniDexed::TGParameterNoteShift}, {0} }; @@ -1730,6 +1730,16 @@ void CUIMenu::TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void pThis->EventHandler (MenuEventUpdate); } +void CUIMenu::InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + int nLastKeyDown = pUIMenu->m_pMiniDexed->GetLastKeyDown (); + CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) pUIMenu->m_nCurrentParameter; + unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; + pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); +} + void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); diff --git a/src/uimenu.h b/src/uimenu.h index 62b2f9ab2..571fadc04 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -137,7 +137,8 @@ class CUIMenu static void InputTxt (CUIMenu *pUIMenu, TMenuEvent Event); static void TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext); - + + static void InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; From 1e1776ac49848e5b2b2fd4dc353c5bdb24ed26f2 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 16:47:37 +0200 Subject: [PATCH 055/136] CUIMenu: call InputShiftKeyDown for note shift --- src/uimenu.cpp | 14 +++++++++++++- src/uimenu.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 4eebf057e..3db9ff6e4 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -134,7 +134,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EditNoteLimitMenu[] = { {"Limit Low", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitLow, .OnSelect=InputKeyDown}, {"Limit High", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitHigh, .OnSelect=InputKeyDown}, - {"Shift", EditTGParameter2, 0, CMiniDexed::TGParameterNoteShift}, + {"Shift", EditTGParameter2, 0, CMiniDexed::TGParameterNoteShift, .OnSelect=InputShiftKeyDown}, {0} }; @@ -444,6 +444,7 @@ const char CUIMenu::s_MIDINoteShift[49][8] = }; static const unsigned NoteC3 = 39; +static const unsigned MIDINoteC3 = 60; const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = { @@ -1740,6 +1741,17 @@ void CUIMenu::InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); } +void CUIMenu::InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + int nLastKeyDown = pUIMenu->m_pMiniDexed->GetLastKeyDown () - MIDINoteC3; + CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) pUIMenu->m_nCurrentParameter; + unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; + if (nLastKeyDown >= -24 && nLastKeyDown <= 24) + pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); +} + void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); diff --git a/src/uimenu.h b/src/uimenu.h index 571fadc04..753ae7b9b 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -139,6 +139,7 @@ class CUIMenu static void TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext); static void InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); + static void InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; From 288ede1099ea311784e60edae91938efb599d1ee Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 24 Aug 2025 06:40:46 +0200 Subject: [PATCH 056/136] Update README.md Cloud Seed MIT license --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 3f849a4b4..622e1163f 100644 --- a/README.md +++ b/README.md @@ -114,3 +114,17 @@ This project stands on the shoulders of giants. Special thanks to: - [dwhinham/mt32-pi](https://github.com/dwhinham/mt32-pi) for creating networking support for Circle - [omersiar](https://github.com/omersiar) for porting networking support to MiniDexed - [soyersoyer](https://github.com/soyersoyer) for sound and other improvements, and for debugging + +## About the Reverb (Cloud Seed) + +DreamDexed includes the **Cloud Seed** reverb algorithm, originally created by [Ghost Note Audio](https://github.com/ValdemarOrn/CloudSeed). + +- The algorithm is MIT-licensed and may be used in both free and commercial projects. +- **Cloud Seed** is the work of Ghost Note Audio and not part of DreamDexed itself. +- When mentioning *Cloud Seed* in documentation or marketing, it must be clear that DreamDexed is an independent project that simply makes use of this reverb algorithm. +- Ghost Note Audio reserves the right to withdraw the use of the *Cloud Seed* name if these conditions are not respected. + +### Credits +A huge thanks to **Ghost Note Audio** for releasing this gem under MIT. +Without Cloud Seed, our DX tones would be stuck in the dry desert of 80s presets — +now they can float through infinite digital cathedrals. 🌌🎹✨ From bedb960071439904caff9f5256f34ee5e5d4443d Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 23 Aug 2025 14:44:13 +0200 Subject: [PATCH 057/136] Add Compressor Makeup gain --- Synth_Dexed | 2 +- src/minidexed.cpp | 17 +++++++++++++++++ src/minidexed.h | 3 +++ src/performanceconfig.cpp | 18 ++++++++++++++++++ src/performanceconfig.h | 3 +++ src/uimenu.cpp | 2 ++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Synth_Dexed b/Synth_Dexed index a02b5c0bf..376dd1d2f 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit a02b5c0bf2da132f49a923f9c69796220a8ea93f +Subproject commit 376dd1d2f53a95ce1581cb636304debb4064e735 diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 7d500e153..177fe0c19 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -131,6 +131,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bCompressorEnable[i] = 1; m_nCompressorPreGain[i] = 0; + m_nCompressorMakeupGain[i] = 0; m_nCompressorAttack[i] = 5; m_nCompressorRelease[i] = 200; m_nCompressorThresh[i] = -20; @@ -1276,6 +1277,7 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT case TGParameterCompressorEnable: SetCompressorEnable (nValue, nTG); break; case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, nTG); break; + case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, nTG); break; case TGParameterCompressorAttack: SetCompressorAttack (nValue, nTG); break; case TGParameterCompressorRelease: SetCompressorRelease (nValue, nTG); break; case TGParameterCompressorThresh: SetCompressorThresh (nValue, nTG); break; @@ -1343,6 +1345,7 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCompressorEnable: return m_bCompressorEnable[nTG]; case TGParameterCompressorPreGain: return m_nCompressorPreGain[nTG]; + case TGParameterCompressorMakeupGain: return m_nCompressorMakeupGain[nTG]; case TGParameterCompressorAttack: return m_nCompressorAttack[nTG]; case TGParameterCompressorRelease: return m_nCompressorRelease[nTG]; case TGParameterCompressorThresh: return m_nCompressorThresh[nTG]; @@ -1745,6 +1748,7 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); m_PerformanceConfig.SetCompressorPreGain (m_nCompressorPreGain[nTG], nTG); + m_PerformanceConfig.SetCompressorMakeupGain (m_nCompressorMakeupGain[nTG], nTG); m_PerformanceConfig.SetCompressorAttack (m_nCompressorAttack[nTG], nTG); m_PerformanceConfig.SetCompressorRelease (m_nCompressorRelease[nTG], nTG); m_PerformanceConfig.SetCompressorThresh (m_nCompressorThresh[nTG], nTG); @@ -1813,6 +1817,18 @@ void CMiniDexed::SetCompressorPreGain (int preGain, unsigned nTG) m_UI.ParameterChanged (); } +void CMiniDexed::SetCompressorMakeupGain (int makeupGain, unsigned nTG) +{ + makeupGain = constrain (makeupGain, -20, 20); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorMakeupGain[nTG] = makeupGain; + m_pTG[nTG]->Compr.setMakeupGain_dB (makeupGain); + m_UI.ParameterChanged (); +} + void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) { attack = constrain (attack, 0u, 1000u); @@ -2438,6 +2454,7 @@ void CMiniDexed::LoadPerformanceParameters(void) SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); + SetCompressorMakeupGain (m_PerformanceConfig.GetCompressorMakeupGain (nTG), nTG); SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); diff --git a/src/minidexed.h b/src/minidexed.h index 39f5e1054..141813dce 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -111,6 +111,7 @@ class CMiniDexed void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) + void SetCompressorMakeupGain (int makeupGain, unsigned nTG); // -20 .. 20 dB (default 0) void SetCompressorAttack (unsigned attack, unsigned nTG); // 0 .. 1000 ms (default 5) void SetCompressorRelease (unsigned release, unsigned nTG); // 0 .. 1000 ms (default 200) void SetCompressorThresh (int thresh, unsigned nTG); // -60 .. 0 dBFS (default -20) @@ -261,6 +262,7 @@ class CMiniDexed TGParameterCompressorEnable, TGParameterCompressorPreGain, + TGParameterCompressorMakeupGain, TGParameterCompressorAttack, TGParameterCompressorRelease, TGParameterCompressorThresh, @@ -358,6 +360,7 @@ class CMiniDexed bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; int m_nCompressorThresh[CConfig::AllToneGenerators]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index f4dd2a291..3b912e725 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -215,6 +215,9 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("CompressorPreGain%u", nTG+1); m_nCompressorPreGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_nCompressorMakeupGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + PropertyName.Format ("CompressorAttack%u", nTG+1); m_nCompressorAttack[nTG] = m_Properties.GetNumber (PropertyName, 5); @@ -390,6 +393,9 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("CompressorPreGain%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nCompressorPreGain[nTG]); + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorMakeupGain[nTG]); + PropertyName.Format ("CompressorAttack%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nCompressorAttack[nTG]); @@ -1061,6 +1067,18 @@ int CPerformanceConfig::GetCompressorPreGain (unsigned nTG) const return m_nCompressorPreGain[nTG]; } +void CPerformanceConfig::SetCompressorMakeupGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorMakeupGain[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorMakeupGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorMakeupGain[nTG]; +} + void CPerformanceConfig::SetCompressorAttack (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); diff --git a/src/performanceconfig.h b/src/performanceconfig.h index b831030ae..a77281567 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -73,6 +73,7 @@ class CPerformanceConfig // Performance configuration bool GetCompressorEnable (unsigned nTG) const; // 0 .. 1 int GetCompressorPreGain (unsigned nTG) const; + int GetCompressorMakeupGain (unsigned nTG) const; unsigned GetCompressorAttack (unsigned nTG) const; unsigned GetCompressorRelease (unsigned nTG) const; int GetCompressorThresh (unsigned nTG) const; @@ -110,6 +111,7 @@ class CPerformanceConfig // Performance configuration void SetCompressorEnable (bool nValue, unsigned nTG); void SetCompressorPreGain (int nValue, unsigned nTG); + void SetCompressorMakeupGain (int nValue, unsigned nTG); void SetCompressorAttack (unsigned nValue, unsigned nTG); void SetCompressorRelease (unsigned nValue, unsigned nTG); void SetCompressorThresh (int nValue, unsigned nTG); @@ -241,6 +243,7 @@ class CPerformanceConfig // Performance configuration bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; int m_nCompressorThresh[CConfig::AllToneGenerators]; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 3db9ff6e4..a974054f0 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -98,6 +98,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = { {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable}, {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain}, + {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain}, {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack}, {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease}, {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh}, @@ -342,6 +343,7 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1, 1, ToOnOff}, //AT EGBias {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable {-20, 20, 1, TodB}, // TGParameterCompressorPreGain + {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh From 41f32d663e5955119745cc192768eb0c5b982911 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 25 Aug 2025 01:01:43 +0200 Subject: [PATCH 058/136] reorder compressor and limiter fields --- src/minidexed.cpp | 106 ++++++++++++++++++------------------- src/minidexed.h | 22 ++++---- src/performanceconfig.cpp | 108 +++++++++++++++++++------------------- src/performanceconfig.h | 30 +++++------ src/uimenu.cpp | 20 +++---- 5 files changed, 143 insertions(+), 143 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 177fe0c19..7de0bda23 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -131,11 +131,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bCompressorEnable[i] = 1; m_nCompressorPreGain[i] = 0; - m_nCompressorMakeupGain[i] = 0; - m_nCompressorAttack[i] = 5; - m_nCompressorRelease[i] = 200; m_nCompressorThresh[i] = -20; m_nCompressorRatio[i] = 5; + m_nCompressorAttack[i] = 5; + m_nCompressorRelease[i] = 200; + m_nCompressorMakeupGain[i] = 0; m_nEQLow[i] = 0; m_nEQMid[i] = 0; @@ -287,10 +287,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetParameter (ParameterLimiterEnable, 1); SetParameter (ParameterLimiterPreGain, 0); - SetParameter (ParameterLimiterAttack, 5); - SetParameter (ParameterLimiterRelease, 5); SetParameter (ParameterLimiterThresh, -3); SetParameter (ParameterLimiterRatio, 20); + SetParameter (ParameterLimiterAttack, 5); + SetParameter (ParameterLimiterRelease, 5); SetParameter (ParameterLimiterHPFilterEnable, 0); SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); @@ -1120,35 +1120,35 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_LimiterSpinLock.Release (); break; - case ParameterLimiterAttack: - nValue=constrain(nValue,0,1000); + case ParameterLimiterThresh: + nValue=constrain(nValue,-60,0); m_LimiterSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_Limiter[i].setThresh_dBFS(nValue); m_LimiterSpinLock.Release (); break; - case ParameterLimiterRelease: - nValue=constrain(nValue,0,1000); + case ParameterLimiterRatio: + nValue=constrain(nValue,1,20); m_LimiterSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_Limiter[i].setCompressionRatio(nValue); m_LimiterSpinLock.Release (); break; - case ParameterLimiterThresh: - nValue=constrain(nValue,-60,0); + case ParameterLimiterAttack: + nValue=constrain(nValue,0,1000); m_LimiterSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setThresh_dBFS(nValue); + m_Limiter[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); m_LimiterSpinLock.Release (); break; - case ParameterLimiterRatio: - nValue=constrain(nValue,1,20); + case ParameterLimiterRelease: + nValue=constrain(nValue,0,1000); m_LimiterSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setCompressionRatio(nValue); + m_Limiter[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); m_LimiterSpinLock.Release (); break; @@ -1277,11 +1277,11 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT case TGParameterCompressorEnable: SetCompressorEnable (nValue, nTG); break; case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, nTG); break; - case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, nTG); break; - case TGParameterCompressorAttack: SetCompressorAttack (nValue, nTG); break; - case TGParameterCompressorRelease: SetCompressorRelease (nValue, nTG); break; case TGParameterCompressorThresh: SetCompressorThresh (nValue, nTG); break; case TGParameterCompressorRatio: SetCompressorRatio (nValue, nTG); break; + case TGParameterCompressorAttack: SetCompressorAttack (nValue, nTG); break; + case TGParameterCompressorRelease: SetCompressorRelease (nValue, nTG); break; + case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, nTG); break; case TGParameterEQLow: SetEQLow (nValue, nTG); break; case TGParameterEQMid: SetEQMid (nValue, nTG); break; @@ -1345,11 +1345,11 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCompressorEnable: return m_bCompressorEnable[nTG]; case TGParameterCompressorPreGain: return m_nCompressorPreGain[nTG]; - case TGParameterCompressorMakeupGain: return m_nCompressorMakeupGain[nTG]; + case TGParameterCompressorThresh: return m_nCompressorThresh[nTG]; + case TGParameterCompressorRatio: return m_nCompressorRatio[nTG]; case TGParameterCompressorAttack: return m_nCompressorAttack[nTG]; case TGParameterCompressorRelease: return m_nCompressorRelease[nTG]; - case TGParameterCompressorThresh: return m_nCompressorThresh[nTG]; - case TGParameterCompressorRatio: return m_nCompressorRatio[nTG]; + case TGParameterCompressorMakeupGain: return m_nCompressorMakeupGain[nTG]; case TGParameterEQLow: return m_nEQLow[nTG]; break; case TGParameterEQMid: return m_nEQMid[nTG]; break; @@ -1748,11 +1748,11 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); m_PerformanceConfig.SetCompressorPreGain (m_nCompressorPreGain[nTG], nTG); - m_PerformanceConfig.SetCompressorMakeupGain (m_nCompressorMakeupGain[nTG], nTG); + m_PerformanceConfig.SetCompressorThresh (m_nCompressorThresh[nTG], nTG); + m_PerformanceConfig.SetCompressorRatio (m_nCompressorRatio[nTG], nTG); m_PerformanceConfig.SetCompressorAttack (m_nCompressorAttack[nTG], nTG); m_PerformanceConfig.SetCompressorRelease (m_nCompressorRelease[nTG], nTG); - m_PerformanceConfig.SetCompressorThresh (m_nCompressorThresh[nTG], nTG); - m_PerformanceConfig.SetCompressorRatio (m_nCompressorRatio[nTG], nTG); + m_PerformanceConfig.SetCompressorMakeupGain (m_nCompressorMakeupGain[nTG], nTG); m_PerformanceConfig.SetEQLow (m_nEQLow[nTG], nTG); m_PerformanceConfig.SetEQMid (m_nEQMid[nTG], nTG); @@ -1779,10 +1779,10 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetLimiterEnable (m_nParameter[ParameterLimiterEnable]); m_PerformanceConfig.SetLimiterPreGain (m_nParameter[ParameterLimiterPreGain]); - m_PerformanceConfig.SetLimiterAttack (m_nParameter[ParameterLimiterAttack]); - m_PerformanceConfig.SetLimiterRelease (m_nParameter[ParameterLimiterRelease]); m_PerformanceConfig.SetLimiterThresh (m_nParameter[ParameterLimiterThresh]); m_PerformanceConfig.SetLimiterRatio (m_nParameter[ParameterLimiterRatio]); + m_PerformanceConfig.SetLimiterAttack (m_nParameter[ParameterLimiterAttack]); + m_PerformanceConfig.SetLimiterRelease (m_nParameter[ParameterLimiterRelease]); m_PerformanceConfig.SetLimiterHPFilterEnable (m_nParameter[ParameterLimiterHPFilterEnable]); if(m_bSaveAsDeault) @@ -1817,63 +1817,63 @@ void CMiniDexed::SetCompressorPreGain (int preGain, unsigned nTG) m_UI.ParameterChanged (); } -void CMiniDexed::SetCompressorMakeupGain (int makeupGain, unsigned nTG) +void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) { - makeupGain = constrain (makeupGain, -20, 20); + thresh = constrain (thresh, -60, 0); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); - m_nCompressorMakeupGain[nTG] = makeupGain; - m_pTG[nTG]->Compr.setMakeupGain_dB (makeupGain); + m_nCompressorThresh[nTG] = thresh; + m_pTG[nTG]->Compr.setThresh_dBFS (thresh); m_UI.ParameterChanged (); } -void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) +void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) { - attack = constrain (attack, 0u, 1000u); + ratio = constrain (ratio, 1u, 20u); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); - m_nCompressorAttack[nTG] = attack; - m_pTG[nTG]->Compr.setAttack_sec (attack / 1000.0, m_pConfig->GetSampleRate ()); + m_nCompressorRatio[nTG] = ratio; + m_pTG[nTG]->Compr.setCompressionRatio (ratio); m_UI.ParameterChanged (); } -void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) +void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) { - release = constrain (release, 0u, 1000u); + attack = constrain (attack, 0u, 1000u); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); - m_nCompressorRelease[nTG] = release; - m_pTG[nTG]->Compr.setRelease_sec (release / 1000.0, m_pConfig->GetSampleRate ()); + m_nCompressorAttack[nTG] = attack; + m_pTG[nTG]->Compr.setAttack_sec (attack / 1000.0, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } -void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) +void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) { - thresh = constrain (thresh, -60, 0); + release = constrain (release, 0u, 1000u); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); - m_nCompressorThresh[nTG] = thresh; - m_pTG[nTG]->Compr.setThresh_dBFS (thresh); + m_nCompressorRelease[nTG] = release; + m_pTG[nTG]->Compr.setRelease_sec (release / 1000.0, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } -void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) +void CMiniDexed::SetCompressorMakeupGain (int makeupGain, unsigned nTG) { - ratio = constrain (ratio, 1u, 20u); + makeupGain = constrain (makeupGain, -20, 20); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); - m_nCompressorRatio[nTG] = ratio; - m_pTG[nTG]->Compr.setCompressionRatio (ratio); + m_nCompressorMakeupGain[nTG] = makeupGain; + m_pTG[nTG]->Compr.setMakeupGain_dB (makeupGain); m_UI.ParameterChanged (); } @@ -2454,11 +2454,11 @@ void CMiniDexed::LoadPerformanceParameters(void) SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); - SetCompressorMakeupGain (m_PerformanceConfig.GetCompressorMakeupGain (nTG), nTG); + SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); + SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); - SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); - SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); + SetCompressorMakeupGain (m_PerformanceConfig.GetCompressorMakeupGain (nTG), nTG); SetEQLow (m_PerformanceConfig.GetEQLow (nTG), nTG); SetEQMid (m_PerformanceConfig.GetEQMid (nTG), nTG); @@ -2486,10 +2486,10 @@ void CMiniDexed::LoadPerformanceParameters(void) SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); - SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); - SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); SetParameter (ParameterLimiterThresh, m_PerformanceConfig.GetLimiterThresh ()); SetParameter (ParameterLimiterRatio, m_PerformanceConfig.GetLimiterRatio ()); + SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); + SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); SetParameter (ParameterLimiterHPFilterEnable, m_PerformanceConfig.GetLimiterHPFilterEnable ()); m_UI.DisplayChanged (); diff --git a/src/minidexed.h b/src/minidexed.h index 141813dce..ecb95405a 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -111,11 +111,11 @@ class CMiniDexed void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) - void SetCompressorMakeupGain (int makeupGain, unsigned nTG); // -20 .. 20 dB (default 0) - void SetCompressorAttack (unsigned attack, unsigned nTG); // 0 .. 1000 ms (default 5) - void SetCompressorRelease (unsigned release, unsigned nTG); // 0 .. 1000 ms (default 200) void SetCompressorThresh (int thresh, unsigned nTG); // -60 .. 0 dBFS (default -20) void SetCompressorRatio (unsigned ratio, unsigned nTG); // 1 .. 20 (default 5) + void SetCompressorAttack (unsigned attack, unsigned nTG); // 0 .. 1000 ms (default 5) + void SetCompressorRelease (unsigned release, unsigned nTG); // 0 .. 1000 ms (default 200) + void SetCompressorMakeupGain (int makeupGain, unsigned nTG); // -20 .. 20 dB (default 0) void SetEQLow (int nValue, unsigned nTG); void SetEQMid (int nValue, unsigned nTG); @@ -193,10 +193,10 @@ class CMiniDexed ParameterMasterVolume, ParameterLimiterEnable, ParameterLimiterPreGain, - ParameterLimiterAttack, - ParameterLimiterRelease, ParameterLimiterThresh, ParameterLimiterRatio, + ParameterLimiterAttack, + ParameterLimiterRelease, ParameterLimiterHPFilterEnable, ParameterMasterEQLow, ParameterMasterEQMid, @@ -262,11 +262,11 @@ class CMiniDexed TGParameterCompressorEnable, TGParameterCompressorPreGain, - TGParameterCompressorMakeupGain, - TGParameterCompressorAttack, - TGParameterCompressorRelease, TGParameterCompressorThresh, TGParameterCompressorRatio, + TGParameterCompressorAttack, + TGParameterCompressorRelease, + TGParameterCompressorMakeupGain, TGParameterEQLow, TGParameterEQMid, @@ -360,11 +360,11 @@ class CMiniDexed bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; - int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; - unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; - unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; int m_nCompressorThresh[CConfig::AllToneGenerators]; unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; int m_nEQLow[CConfig::AllToneGenerators]; int m_nEQMid[CConfig::AllToneGenerators]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 3b912e725..16ac81ea8 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -215,8 +215,11 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("CompressorPreGain%u", nTG+1); m_nCompressorPreGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); - PropertyName.Format ("CompressorMakeupGain%u", nTG+1); - m_nCompressorMakeupGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_nCompressorThresh[nTG] = m_Properties.GetSignedNumber (PropertyName, -20); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_nCompressorRatio[nTG] = m_Properties.GetNumber (PropertyName, 5); PropertyName.Format ("CompressorAttack%u", nTG+1); m_nCompressorAttack[nTG] = m_Properties.GetNumber (PropertyName, 5); @@ -224,11 +227,8 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("CompressorRelease%u", nTG+1); m_nCompressorRelease[nTG] = m_Properties.GetNumber (PropertyName, 200); - PropertyName.Format ("CompressorThresh%u", nTG+1); - m_nCompressorThresh[nTG] = m_Properties.GetSignedNumber (PropertyName, -20); - - PropertyName.Format ("CompressorRatio%u", nTG+1); - m_nCompressorRatio[nTG] = m_Properties.GetNumber (PropertyName, 5); + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_nCompressorMakeupGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); PropertyName.Format ("EQLow%u", nTG+1); m_nEQLow[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); @@ -266,10 +266,10 @@ bool CPerformanceConfig::Load (void) m_bLimiterEnable = m_Properties.GetNumber ("LimiterEnable", 1); m_nLimiterPreGain = m_Properties.GetSignedNumber ("LimiterPreGain", 0); - m_nLimiterAttack = m_Properties.GetNumber ("LimiterAttack", 5); - m_nLimiterRelease = m_Properties.GetNumber ("LimiterRelease", 5); m_nLimiterThresh = m_Properties.GetSignedNumber ("LimiterThresh", -3); m_nLimiterRatio = m_Properties.GetNumber ("LimiterRatio", 20); + m_nLimiterAttack = m_Properties.GetNumber ("LimiterAttack", 5); + m_nLimiterRelease = m_Properties.GetNumber ("LimiterRelease", 5); m_bLimiterHPFilterEnable = m_Properties.GetNumber ("LimiterHPFilterEnable", 0); // Compatibility @@ -393,8 +393,11 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("CompressorPreGain%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nCompressorPreGain[nTG]); - PropertyName.Format ("CompressorMakeupGain%u", nTG+1); - m_Properties.SetSignedNumber (PropertyName, m_nCompressorMakeupGain[nTG]); + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorThresh[nTG]); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorRatio[nTG]); PropertyName.Format ("CompressorAttack%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nCompressorAttack[nTG]); @@ -402,11 +405,8 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("CompressorRelease%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nCompressorRelease[nTG]); - PropertyName.Format ("CompressorThresh%u", nTG+1); - m_Properties.SetSignedNumber (PropertyName, m_nCompressorThresh[nTG]); - - PropertyName.Format ("CompressorRatio%u", nTG+1); - m_Properties.SetNumber (PropertyName, m_nCompressorRatio[nTG]); + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorMakeupGain[nTG]); PropertyName.Format ("EQLow%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nEQLow[nTG]); @@ -445,10 +445,10 @@ bool CPerformanceConfig::Save (void) m_Properties.SetNumber ("LimiterEnable", m_bLimiterEnable); m_Properties.SetSignedNumber ("LimiterPreGain", m_nLimiterPreGain); - m_Properties.SetNumber ("LimiterAttack", m_nLimiterAttack); - m_Properties.SetNumber ("LimiterRelease", m_nLimiterRelease); m_Properties.SetSignedNumber ("LimiterThresh", m_nLimiterThresh); m_Properties.SetNumber ("LimiterRatio", m_nLimiterRatio); + m_Properties.SetNumber ("LimiterAttack", m_nLimiterAttack); + m_Properties.SetNumber ("LimiterRelease", m_nLimiterRelease); m_Properties.SetNumber ("LimiterHPFilterEnable", m_bLimiterHPFilterEnable); return m_Properties.Save (); @@ -811,24 +811,24 @@ int CPerformanceConfig::GetLimiterPreGain () const return m_nLimiterPreGain; } -unsigned CPerformanceConfig::GetLimiterAttack () const +int CPerformanceConfig::GetLimiterThresh () const { - return m_nLimiterAttack; + return m_nLimiterThresh; } -unsigned CPerformanceConfig::GetLimiterRelease () const +unsigned CPerformanceConfig::GetLimiterRatio () const { - return m_nLimiterRelease; + return m_nLimiterRatio; } -int CPerformanceConfig::GetLimiterThresh () const +unsigned CPerformanceConfig::GetLimiterAttack () const { - return m_nLimiterThresh; + return m_nLimiterAttack; } -unsigned CPerformanceConfig::GetLimiterRatio () const +unsigned CPerformanceConfig::GetLimiterRelease () const { - return m_nLimiterRatio; + return m_nLimiterRelease; } bool CPerformanceConfig::GetLimiterHPFilterEnable () const @@ -846,24 +846,24 @@ void CPerformanceConfig::SetLimiterPreGain (int nValue) m_nLimiterPreGain= nValue; } -void CPerformanceConfig::SetLimiterAttack (unsigned nValue) +void CPerformanceConfig::SetLimiterThresh (int nValue) { - m_nLimiterAttack = nValue; + m_nLimiterThresh = nValue; } -void CPerformanceConfig::SetLimiterRelease (unsigned nValue) +void CPerformanceConfig::SetLimiterRatio (unsigned nValue) { - m_nLimiterRelease = nValue; + m_nLimiterRatio = nValue; } -void CPerformanceConfig::SetLimiterThresh (int nValue) +void CPerformanceConfig::SetLimiterAttack (unsigned nValue) { - m_nLimiterThresh = nValue; + m_nLimiterAttack = nValue; } -void CPerformanceConfig::SetLimiterRatio (unsigned nValue) +void CPerformanceConfig::SetLimiterRelease (unsigned nValue) { - m_nLimiterRatio = nValue; + m_nLimiterRelease = nValue; } void CPerformanceConfig::SetLimiterHPFilterEnable (bool nValue) @@ -1067,64 +1067,64 @@ int CPerformanceConfig::GetCompressorPreGain (unsigned nTG) const return m_nCompressorPreGain[nTG]; } -void CPerformanceConfig::SetCompressorMakeupGain (int nValue, unsigned nTG) +void CPerformanceConfig::SetCompressorThresh (int nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nCompressorMakeupGain[nTG] = nValue; + m_nCompressorThresh[nTG] = nValue; } -int CPerformanceConfig::GetCompressorMakeupGain (unsigned nTG) const +int CPerformanceConfig::GetCompressorThresh (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nCompressorMakeupGain[nTG]; + return m_nCompressorThresh[nTG]; } -void CPerformanceConfig::SetCompressorAttack (unsigned nValue, unsigned nTG) +void CPerformanceConfig::SetCompressorRatio (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nCompressorAttack[nTG] = nValue; + m_nCompressorRatio[nTG] = nValue; } -unsigned CPerformanceConfig::GetCompressorAttack (unsigned nTG) const +unsigned CPerformanceConfig::GetCompressorRatio (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nCompressorAttack[nTG]; + return m_nCompressorRatio[nTG]; } -void CPerformanceConfig::SetCompressorRelease (unsigned nValue, unsigned nTG) +void CPerformanceConfig::SetCompressorAttack (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nCompressorRelease[nTG] = nValue; + m_nCompressorAttack[nTG] = nValue; } -unsigned CPerformanceConfig::GetCompressorRelease (unsigned nTG) const +unsigned CPerformanceConfig::GetCompressorAttack (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nCompressorRelease[nTG]; + return m_nCompressorAttack[nTG]; } -void CPerformanceConfig::SetCompressorThresh (int nValue, unsigned nTG) +void CPerformanceConfig::SetCompressorRelease (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nCompressorThresh[nTG] = nValue; + m_nCompressorRelease[nTG] = nValue; } -int CPerformanceConfig::GetCompressorThresh (unsigned nTG) const +unsigned CPerformanceConfig::GetCompressorRelease (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nCompressorThresh[nTG]; + return m_nCompressorRelease[nTG]; } -void CPerformanceConfig::SetCompressorRatio (unsigned nValue, unsigned nTG) +void CPerformanceConfig::SetCompressorMakeupGain (int nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nCompressorRatio[nTG] = nValue; + m_nCompressorMakeupGain[nTG] = nValue; } -unsigned CPerformanceConfig::GetCompressorRatio (unsigned nTG) const +int CPerformanceConfig::GetCompressorMakeupGain (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nCompressorRatio[nTG]; + return m_nCompressorMakeupGain[nTG]; } diff --git a/src/performanceconfig.h b/src/performanceconfig.h index a77281567..d899a4561 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -73,11 +73,11 @@ class CPerformanceConfig // Performance configuration bool GetCompressorEnable (unsigned nTG) const; // 0 .. 1 int GetCompressorPreGain (unsigned nTG) const; - int GetCompressorMakeupGain (unsigned nTG) const; - unsigned GetCompressorAttack (unsigned nTG) const; - unsigned GetCompressorRelease (unsigned nTG) const; int GetCompressorThresh (unsigned nTG) const; unsigned GetCompressorRatio (unsigned nTG) const; + unsigned GetCompressorAttack (unsigned nTG) const; + unsigned GetCompressorRelease (unsigned nTG) const; + int GetCompressorMakeupGain (unsigned nTG) const; void SetBankNumber (unsigned nValue, unsigned nTG); void SetVoiceNumber (unsigned nValue, unsigned nTG); @@ -111,11 +111,11 @@ class CPerformanceConfig // Performance configuration void SetCompressorEnable (bool nValue, unsigned nTG); void SetCompressorPreGain (int nValue, unsigned nTG); - void SetCompressorMakeupGain (int nValue, unsigned nTG); + void SetCompressorThresh (int nValue, unsigned nTG); + void SetCompressorRatio (unsigned nValue, unsigned nTG); void SetCompressorAttack (unsigned nValue, unsigned nTG); void SetCompressorRelease (unsigned nValue, unsigned nTG); - void SetCompressorThresh (int nValue, unsigned nTG); - void SetCompressorRatio (unsigned nValue, unsigned nTG); + void SetCompressorMakeupGain (int nValue, unsigned nTG); int GetEQLow (unsigned nTG) const; int GetEQMid (unsigned nTG) const; @@ -164,18 +164,18 @@ class CPerformanceConfig // Performance configuration bool GetLimiterEnable () const; int GetLimiterPreGain () const; - unsigned GetLimiterAttack () const; - unsigned GetLimiterRelease () const; int GetLimiterThresh () const; unsigned GetLimiterRatio () const; + unsigned GetLimiterAttack () const; + unsigned GetLimiterRelease () const; bool GetLimiterHPFilterEnable () const; void SetLimiterEnable (bool nValue); void SetLimiterPreGain (int nValue); - void SetLimiterAttack (unsigned nValue); - void SetLimiterRelease (unsigned nValue); void SetLimiterThresh (int nValue); void SetLimiterRatio (unsigned nValue); + void SetLimiterAttack (unsigned nValue); + void SetLimiterRelease (unsigned nValue); void SetLimiterHPFilterEnable (bool nValue); bool VoiceDataFilled(unsigned nTG); @@ -243,11 +243,11 @@ class CPerformanceConfig // Performance configuration bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; - int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; - unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; - unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; int m_nCompressorThresh[CConfig::AllToneGenerators]; unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; int m_nEQLow[CConfig::AllToneGenerators]; int m_nEQMid[CConfig::AllToneGenerators]; @@ -286,10 +286,10 @@ class CPerformanceConfig // Performance configuration bool m_bLimiterEnable; int m_nLimiterPreGain; - unsigned m_nLimiterAttack; - unsigned m_nLimiterRelease; int m_nLimiterThresh; unsigned m_nLimiterRatio; + unsigned m_nLimiterAttack; + unsigned m_nLimiterRelease; bool m_bLimiterHPFilterEnable; }; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index a974054f0..28a5e3c8e 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -98,11 +98,11 @@ const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = { {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable}, {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain}, - {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain}, - {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack}, - {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease}, {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh}, {"Ratio", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRatio}, + {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack}, + {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease}, + {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain}, {0} }; @@ -197,10 +197,10 @@ const CUIMenu::TMenuItem CUIMenu::s_LimiterMenu[] = { {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterEnable}, {"Pre Gain", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterPreGain}, - {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterAttack}, - {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRelease}, {"Threshold", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterThresh}, {"Ratio", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRatio}, + {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterAttack}, + {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRelease}, {"HPFilter", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterHPFilterEnable}, {0} }; @@ -289,10 +289,10 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, 127, 8, ToVolume}, // ParameterMasterVolume {0, 1, 1, ToOnOff}, // ParameterLimiterEnable {-20, 20, 1, TodB}, // ParameterLimiterPreGain - {0, 1000, 5, ToMillisec}, // ParameterLimiterAttack - {0, 1000, 5, ToMillisec}, // ParameterLimiterRelease {-60, 0, 1, TodBFS}, // ParameterLimiterThresh {1, 20, 1, ToRatio}, // ParameterLimiterRatio + {0, 1000, 5, ToMillisec}, // ParameterLimiterAttack + {0, 1000, 5, ToMillisec}, // ParameterLimiterRelease {0, 1, 1, ToOnOff}, // ParameterLimiterHPFilterEnable {-24, 24, 1, TodB}, // ParameterMasterEQLow {-24, 24, 1, TodB}, // ParameterMasterEQMid @@ -343,11 +343,11 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1, 1, ToOnOff}, //AT EGBias {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable {-20, 20, 1, TodB}, // TGParameterCompressorPreGain - {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain - {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack - {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh {1, 20, 1, ToRatio}, // TGParameterCompressorRatio + {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack + {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease + {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain {-24, 24, 1, TodB}, // TGParameterEQLow {-24, 24, 1, TodB}, // TGParameterEQMid {-24, 24, 1, TodB}, // TGParameterEQHigh From b07e13fb7747668322abe2351aed8650f55c3a83 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 9 Sep 2025 03:50:40 +0200 Subject: [PATCH 059/136] effect_mixer: use simple slow ramping instead of zero cross detection Some performances have a DC component while silent, which prevents ramping. --- src/Makefile | 2 +- src/arm_scale_zc_ramp_f32.c | 119 ------------------------------------ src/arm_scale_zc_ramp_f32.h | 22 ------- src/effect_mixer.hpp | 42 +++++++++++-- src/minidexed.cpp | 9 ++- 5 files changed, 42 insertions(+), 152 deletions(-) delete mode 100644 src/arm_scale_zc_ramp_f32.c delete mode 100644 src/arm_scale_zc_ramp_f32.h diff --git a/src/Makefile b/src/Makefile index b6232edf8..ae723c1ee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ effect_platervbstereo.o uibuttons.o midipin.o \ - arm_float_to_q23.o arm_scale_zc_ramp_f32.o arm_zip_f32.o arm_scale_zip_f32.o \ + arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) diff --git a/src/arm_scale_zc_ramp_f32.c b/src/arm_scale_zc_ramp_f32.c deleted file mode 100644 index 933437c71..000000000 --- a/src/arm_scale_zc_ramp_f32.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "arm_scale_zc_ramp_f32.h" - -const float32_t RAMP_DT = 1.0 / 254; -const float32_t RAMP_EPS = 1.0 / 127; - -/** -* @brief Scale a floating-point vector with a scalar and scalar2 after a zero cross. -* @param[in] pSrc points to the input vector 1 -* @param[in] scale1 scale1 scalar -* @param[in] scale2 scale2 scalar -* @param[out] pDst points to the output vector -* @param[in] blockSize number of samples in the vector -*/ - -#if defined(ARM_MATH_NEON_EXPERIMENTAL) - -static inline int -v_any_u32(uint32x4_t d) -{ - return vpaddd_u64(vreinterpretq_u64_u32(d)) != 0; -} - -void arm_scale_zc_ramp_f32( - const float32_t * pSrc, - float32_t * pScale, - float32_t dScale, - float32_t * pDst, - uint32_t blockSize) -{ - uint32_t blkCnt; /* Loop counter */ - float32_t scale = *pScale; - - f32x4_t res; - - blkCnt = blockSize >> 2U; - - while (blkCnt > 0U) - { - res = vmulq_n_f32(vld1q_f32(pSrc), scale); - vst1q_f32(pDst, res); - - pSrc += 4; - pDst += 4; - - /* Decrement the loop counter */ - blkCnt--; - - if (scale != dScale && blkCnt) - { - f32x4_t resn1 = vld1q_f32(pSrc-3); - - // this probably runs faster, but does not find all zc - // so ramping is a bit slower - //if (vminnmvq_f32(res) <= 0 && vmaxnmvq_f32(res) >= 0) - - if (v_any_u32(vorrq_u32( - vandq_u32(vcgezq_f32(res), vclezq_f32(resn1)), - vandq_u32(vclezq_f32(res), vcgezq_f32(resn1)) - ))) - { - scale += dScale > scale ? RAMP_DT : -RAMP_DT; - if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; - } - } - } - - /* If the blockSize is not a multiple of 4, compute any remaining output samples here. - ** No loop unrolling is used. */ - blkCnt = blockSize & 3; - - while (blkCnt > 0U) - { - *pDst++ = *pSrc++ * scale; - - /* Decrement the loop counter */ - blkCnt--; - - if (blkCnt && scale != dScale && (*(pSrc-1) <= 0 && *pSrc >= 0 || *(pSrc-1) >= 0 && *pSrc <= 0)) - { - scale += dScale > scale ? RAMP_DT : -RAMP_DT; - if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; - } - } - - *pScale = scale; -} - -#else - -void arm_scale_zc_ramp_f32( - const float32_t * pSrc, - float32_t * pScale, - float32_t dScale, - float32_t * pDst, - uint32_t blockSize) -{ - uint32_t blkCnt; /* Loop counter */ - float32_t scale = *pScale; - - blkCnt = blockSize; - - while (blkCnt > 0U) - { - *pDst++ = *pSrc++ * scale; - - /* Decrement the loop counter */ - blkCnt--; - - if (blkCnt && scale != dScale && (*(pSrc-1) <= 0 && *pSrc >= 0 || *(pSrc-1) >= 0 && *pSrc <= 0)) - { - scale += dScale > scale ? RAMP_DT : -RAMP_DT; - if (fabs(dScale - scale) < RAMP_EPS) scale = dScale; - } - } - - *pScale = scale; -} - -#endif diff --git a/src/arm_scale_zc_ramp_f32.h b/src/arm_scale_zc_ramp_f32.h deleted file mode 100644 index 6e7d51702..000000000 --- a/src/arm_scale_zc_ramp_f32.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "arm_math_types.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** -* @brief Scale a floating-point vector with a scalar and scalar2 after a zero cross. -* @param[in] pSrc points to the input vector 1 -* @param[inout] pScale points to actual scale scalar -* @param[in] dScale destination scale scalar -* @param[out] pDst points to the output vector -* @param[in] blockSize number of samples in the vector -*/ -void arm_scale_zc_ramp_f32(const float32_t * pSrc, float32_t * pScale, float32_t dScale, float32_t * pDst, uint32_t blockSize); - -#ifdef __cplusplus -} -#endif diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 754fc882a..e4185b687 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -7,7 +7,6 @@ #include #include #include -#include "arm_scale_zc_ramp_f32.h" #define UNITY_GAIN 1.0f #define MAX_GAIN 1.0f @@ -16,10 +15,41 @@ #define MAX_PANORAMA 1.0f #define MIN_PANORAMA 0.0f +void inline scale_ramp_f32( + const float32_t * pSrc, + float32_t * pScale, + float32_t dScale, + float32_t ramp, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + float32_t scale = *pScale; + + blkCnt = blockSize; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc++ * scale; + + blkCnt--; + + if (blkCnt && scale != dScale) + { + if (dScale > scale) scale = fmin(dScale, scale + ramp); + else if (dScale < scale) scale = fmax(dScale, scale - ramp); + } + } + + *pScale = scale; +} + + template class AudioMixer { public: - AudioMixer(uint16_t len) + AudioMixer(uint16_t len, float32_t samplerate): + ramp{10.0f / samplerate} // 100ms { buffer_length=len; for (uint8_t i=0; i class AudioMixer float32_t multiplier[NN]; float32_t* sumbufL; uint16_t buffer_length; + const float32_t ramp; }; template class AudioStereoMixer : public AudioMixer { public: - AudioStereoMixer(uint16_t len) : AudioMixer(len) + AudioStereoMixer(uint16_t len, float32_t samplerate) : AudioMixer(len, samplerate) { for (uint8_t i=0; i class AudioStereoMixer : public AudioMixer if (mp[channel][0] == mp_w[channel][0]) arm_scale_f32(in, mp[channel][0], tmp, buffer_length); else - arm_scale_zc_ramp_f32(in, &mp[channel][0], mp_w[channel][0], tmp, buffer_length); + scale_ramp_f32(in, &mp[channel][0], mp_w[channel][0], ramp, tmp, buffer_length); arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); if (mp[channel][1] == mp_w[channel][1]) arm_scale_f32(in, mp[channel][1], tmp, buffer_length); else - arm_scale_zc_ramp_f32(in, &mp[channel][1], mp_w[channel][1], tmp, buffer_length); + scale_ramp_f32(in, &mp[channel][1], mp_w[channel][1], ramp, tmp, buffer_length); arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } @@ -211,6 +242,7 @@ template class AudioStereoMixer : public AudioMixer using AudioMixer::sumbufL; using AudioMixer::multiplier; using AudioMixer::buffer_length; + using AudioMixer::ramp; float32_t panorama[NN][2]; float32_t mp[NN][2]; float32_t mp_w[NN][2]; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 7de0bda23..7eea0187d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -30,7 +30,6 @@ #include #include #include "arm_float_to_q23.h" -#include "arm_scale_zc_ramp_f32.h" #include "arm_scale_zip_f32.h" #include "arm_zip_f32.h" @@ -260,11 +259,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, #endif // BEGIN setup tg_mixer - tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); + tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); // END setup tgmixer // BEGIN setup reverb - reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); + reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); SetParameter (ParameterMasterEQLow, 0); @@ -1637,8 +1636,8 @@ void CMiniDexed::ProcessSound (void) } else { - arm_scale_zc_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], m_fMasterVolumeW, SampleBuffer[0], nFrames); - arm_scale_zc_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], m_fMasterVolumeW, SampleBuffer[1], nFrames); + scale_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], m_fMasterVolumeW, m_fRamp, SampleBuffer[0], nFrames); + scale_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], m_fMasterVolumeW, m_fRamp, SampleBuffer[1], nFrames); arm_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], tmp_float, nFrames); } From 9d60a737155f17f4072a98c016c71668a0e8fa73 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 9 Sep 2025 21:37:44 +0200 Subject: [PATCH 060/136] reverb: add explicit reset --- src/effect_platervbstereo.cpp | 82 ++++++++++++++++++++++++----------- src/effect_platervbstereo.h | 2 + 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index 6cae1287f..6a69771ed 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -158,6 +158,63 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) // #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift)) +void AudioEffectPlateReverb::reset() +{ + memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); + memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); + memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); + memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); + in_allp1_idxL = 0; + in_allp2_idxL = 0; + in_allp3_idxL = 0; + in_allp4_idxL = 0; + + memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); + memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); + memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); + memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); + in_allp1_idxR = 0; + in_allp2_idxR = 0; + in_allp3_idxR = 0; + in_allp4_idxR = 0; + + memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); + memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); + memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); + memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); + lp_allp1_idx = 0; + lp_allp2_idx = 0; + lp_allp3_idx = 0; + lp_allp4_idx = 0; + + lp_allp_out = 0.0f; + + memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); + memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); + memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); + memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); + lp_dly1_idx = 0; + lp_dly2_idx = 0; + lp_dly3_idx = 0; + lp_dly4_idx = 0; + + lpf1 = 0.0f; + lpf2 = 0.0f; + lpf3 = 0.0f; + lpf4 = 0.0f; + + hpf1 = 0.0f; + hpf2 = 0.0f; + hpf3 = 0.0f; + hpf4 = 0.0f; + + master_lowpass_l = 0.0f; + master_lowpass_r = 0.0f; + + lfo1_phase_acc = 0; + lfo2_phase_acc = 0; +} + void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len) { float32_t input, acc, temp1, temp2; @@ -169,36 +226,11 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t int32_t y0, y1; int64_t y; uint32_t idx; - static bool cleanup_done = false; - // handle bypass, 1st call will clean the buffers to avoid continuing the previous reverb tail if (bypass) { - if (!cleanup_done) - { - memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); - memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); - memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); - memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); - memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); - memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); - memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); - memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); - memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); - memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); - memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); - memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); - memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); - memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); - memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); - memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); - - cleanup_done = true; - } - return; } - cleanup_done = false; rv_time = rv_time_k; diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 8d3716c45..13bad8e72 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -109,6 +109,8 @@ class AudioEffectPlateReverb void set_bypass(bool state) {bypass = state;}; void tgl_bypass(void) {bypass ^=1;} float32_t get_level(void) {return reverb_level;} + + void reset(); private: bool bypass = false; float32_t reverb_level; From 6400d24c1a0202d3f23bb35592032ac96b4b064c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 26 Aug 2025 15:53:59 +0200 Subject: [PATCH 061/136] AudioEffect3BandEQ: add resetState() function --- src/effect_3bandeq.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h index 7585ad143..1aa778f8c 100644 --- a/src/effect_3bandeq.h +++ b/src/effect_3bandeq.h @@ -93,6 +93,8 @@ class AudioEffect3BandEQ unsigned getLowMidFreq_n() const { return nLowMidFreq; } unsigned getMidHighFreq_n() const { return nMidHighFreq; } + void resetState() { tmpLP = 0.0f; tmpHP = 0.0f; } + void process(float32_t* block, uint16_t len) { float outLP, outHP; From 243f0f82b46ab1d76d321011ea6232fdcf91a7e6 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 26 Aug 2025 00:04:30 +0200 Subject: [PATCH 062/136] Volume ramping before and after performance change --- Synth_Dexed | 2 +- src/dexedadapter.h | 10 ++++++++++ src/minidexed.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/minidexed.h | 5 +++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Synth_Dexed b/Synth_Dexed index 376dd1d2f..6db60575b 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit 376dd1d2f53a95ce1581cb636304debb4064e735 +Subproject commit 6db60575b467a4652a1aa6676b711d5dc1add13e diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 9631b7dbf..7a6a038fb 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -98,6 +98,16 @@ class CDexedAdapter : public Dexed m_SpinLock.Release (); } + void resetState () + { + m_SpinLock.Acquire (); + deactivate (); + resetFxState (); + EQ.resetState (); + Compr.resetStates (); + m_SpinLock.Release (); + } + AudioEffect3BandEQ EQ; Compressor Compr; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 7eea0187d..de512ef90 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -87,7 +87,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bSetFirstPerformance (false), m_bDeletePerformance (false), m_bLoadPerformanceBusy(false), - m_bLoadPerformanceBankBusy(false) + m_bLoadPerformanceBankBusy(false), + m_bVolRampDownWait{}, + m_bVolRampedDown{}, + m_fRamp{10.0f / pConfig->GetSampleRate()} { assert (m_pConfig); @@ -477,12 +480,21 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) pScheduler->Yield(); } - if (m_bSetNewPerformance && !m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) + if (m_bSetNewPerformance && m_bVolRampedDown && !m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) { + for (unsigned i = 0; i < m_nToneGenerators; ++i) + { + m_pTG[i]->resetState(); + } + DoSetNewPerformance (); + + reverb->reset(); + if (m_nSetNewPerformanceID == GetActualPerformanceID()) { m_bSetNewPerformance = false; + m_bVolRampedDown = false; } pScheduler->Yield(); } @@ -1630,7 +1642,25 @@ void CMiniDexed::ProcessSound (void) } // Convert dual float array (left, right) to single int32 (q23) array (left/right) - if (m_fMasterVolume[0] == m_fMasterVolumeW && m_fMasterVolume[1] == m_fMasterVolumeW) + if (m_bVolRampDownWait) + { + float targetVol = 0.0f; + + scale_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], targetVol, m_fRamp, SampleBuffer[0], nFrames); + scale_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], targetVol, m_fRamp, SampleBuffer[1], nFrames); + arm_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], tmp_float, nFrames); + + if (targetVol == m_fMasterVolume[0] && targetVol == m_fMasterVolume[1]) + { + m_bVolRampDownWait = false; + m_bVolRampedDown = true; + } + } + else if (m_bVolRampedDown) + { + arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], 0.0f, tmp_float, nFrames); + } + else if (m_fMasterVolume[0] == m_fMasterVolumeW && m_fMasterVolume[1] == m_fMasterVolumeW) { arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], m_fMasterVolumeW, tmp_float, nFrames); } @@ -2325,6 +2355,8 @@ bool CMiniDexed::SetNewPerformance(unsigned nID) { m_bSetNewPerformance = true; m_nSetNewPerformanceID = nID; + if (!m_bVolRampedDown) + m_bVolRampDownWait = true; return true; } diff --git a/src/minidexed.h b/src/minidexed.h index ecb95405a..bbd30c2ee 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -439,6 +439,11 @@ class CMiniDexed bool m_bLoadPerformanceBusy; bool m_bLoadPerformanceBankBusy; bool m_bSaveAsDeault; + + std::atomic m_bVolRampDownWait; + std::atomic m_bVolRampedDown; + + const float32_t m_fRamp; }; #endif From 114e3aaa1b83c2d452c32b4386607b304b2361d6 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 10 Sep 2025 17:20:12 +0200 Subject: [PATCH 063/136] AudioMixer: simplify scale_ramp_f32 --- src/effect_mixer.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index e4185b687..27bca94a9 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -30,15 +30,16 @@ void inline scale_ramp_f32( while (blkCnt > 0U) { + if (scale != dScale) + { + scale = dScale > scale ? + fmin(dScale, scale + ramp): + fmax(dScale, scale - ramp); + } + *pDst++ = *pSrc++ * scale; blkCnt--; - - if (blkCnt && scale != dScale) - { - if (dScale > scale) scale = fmin(dScale, scale + ramp); - else if (dScale < scale) scale = fmax(dScale, scale - ramp); - } } *pScale = scale; From 34020d02186311e4a597e10f622de956a8ef9949 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 10 Sep 2025 17:39:18 +0200 Subject: [PATCH 064/136] Synth_Dexed: update to e3f524c8b (PluginFx: use small ramping instead of zero cross detection) --- Synth_Dexed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Synth_Dexed b/Synth_Dexed index 6db60575b..e3f524c8b 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit 6db60575b467a4652a1aa6676b711d5dc1add13e +Subproject commit e3f524c8bd92cdd37d0aea2728ea991254dda8ab From 8645e3e35f2a665062050bd22553e7a494fb6f21 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 11 Sep 2025 16:19:16 +0200 Subject: [PATCH 065/136] Add TG-Links Now every TG has a TG-Link parameter. default: - Possible values: - A B C D If you modify a parameter whose TG belongs to a TG-Link, the parameter of the TGs belonging to the group will also be modified. Except Pan, MasterTune and TG-Link parameters. --- src/mididevice.cpp | 6 ++ src/minidexed.cpp | 200 +++++++++++++++++++++++--------------- src/minidexed.h | 6 ++ src/performanceconfig.cpp | 21 +++- src/performanceconfig.h | 3 + src/uimenu.cpp | 8 ++ src/uimenu.h | 1 + 7 files changed, 164 insertions(+), 81 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index c10fd7dfa..09e2bf232 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -527,6 +527,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case MIDI_CC_PAN_POSITION: + if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) + break; + m_pSynthesizer->SetPan (pMessage[2], nTG); break; @@ -574,6 +577,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case MIDI_CC_DETUNE_LEVEL: + if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) + break; + if (pMessage[2] == 0) { // 0 to 127, with 0 being no detune effect applied at all diff --git a/src/minidexed.cpp b/src/minidexed.cpp index de512ef90..51f08dc8d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -116,6 +116,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nPortamentoGlissando[i] = 0; m_nPortamentoTime[i] = 0; m_bMonoMode[i]=0; + m_nTGLink[i]=0; m_nNoteLimitLow[i] = 0; m_nNoteLimitHigh[i] = 127; m_nNoteShift[i] = 0; @@ -1237,73 +1238,91 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG - switch (Parameter) + unsigned nTGLink = m_nTGLink[nTG]; + + for (unsigned i = 0; i < m_nToneGenerators; i++) { - case TGParameterVoiceBank: BankSelect (nValue, nTG); break; - case TGParameterVoiceBankMSB: BankSelectMSB (nValue, nTG); break; - case TGParameterVoiceBankLSB: BankSelectLSB (nValue, nTG); break; - case TGParameterProgram: ProgramChange (nValue, nTG); break; - case TGParameterVolume: SetVolume (nValue, nTG); break; - case TGParameterPan: SetPan (nValue, nTG); break; - case TGParameterMasterTune: SetMasterTune (nValue, nTG); break; - case TGParameterCutoff: SetCutoff (nValue, nTG); break; - case TGParameterResonance: SetResonance (nValue, nTG); break; - case TGParameterPitchBendRange: setPitchbendRange (nValue, nTG); break; - case TGParameterPitchBendStep: setPitchbendStep (nValue, nTG); break; - case TGParameterPortamentoMode: setPortamentoMode (nValue, nTG); break; - case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, nTG); break; - case TGParameterPortamentoTime: setPortamentoTime (nValue, nTG); break; - case TGParameterNoteLimitLow: setNoteLimitLow (nValue, nTG); break; - case TGParameterNoteLimitHigh: setNoteLimitHigh (nValue, nTG); break; - case TGParameterNoteShift: setNoteShift (nValue, nTG); break; - case TGParameterMonoMode: setMonoMode (nValue , nTG); break; - - case TGParameterMWRange: setModController(0, 0, nValue, nTG); break; - case TGParameterMWPitch: setModController(0, 1, nValue, nTG); break; - case TGParameterMWAmplitude: setModController(0, 2, nValue, nTG); break; - case TGParameterMWEGBias: setModController(0, 3, nValue, nTG); break; - - case TGParameterFCRange: setModController(1, 0, nValue, nTG); break; - case TGParameterFCPitch: setModController(1, 1, nValue, nTG); break; - case TGParameterFCAmplitude: setModController(1, 2, nValue, nTG); break; - case TGParameterFCEGBias: setModController(1, 3, nValue, nTG); break; - - case TGParameterBCRange: setModController(2, 0, nValue, nTG); break; - case TGParameterBCPitch: setModController(2, 1, nValue, nTG); break; - case TGParameterBCAmplitude: setModController(2, 2, nValue, nTG); break; - case TGParameterBCEGBias: setModController(2, 3, nValue, nTG); break; - - case TGParameterATRange: setModController(3, 0, nValue, nTG); break; - case TGParameterATPitch: setModController(3, 1, nValue, nTG); break; - case TGParameterATAmplitude: setModController(3, 2, nValue, nTG); break; - case TGParameterATEGBias: setModController(3, 3, nValue, nTG); break; - - - case TGParameterMIDIChannel: - assert (0 <= nValue && nValue <= 255); - SetMIDIChannel ((uint8_t) nValue, nTG); - break; + if (i != nTG && (!nTGLink || m_nTGLink[i] != nTGLink)) + continue; - case TGParameterReverbSend: SetReverbSend (nValue, nTG); break; + if (i != nTG && Parameter == TGParameterTGLink) + continue; - case TGParameterCompressorEnable: SetCompressorEnable (nValue, nTG); break; - case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, nTG); break; - case TGParameterCompressorThresh: SetCompressorThresh (nValue, nTG); break; - case TGParameterCompressorRatio: SetCompressorRatio (nValue, nTG); break; - case TGParameterCompressorAttack: SetCompressorAttack (nValue, nTG); break; - case TGParameterCompressorRelease: SetCompressorRelease (nValue, nTG); break; - case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, nTG); break; + if (i != nTG && Parameter == TGParameterPan) + continue; - case TGParameterEQLow: SetEQLow (nValue, nTG); break; - case TGParameterEQMid: SetEQMid (nValue, nTG); break; - case TGParameterEQHigh: SetEQHigh (nValue, nTG); break; - case TGParameterEQGain: SetEQGain (nValue, nTG); break; - case TGParameterEQLowMidFreq: SetEQLowMidFreq (nValue, nTG); break; - case TGParameterEQMidHighFreq: SetEQMidHighFreq (nValue, nTG); break; + if (i != nTG && Parameter == TGParameterMasterTune) + continue; - default: - assert (0); - break; + switch (Parameter) + { + case TGParameterVoiceBank: BankSelect (nValue, i); break; + case TGParameterVoiceBankMSB: BankSelectMSB (nValue, i); break; + case TGParameterVoiceBankLSB: BankSelectLSB (nValue, i); break; + case TGParameterProgram: ProgramChange (nValue, i); break; + case TGParameterVolume: SetVolume (nValue, i); break; + case TGParameterPan: SetPan (nValue, i); break; + case TGParameterMasterTune: SetMasterTune (nValue, i); break; + case TGParameterCutoff: SetCutoff (nValue, i); break; + case TGParameterResonance: SetResonance (nValue, i); break; + case TGParameterPitchBendRange: setPitchbendRange (nValue, i); break; + case TGParameterPitchBendStep: setPitchbendStep (nValue, i); break; + case TGParameterPortamentoMode: setPortamentoMode (nValue, i); break; + case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, i); break; + case TGParameterPortamentoTime: setPortamentoTime (nValue, i); break; + case TGParameterNoteLimitLow: setNoteLimitLow (nValue, i); break; + case TGParameterNoteLimitHigh: setNoteLimitHigh (nValue, i); break; + case TGParameterNoteShift: setNoteShift (nValue, i); break; + case TGParameterMonoMode: setMonoMode (nValue , i); break; + case TGParameterTGLink: setTGLink(nValue, i); break; + + case TGParameterMWRange: setModController(0, 0, nValue, i); break; + case TGParameterMWPitch: setModController(0, 1, nValue, i); break; + case TGParameterMWAmplitude: setModController(0, 2, nValue, i); break; + case TGParameterMWEGBias: setModController(0, 3, nValue, i); break; + + case TGParameterFCRange: setModController(1, 0, nValue, i); break; + case TGParameterFCPitch: setModController(1, 1, nValue, i); break; + case TGParameterFCAmplitude: setModController(1, 2, nValue, i); break; + case TGParameterFCEGBias: setModController(1, 3, nValue, i); break; + + case TGParameterBCRange: setModController(2, 0, nValue, i); break; + case TGParameterBCPitch: setModController(2, 1, nValue, i); break; + case TGParameterBCAmplitude: setModController(2, 2, nValue, i); break; + case TGParameterBCEGBias: setModController(2, 3, nValue, i); break; + + case TGParameterATRange: setModController(3, 0, nValue, i); break; + case TGParameterATPitch: setModController(3, 1, nValue, i); break; + case TGParameterATAmplitude: setModController(3, 2, nValue, i); break; + case TGParameterATEGBias: setModController(3, 3, nValue, i); break; + + + case TGParameterMIDIChannel: + assert (0 <= nValue && nValue <= 255); + SetMIDIChannel ((uint8_t) nValue, i); + break; + + case TGParameterReverbSend: SetReverbSend (nValue, i); break; + + case TGParameterCompressorEnable: SetCompressorEnable (nValue, i); break; + case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, i); break; + case TGParameterCompressorThresh: SetCompressorThresh (nValue, i); break; + case TGParameterCompressorRatio: SetCompressorRatio (nValue, i); break; + case TGParameterCompressorAttack: SetCompressorAttack (nValue, i); break; + case TGParameterCompressorRelease: SetCompressorRelease (nValue, i); break; + case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, i); break; + + case TGParameterEQLow: SetEQLow (nValue, i); break; + case TGParameterEQMid: SetEQMid (nValue, i); break; + case TGParameterEQHigh: SetEQHigh (nValue, i); break; + case TGParameterEQGain: SetEQGain (nValue, i); break; + case TGParameterEQLowMidFreq: SetEQLowMidFreq (nValue, i); break; + case TGParameterEQMidHighFreq: SetEQMidHighFreq (nValue, i); break; + + default: + assert (0); + break; + } } } @@ -1333,6 +1352,8 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterNoteLimitHigh: return m_nNoteLimitHigh[nTG]; case TGParameterNoteShift: return m_nNoteShift[nTG]; case TGParameterMonoMode: return m_bMonoMode[nTG] ? 1 : 0; + + case TGParameterTGLink: return m_nTGLink[nTG]; case TGParameterMWRange: return getModController(0, 0, nTG); case TGParameterMWPitch: return getModController(0, 1, nTG); @@ -1383,30 +1404,38 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne assert (m_pTG[nTG]); assert (nOP <= 6); - if (nOP < 6) + unsigned nTGLink = m_nTGLink[nTG]; + + for (unsigned i = 0; i < m_nToneGenerators; i++) { - nOP = 5 - nOP; // OPs are in reverse order + if (i != nTG && (!nTGLink || m_nTGLink[i] != nTGLink)) + continue; - if (uchOffset == DEXED_OP_ENABLE) + if (nOP < 6) { - if (uchValue) - { - setOPMask(m_uchOPMask[nTG] | 1 << nOP, nTG); - } - else + nOP = 5 - nOP; // OPs are in reverse order + + if (uchOffset == DEXED_OP_ENABLE) { - setOPMask(m_uchOPMask[nTG] & ~(1 << nOP), nTG); - } + if (uchValue) + { + setOPMask(m_uchOPMask[i] | 1 << nOP, i); + } + else + { + setOPMask(m_uchOPMask[i] & ~(1 << nOP), i); + } - return; - } - } + continue; + } + } - uchOffset += nOP * 21; - assert (uchOffset < 156); + uint8_t offset = uchOffset + nOP * 21; + assert (offset < 156); - m_pTG[nTG]->setVoiceDataElement (uchOffset, uchValue); + m_pTG[i]->setVoiceDataElement (offset, uchValue); + } } uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned nTG) @@ -1763,7 +1792,8 @@ bool CMiniDexed::DoSavePerformance (void) } m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG); m_PerformanceConfig.SetMonoMode (m_bMonoMode[nTG], nTG); - + m_PerformanceConfig.SetTGLink (m_nTGLink[nTG], nTG); + m_PerformanceConfig.SetModulationWheelRange (m_nModulationWheelRange[nTG], nTG); m_PerformanceConfig.SetModulationWheelTarget (m_nModulationWheelTarget[nTG], nTG); m_PerformanceConfig.SetFootControlRange (m_nFootControlRange[nTG], nTG); @@ -1976,6 +2006,16 @@ void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) m_UI.ParameterChanged (); } +void CMiniDexed::setTGLink(uint8_t nTGLink, uint8_t nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nTGLink[nTG]= constrain(nTGLink, 0, 4); + m_UI.ParameterChanged (); +} + void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG) { range = constrain (range, 0, 12); @@ -2472,6 +2512,8 @@ void CMiniDexed::LoadPerformanceParameters(void) } setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); + setTGLink(m_PerformanceConfig.GetTGLink(nTG), nTG); + SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); diff --git a/src/minidexed.h b/src/minidexed.h index bbd30c2ee..44753b6dc 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -125,6 +125,9 @@ class CMiniDexed void SetEQMidHighFreq (unsigned nValue, unsigned nTG); void setMonoMode(uint8_t mono, uint8_t nTG); + + void setTGLink(uint8_t nTGLink, uint8_t nTG); + void setPitchbendRange(uint8_t range, uint8_t nTG); void setPitchbendStep(uint8_t step, uint8_t nTG); void setPortamentoMode(uint8_t mode, uint8_t nTG); @@ -239,6 +242,7 @@ class CMiniDexed TGParameterNoteLimitHigh, TGParameterNoteShift, TGParameterMonoMode, + TGParameterTGLink, TGParameterMWRange, TGParameterMWPitch, @@ -342,6 +346,8 @@ class CMiniDexed unsigned m_nPortamentoGlissando[CConfig::AllToneGenerators]; unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; bool m_bMonoMode[CConfig::AllToneGenerators]; + + unsigned m_nTGLink[CConfig::AllToneGenerators]; unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 16ac81ea8..6fc7bffd6 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -184,7 +184,10 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("MonoMode%u", nTG+1); m_bMonoMode[nTG] = m_Properties.GetNumber (PropertyName, 0) != 0; - + + PropertyName.Format ("TGLink%u", nTG+1); + m_nTGLink[nTG] = m_Properties.GetNumber (PropertyName, 0); + PropertyName.Format ("ModulationWheelRange%u", nTG+1); m_nModulationWheelRange[nTG] = m_Properties.GetNumber (PropertyName, 99); @@ -362,7 +365,10 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("MonoMode%u", nTG+1); m_Properties.SetNumber (PropertyName, m_bMonoMode[nTG] ? 1 : 0); - + + PropertyName.Format ("TGLink%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nTGLink[nTG]); + PropertyName.Format ("ModulationWheelRange%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nModulationWheelRange[nTG]); @@ -947,6 +953,17 @@ bool CPerformanceConfig::GetMonoMode (unsigned nTG) const return m_bMonoMode[nTG]; } +void CPerformanceConfig::SetTGLink (unsigned nTGLink, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nTGLink[nTG] = nTGLink; +} + +unsigned CPerformanceConfig::GetTGLink (unsigned nTG) const +{ + return m_nTGLink[nTG]; +} + void CPerformanceConfig::SetModulationWheelRange (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); diff --git a/src/performanceconfig.h b/src/performanceconfig.h index d899a4561..06d5a3275 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -61,6 +61,7 @@ class CPerformanceConfig // Performance configuration unsigned GetPortamentoGlissando (unsigned nTG) const; // 0 .. 1 unsigned GetPortamentoTime (unsigned nTG) const; // 0 .. 99 bool GetMonoMode (unsigned nTG) const; // 0 .. 1 + unsigned GetTGLink (unsigned nTG) const; // 0 .. 4 unsigned GetModulationWheelRange (unsigned nTG) const; // 0 .. 99 unsigned GetModulationWheelTarget (unsigned nTG) const; // 0 .. 7 @@ -99,6 +100,7 @@ class CPerformanceConfig // Performance configuration void SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG); uint8_t *GetVoiceDataFromTxt (unsigned nTG); void SetMonoMode (bool bOKValue, unsigned nTG); + void SetTGLink (unsigned nTGLink, unsigned nTG); void SetModulationWheelRange (unsigned nValue, unsigned nTG); void SetModulationWheelTarget (unsigned nValue, unsigned nTG); @@ -231,6 +233,7 @@ class CPerformanceConfig // Performance configuration unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; std::string m_nVoiceDataTxt[CConfig::AllToneGenerators]; bool m_bMonoMode[CConfig::AllToneGenerators]; + unsigned m_nTGLink[CConfig::AllToneGenerators]; unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 28a5e3c8e..5e011045c 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -86,6 +86,7 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Portamento", MenuHandler, s_EditPortamentoMenu}, {"Note Limit", MenuHandler, s_EditNoteLimitMenu}, {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, + {"TG-Link", EditTGParameter, 0, CMiniDexed::TGParameterTGLink}, {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, {"EQ", MenuHandler, s_EQMenu}, @@ -325,6 +326,7 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 127, 1, ToMIDINote}, // TGParameterNoteLimitHigh {-24, 24, 1, ToMIDINoteShift}, // TGParameterNoteShift {0, 1, 1, ToPolyMono}, // TGParameterMonoMode + {0, 4, 1, ToTGLinkName}, // TGParameterTGLink {0, 99, 1}, //MW Range {0, 1, 1, ToOnOff}, //MW Pitch {0, 1, 1, ToOnOff}, //MW Amp @@ -1380,6 +1382,12 @@ std::string CUIMenu::ToPolyMono (int nValue, int nWidth) } } +std::string CUIMenu::ToTGLinkName (int nValue, int nWidth) +{ + if (nValue == 0) return "-"; + return std::string{(char)(nValue + 'A' - 1)}; +} + std::string CUIMenu::TodB (int nValue, int nWidth) { return std::to_string (nValue) + " dB"; diff --git a/src/uimenu.h b/src/uimenu.h index 753ae7b9b..aa9fc9703 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -120,6 +120,7 @@ class CUIMenu static std::string ToPortaMode (int nValue, int nWidth); static std::string ToPortaGlissando (int nValue, int nWidth); static std::string ToPolyMono (int nValue, int nWidth); + static std::string ToTGLinkName (int nValue, int nWidth); static std::string TodB (int nValue, int nWidth); static std::string TodBFS (int nValue, int nWidth); static std::string ToMillisec (int nValue, int nWidth); From 48ab20f649655b2e3a5317e17b0b365356442934 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 12 Sep 2025 10:26:56 +0200 Subject: [PATCH 066/136] CUIMenu: TGShortcutHandler switch between menu items Now we have TG-Link so switching between TG-s is not necessary anymore. --- src/uimenu.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 5e011045c..b9ce9a7f3 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1431,22 +1431,41 @@ void CUIMenu::TGShortcutHandler (TMenuEvent Event) assert ( Event == MenuEventPressAndStepDown || Event == MenuEventPressAndStepUp); - if (Event == MenuEventPressAndStepDown) + + if (m_pParentMenu == s_EQMenu || m_pParentMenu == s_EditCompressorMenu) { - nTG--; + if (Event == MenuEventPressAndStepDown) + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepDown); + EventHandler (MenuEventSelect); + } + else + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepUp); + EventHandler (MenuEventSelect); + } } else { - nTG++; - } + if (Event == MenuEventPressAndStepDown) + { + nTG--; + } + else + { + nTG++; + } - if (nTG < m_nToneGenerators) - { - m_nMenuStackSelection[0] = nTG; - m_nMenuStackItem[1] = nTG; - m_nMenuStackParameter[1] = nTG; + if (nTG < m_nToneGenerators) + { + m_nMenuStackSelection[0] = nTG; + m_nMenuStackItem[1] = nTG; + m_nMenuStackParameter[1] = nTG; - EventHandler (MenuEventUpdate); + EventHandler (MenuEventUpdate); + } } } From 29505535ff2731a565689f3fe0894d7a3e31d5ce Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 13 Sep 2025 01:01:36 +0200 Subject: [PATCH 067/136] CUIMenu: add GlobalShortcutHandler --- src/uimenu.cpp | 34 ++++++++++++++++++++++++++++++++++ src/uimenu.h | 1 + 2 files changed, 35 insertions(+) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index b9ce9a7f3..73adaf3c4 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -657,6 +657,11 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) } break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->GlobalShortcutHandler (Event); + return; + default: return; } @@ -708,6 +713,11 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetParameter (Param, nValue); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->GlobalShortcutHandler (Event); + return; + default: return; } @@ -1420,6 +1430,30 @@ std::string CUIMenu::ToHz (int nValue, int nWidth) return buf; } +void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) +{ +#ifdef ARM_ALLOW_MULTI_CORE + if (m_pParentMenu == s_ReverbMenu || + m_pParentMenu == s_MasterEQMenu || + m_pParentMenu == s_LimiterMenu || + m_pCurrentMenu == s_TGMenu) + { + if (Event == MenuEventPressAndStepDown) + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepDown); + EventHandler (MenuEventSelect); + } + else + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepUp); + EventHandler (MenuEventSelect); + } + } +#endif +} + void CUIMenu::TGShortcutHandler (TMenuEvent Event) { assert (m_nCurrentMenuDepth >= 2); diff --git a/src/uimenu.h b/src/uimenu.h index aa9fc9703..e93ae7fab 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -127,6 +127,7 @@ class CUIMenu static std::string ToRatio (int nValue, int nWidth); static std::string ToHz (int nValue, int nWidth); + void GlobalShortcutHandler (TMenuEvent Event); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); From 75d5802de1933342ac690086bcf03f4386a2cec1 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 12 Sep 2025 11:53:14 +0200 Subject: [PATCH 068/136] CUIMenu: put link names after TG names --- src/uimenu.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 73adaf3c4..53042aced 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -669,10 +669,30 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) if (pUIMenu->m_pCurrentMenu) // if this is another menu? { bool bIsMainMenu = pUIMenu->m_pCurrentMenu == s_MainMenu; + bool bIsTGMenu = pUIMenu->m_pCurrentMenu == s_TGMenu; + + std::string menuName = pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name; + + if (bIsTGMenu) + { + int nTG = pUIMenu->m_nCurrentParameter; + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); + if (nTGLink) menuName += ToTGLinkName(nTGLink, 0); + } + + std::string selectionName = pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name; + + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem == s_TGMenu) + { + int nTG = pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter; + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); + if (nTGLink) selectionName += ToTGLinkName(nTGLink, 0); + } + pUIMenu->m_pUI->DisplayWrite ( - pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + menuName.c_str(), "", - pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + selectionName.c_str(), pUIMenu->m_nCurrentSelection > 0 || bIsMainMenu, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name || bIsMainMenu); } @@ -741,6 +761,7 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -771,6 +792,7 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) std::string TG ("TG"); TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = std::to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetBankName (nValue); @@ -876,6 +898,7 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -912,6 +935,12 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) std::string TG ("TG"); TG += std::to_string (nTG+1); + if (nTGLink && + Param != CMiniDexed::TGParameterTGLink && + Param != CMiniDexed::TGParameterPan && + Param != CMiniDexed::TGParameterMasterTune + ) + TG += ToTGLinkName(nTGLink, 0); std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), @@ -932,6 +961,7 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -973,6 +1003,7 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me std::string TG ("TG"); TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), @@ -992,6 +1023,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_VoiceParameter[nParam]; int nValue = pUIMenu->m_pMiniDexed->GetVoiceParameter (nParam, CMiniDexed::NoOP, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -1028,6 +1060,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) std::string TG ("TG"); TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); @@ -2274,6 +2307,7 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -2309,6 +2343,7 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) std::string TG ("TG"); TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), From e9935f0f273af949fe5721997bc8e5559ecf62c0 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 13 Sep 2025 10:38:32 +0200 Subject: [PATCH 069/136] README: add tg-link and noiseless performance --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 622e1163f..8995b77f6 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with the following additional features: - [x] Configurable default screen -- [x] Noiseless volume change +- [x] Noiseless performance and volume change - [x] Configurable TG compressors - [x] Limiter - [x] 3-band EQ (per TG and Master) +- [x] TG-Link - [ ] Two Effect Send with Chrous, Delay, Reverb - [ ] 8 channel mixer (Rpi4+) - [ ] Multiple parts (RPi4+) From ece47c08d8035acb347ea137acedf0a6f8544fa1 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 16 Sep 2025 23:12:00 +0200 Subject: [PATCH 070/136] CUIMenu: save current selection in GlobalShortcutHandler --- src/uimenu.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 53042aced..5111aaf72 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1471,6 +1471,10 @@ void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) m_pParentMenu == s_LimiterMenu || m_pCurrentMenu == s_TGMenu) { + bool bSaveCurrentSelection = m_pCurrentMenu == s_TGMenu; + + unsigned nSavedSelection = m_nCurrentSelection; + if (Event == MenuEventPressAndStepDown) { EventHandler (MenuEventBack); @@ -1483,6 +1487,12 @@ void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) EventHandler (MenuEventStepUp); EventHandler (MenuEventSelect); } + + if (bSaveCurrentSelection) + { + m_nCurrentSelection = nSavedSelection; + EventHandler (MenuEventUpdate); + } } #endif } From f79848579645b0a3012510c53ee57ce569c4565a Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 17 Sep 2025 18:27:09 +0200 Subject: [PATCH 071/136] rename Limiter to MasterCompressor --- README.md | 2 +- src/minidexed.cpp | 104 +++++++++++++++++++------------------- src/minidexed.h | 18 +++---- src/performanceconfig.cpp | 84 +++++++++++++++--------------- src/performanceconfig.h | 42 +++++++-------- src/uimenu.cpp | 34 ++++++------- src/uimenu.h | 2 +- 7 files changed, 143 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 8995b77f6..6353b001a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with th - [x] Configurable default screen - [x] Noiseless performance and volume change - [x] Configurable TG compressors -- [x] Limiter +- [x] Master Compressor - [x] 3-band EQ (per TG and Master) - [x] TG-Link - [ ] Two Effect Send with Chrous, Delay, Reverb diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 51f08dc8d..529719816 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -70,7 +70,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, tg_mixer(nullptr), reverb_send_mixer(nullptr), m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, - m_Limiter {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, + m_MasterCompressor {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), m_pNetDevice(nullptr), m_WLAN(nullptr), @@ -288,13 +288,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetParameter (ParameterReverbLevel, 99); // END setup reverb - SetParameter (ParameterLimiterEnable, 1); - SetParameter (ParameterLimiterPreGain, 0); - SetParameter (ParameterLimiterThresh, -3); - SetParameter (ParameterLimiterRatio, 20); - SetParameter (ParameterLimiterAttack, 5); - SetParameter (ParameterLimiterRelease, 5); - SetParameter (ParameterLimiterHPFilterEnable, 0); + SetParameter (ParameterMasterCompressorEnable, 1); + SetParameter (ParameterMasterCompressorPreGain, 0); + SetParameter (ParameterMasterCompressorThresh, -3); + SetParameter (ParameterMasterCompressorRatio, 20); + SetParameter (ParameterMasterCompressorAttack, 5); + SetParameter (ParameterMasterCompressorRelease, 5); + SetParameter (ParameterMasterCompressorHPFilterEnable, 0); SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); @@ -1121,54 +1121,54 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_UI.ParameterChanged (); break; - case ParameterLimiterEnable: + case ParameterMasterCompressorEnable: break; - case ParameterLimiterPreGain: + case ParameterMasterCompressorPreGain: nValue=constrain(nValue,-20,20); - m_LimiterSpinLock.Acquire (); + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setPreGain_dB(nValue); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].setPreGain_dB(nValue); + m_MasterCompressorSpinLock.Release (); break; - case ParameterLimiterThresh: + case ParameterMasterCompressorThresh: nValue=constrain(nValue,-60,0); - m_LimiterSpinLock.Acquire (); + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setThresh_dBFS(nValue); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].setThresh_dBFS(nValue); + m_MasterCompressorSpinLock.Release (); break; - case ParameterLimiterRatio: + case ParameterMasterCompressorRatio: nValue=constrain(nValue,1,20); - m_LimiterSpinLock.Acquire (); + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setCompressionRatio(nValue); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].setCompressionRatio(nValue); + m_MasterCompressorSpinLock.Release (); break; - case ParameterLimiterAttack: + case ParameterMasterCompressorAttack: nValue=constrain(nValue,0,1000); - m_LimiterSpinLock.Acquire (); + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_MasterCompressorSpinLock.Release (); break; - case ParameterLimiterRelease: + case ParameterMasterCompressorRelease: nValue=constrain(nValue,0,1000); - m_LimiterSpinLock.Acquire (); + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_MasterCompressorSpinLock.Release (); break; - case ParameterLimiterHPFilterEnable: - m_LimiterSpinLock.Acquire (); + case ParameterMasterCompressorHPFilterEnable: + m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_Limiter[i].enableHPFilter(nValue); - m_LimiterSpinLock.Release (); + m_MasterCompressor[i].enableHPFilter(nValue); + m_MasterCompressorSpinLock.Release (); break; case ParameterMasterEQLow: @@ -1655,12 +1655,12 @@ void CMiniDexed::ProcessSound (void) m_MasterEQ[1].process(SampleBuffer[1], nFrames); m_EQSpinLock.Release(); - if (m_nParameter[ParameterLimiterEnable]) + if (m_nParameter[ParameterMasterCompressorEnable]) { - m_LimiterSpinLock.Acquire (); - m_Limiter[0].doCompression (SampleBuffer[0], nFrames); - m_Limiter[1].doCompression (SampleBuffer[1], nFrames); - m_LimiterSpinLock.Release (); + m_MasterCompressorSpinLock.Acquire (); + m_MasterCompressor[0].doCompression (SampleBuffer[0], nFrames); + m_MasterCompressor[1].doCompression (SampleBuffer[1], nFrames); + m_MasterCompressorSpinLock.Release (); } // swap stereo channels if needed prior to writing back out @@ -1836,13 +1836,13 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetMasterEQLowMidFreq (m_nParameter[ParameterMasterEQLowMidFreq]); m_PerformanceConfig.SetMasterEQMidHighFreq (m_nParameter[ParameterMasterEQMidHighFreq]); - m_PerformanceConfig.SetLimiterEnable (m_nParameter[ParameterLimiterEnable]); - m_PerformanceConfig.SetLimiterPreGain (m_nParameter[ParameterLimiterPreGain]); - m_PerformanceConfig.SetLimiterThresh (m_nParameter[ParameterLimiterThresh]); - m_PerformanceConfig.SetLimiterRatio (m_nParameter[ParameterLimiterRatio]); - m_PerformanceConfig.SetLimiterAttack (m_nParameter[ParameterLimiterAttack]); - m_PerformanceConfig.SetLimiterRelease (m_nParameter[ParameterLimiterRelease]); - m_PerformanceConfig.SetLimiterHPFilterEnable (m_nParameter[ParameterLimiterHPFilterEnable]); + m_PerformanceConfig.SetMasterCompressorEnable (m_nParameter[ParameterMasterCompressorEnable]); + m_PerformanceConfig.SetMasterCompressorPreGain (m_nParameter[ParameterMasterCompressorPreGain]); + m_PerformanceConfig.SetMasterCompressorThresh (m_nParameter[ParameterMasterCompressorThresh]); + m_PerformanceConfig.SetMasterCompressorRatio (m_nParameter[ParameterMasterCompressorRatio]); + m_PerformanceConfig.SetMasterCompressorAttack (m_nParameter[ParameterMasterCompressorAttack]); + m_PerformanceConfig.SetMasterCompressorRelease (m_nParameter[ParameterMasterCompressorRelease]); + m_PerformanceConfig.SetMasterCompressorHPFilterEnable (m_nParameter[ParameterMasterCompressorHPFilterEnable]); if(m_bSaveAsDeault) { @@ -2557,13 +2557,13 @@ void CMiniDexed::LoadPerformanceParameters(void) SetParameter (ParameterMasterEQLowMidFreq, m_PerformanceConfig.GetMasterEQLowMidFreq ()); SetParameter (ParameterMasterEQMidHighFreq, m_PerformanceConfig.GetMasterEQMidHighFreq ()); - SetParameter (ParameterLimiterEnable, m_PerformanceConfig.GetLimiterEnable ()); - SetParameter (ParameterLimiterPreGain, m_PerformanceConfig.GetLimiterPreGain ()); - SetParameter (ParameterLimiterThresh, m_PerformanceConfig.GetLimiterThresh ()); - SetParameter (ParameterLimiterRatio, m_PerformanceConfig.GetLimiterRatio ()); - SetParameter (ParameterLimiterAttack, m_PerformanceConfig.GetLimiterAttack ()); - SetParameter (ParameterLimiterRelease, m_PerformanceConfig.GetLimiterRelease ()); - SetParameter (ParameterLimiterHPFilterEnable, m_PerformanceConfig.GetLimiterHPFilterEnable ()); + SetParameter (ParameterMasterCompressorEnable, m_PerformanceConfig.GetMasterCompressorEnable ()); + SetParameter (ParameterMasterCompressorPreGain, m_PerformanceConfig.GetMasterCompressorPreGain ()); + SetParameter (ParameterMasterCompressorThresh, m_PerformanceConfig.GetMasterCompressorThresh ()); + SetParameter (ParameterMasterCompressorRatio, m_PerformanceConfig.GetMasterCompressorRatio ()); + SetParameter (ParameterMasterCompressorAttack, m_PerformanceConfig.GetMasterCompressorAttack ()); + SetParameter (ParameterMasterCompressorRelease, m_PerformanceConfig.GetMasterCompressorRelease ()); + SetParameter (ParameterMasterCompressorHPFilterEnable, m_PerformanceConfig.GetMasterCompressorHPFilterEnable ()); m_UI.DisplayChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index 44753b6dc..769128464 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -194,13 +194,13 @@ class CMiniDexed ParameterPerformanceSelectChannel, ParameterPerformanceBank, ParameterMasterVolume, - ParameterLimiterEnable, - ParameterLimiterPreGain, - ParameterLimiterThresh, - ParameterLimiterRatio, - ParameterLimiterAttack, - ParameterLimiterRelease, - ParameterLimiterHPFilterEnable, + ParameterMasterCompressorEnable, + ParameterMasterCompressorPreGain, + ParameterMasterCompressorThresh, + ParameterMasterCompressorRatio, + ParameterMasterCompressorAttack, + ParameterMasterCompressorRelease, + ParameterMasterCompressorHPFilterEnable, ParameterMasterEQLow, ParameterMasterEQMid, ParameterMasterEQHigh, @@ -419,8 +419,8 @@ class CMiniDexed AudioEffect3BandEQ m_MasterEQ[2]; CSpinLock m_EQSpinLock; - Compressor m_Limiter[2]; - CSpinLock m_LimiterSpinLock; + Compressor m_MasterCompressor[2]; + CSpinLock m_MasterCompressorSpinLock; // Network CNetSubSystem* m_pNet; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 6fc7bffd6..4b99e1476 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -267,13 +267,13 @@ bool CPerformanceConfig::Load (void) m_nMasterEQLowMidFreq = m_Properties.GetNumber ("MasterEQLowMidFreq", 24); m_nMasterEQMidHighFreq = m_Properties.GetNumber ("MasterEQMidHighFreq", 44); - m_bLimiterEnable = m_Properties.GetNumber ("LimiterEnable", 1); - m_nLimiterPreGain = m_Properties.GetSignedNumber ("LimiterPreGain", 0); - m_nLimiterThresh = m_Properties.GetSignedNumber ("LimiterThresh", -3); - m_nLimiterRatio = m_Properties.GetNumber ("LimiterRatio", 20); - m_nLimiterAttack = m_Properties.GetNumber ("LimiterAttack", 5); - m_nLimiterRelease = m_Properties.GetNumber ("LimiterRelease", 5); - m_bLimiterHPFilterEnable = m_Properties.GetNumber ("LimiterHPFilterEnable", 0); + m_bMasterCompressorEnable = m_Properties.GetNumber ("MasterCompressorEnable", 1); + m_nMasterCompressorPreGain = m_Properties.GetSignedNumber ("MasterCompressorPreGain", 0); + m_nMasterCompressorThresh = m_Properties.GetSignedNumber ("MasterCompressorThresh", -3); + m_nMasterCompressorRatio = m_Properties.GetNumber ("MasterCompressorRatio", 20); + m_nMasterCompressorAttack = m_Properties.GetNumber ("MasterCompressorAttack", 5); + m_nMasterCompressorRelease = m_Properties.GetNumber ("MasterCompressorRelease", 5); + m_bMasterCompressorHPFilterEnable = m_Properties.GetNumber ("MasterCompressorHPFilterEnable", 0); // Compatibility if (m_Properties.IsSet ("CompressorEnable") && m_Properties.GetNumber ("CompressorEnable", 1) == 0) @@ -449,13 +449,13 @@ bool CPerformanceConfig::Save (void) m_Properties.SetNumber ("MasterEQLowMidFreq", m_nMasterEQLowMidFreq); m_Properties.SetNumber ("MasterEQMidHighFreq", m_nMasterEQMidHighFreq); - m_Properties.SetNumber ("LimiterEnable", m_bLimiterEnable); - m_Properties.SetSignedNumber ("LimiterPreGain", m_nLimiterPreGain); - m_Properties.SetSignedNumber ("LimiterThresh", m_nLimiterThresh); - m_Properties.SetNumber ("LimiterRatio", m_nLimiterRatio); - m_Properties.SetNumber ("LimiterAttack", m_nLimiterAttack); - m_Properties.SetNumber ("LimiterRelease", m_nLimiterRelease); - m_Properties.SetNumber ("LimiterHPFilterEnable", m_bLimiterHPFilterEnable); + m_Properties.SetNumber ("MasterCompressorEnable", m_bMasterCompressorEnable); + m_Properties.SetSignedNumber ("MasterCompressorPreGain", m_nMasterCompressorPreGain); + m_Properties.SetSignedNumber ("MasterCompressorThresh", m_nMasterCompressorThresh); + m_Properties.SetNumber ("MasterCompressorRatio", m_nMasterCompressorRatio); + m_Properties.SetNumber ("MasterCompressorAttack", m_nMasterCompressorAttack); + m_Properties.SetNumber ("MasterCompressorRelease", m_nMasterCompressorRelease); + m_Properties.SetNumber ("MasterCompressorHPFilterEnable", m_bMasterCompressorHPFilterEnable); return m_Properties.Save (); } @@ -807,74 +807,74 @@ void CPerformanceConfig::SetMasterEQMidHighFreq (unsigned nValue) m_nMasterEQMidHighFreq = nValue; } -bool CPerformanceConfig::GetLimiterEnable () const +bool CPerformanceConfig::GetMasterCompressorEnable () const { - return m_bLimiterEnable; + return m_bMasterCompressorEnable; } -int CPerformanceConfig::GetLimiterPreGain () const +int CPerformanceConfig::GetMasterCompressorPreGain () const { - return m_nLimiterPreGain; + return m_nMasterCompressorPreGain; } -int CPerformanceConfig::GetLimiterThresh () const +int CPerformanceConfig::GetMasterCompressorThresh () const { - return m_nLimiterThresh; + return m_nMasterCompressorThresh; } -unsigned CPerformanceConfig::GetLimiterRatio () const +unsigned CPerformanceConfig::GetMasterCompressorRatio () const { - return m_nLimiterRatio; + return m_nMasterCompressorRatio; } -unsigned CPerformanceConfig::GetLimiterAttack () const +unsigned CPerformanceConfig::GetMasterCompressorAttack () const { - return m_nLimiterAttack; + return m_nMasterCompressorAttack; } -unsigned CPerformanceConfig::GetLimiterRelease () const +unsigned CPerformanceConfig::GetMasterCompressorRelease () const { - return m_nLimiterRelease; + return m_nMasterCompressorRelease; } -bool CPerformanceConfig::GetLimiterHPFilterEnable () const +bool CPerformanceConfig::GetMasterCompressorHPFilterEnable () const { - return m_bLimiterHPFilterEnable; + return m_bMasterCompressorHPFilterEnable; } -void CPerformanceConfig::SetLimiterEnable (bool nValue) +void CPerformanceConfig::SetMasterCompressorEnable (bool nValue) { - m_bLimiterEnable = nValue; + m_bMasterCompressorEnable = nValue; } -void CPerformanceConfig::SetLimiterPreGain (int nValue) +void CPerformanceConfig::SetMasterCompressorPreGain (int nValue) { - m_nLimiterPreGain= nValue; + m_nMasterCompressorPreGain= nValue; } -void CPerformanceConfig::SetLimiterThresh (int nValue) +void CPerformanceConfig::SetMasterCompressorThresh (int nValue) { - m_nLimiterThresh = nValue; + m_nMasterCompressorThresh = nValue; } -void CPerformanceConfig::SetLimiterRatio (unsigned nValue) +void CPerformanceConfig::SetMasterCompressorRatio (unsigned nValue) { - m_nLimiterRatio = nValue; + m_nMasterCompressorRatio = nValue; } -void CPerformanceConfig::SetLimiterAttack (unsigned nValue) +void CPerformanceConfig::SetMasterCompressorAttack (unsigned nValue) { - m_nLimiterAttack = nValue; + m_nMasterCompressorAttack = nValue; } -void CPerformanceConfig::SetLimiterRelease (unsigned nValue) +void CPerformanceConfig::SetMasterCompressorRelease (unsigned nValue) { - m_nLimiterRelease = nValue; + m_nMasterCompressorRelease = nValue; } -void CPerformanceConfig::SetLimiterHPFilterEnable (bool nValue) +void CPerformanceConfig::SetMasterCompressorHPFilterEnable (bool nValue) { - m_bLimiterHPFilterEnable = nValue; + m_bMasterCompressorHPFilterEnable = nValue; } // Pitch bender and portamento: diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 06d5a3275..75d9de4cd 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -164,21 +164,21 @@ class CPerformanceConfig // Performance configuration void SetMasterEQLowMidFreq (unsigned nValue); void SetMasterEQMidHighFreq (unsigned nValue); - bool GetLimiterEnable () const; - int GetLimiterPreGain () const; - int GetLimiterThresh () const; - unsigned GetLimiterRatio () const; - unsigned GetLimiterAttack () const; - unsigned GetLimiterRelease () const; - bool GetLimiterHPFilterEnable () const; + bool GetMasterCompressorEnable () const; + int GetMasterCompressorPreGain () const; + int GetMasterCompressorThresh () const; + unsigned GetMasterCompressorRatio () const; + unsigned GetMasterCompressorAttack () const; + unsigned GetMasterCompressorRelease () const; + bool GetMasterCompressorHPFilterEnable () const; - void SetLimiterEnable (bool nValue); - void SetLimiterPreGain (int nValue); - void SetLimiterThresh (int nValue); - void SetLimiterRatio (unsigned nValue); - void SetLimiterAttack (unsigned nValue); - void SetLimiterRelease (unsigned nValue); - void SetLimiterHPFilterEnable (bool nValue); + void SetMasterCompressorEnable (bool nValue); + void SetMasterCompressorPreGain (int nValue); + void SetMasterCompressorThresh (int nValue); + void SetMasterCompressorRatio (unsigned nValue); + void SetMasterCompressorAttack (unsigned nValue); + void SetMasterCompressorRelease (unsigned nValue); + void SetMasterCompressorHPFilterEnable (bool nValue); bool VoiceDataFilled(unsigned nTG); bool ListPerformances(); @@ -287,13 +287,13 @@ class CPerformanceConfig // Performance configuration unsigned m_nMasterEQLowMidFreq; unsigned m_nMasterEQMidHighFreq; - bool m_bLimiterEnable; - int m_nLimiterPreGain; - int m_nLimiterThresh; - unsigned m_nLimiterRatio; - unsigned m_nLimiterAttack; - unsigned m_nLimiterRelease; - bool m_bLimiterHPFilterEnable; + bool m_bMasterCompressorEnable; + int m_nMasterCompressorPreGain; + int m_nMasterCompressorThresh; + unsigned m_nMasterCompressorRatio; + unsigned m_nMasterCompressorAttack; + unsigned m_nMasterCompressorRelease; + bool m_bMasterCompressorHPFilterEnable; }; #endif diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 5111aaf72..59a9adba7 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -112,7 +112,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = #ifdef ARM_ALLOW_MULTI_CORE {"Reverb", MenuHandler, s_ReverbMenu}, {"EQ", MenuHandler, s_MasterEQMenu}, - {"Limiter", MenuHandler, s_LimiterMenu}, + {"Compressor", MenuHandler, s_MasterCompressorMenu}, #endif {0} }; @@ -194,15 +194,15 @@ const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = {0} }; -const CUIMenu::TMenuItem CUIMenu::s_LimiterMenu[] = +const CUIMenu::TMenuItem CUIMenu::s_MasterCompressorMenu[] = { - {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterEnable}, - {"Pre Gain", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterPreGain}, - {"Threshold", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterThresh}, - {"Ratio", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRatio}, - {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterAttack}, - {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterRelease}, - {"HPFilter", EditGlobalParameter, 0, CMiniDexed::ParameterLimiterHPFilterEnable}, + {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorEnable}, + {"Pre Gain", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorPreGain}, + {"Threshold", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorThresh}, + {"Ratio", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorRatio}, + {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorAttack}, + {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorRelease}, + {"HPFilter", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorHPFilterEnable}, {0} }; @@ -288,13 +288,13 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank {0, 127, 8, ToVolume}, // ParameterMasterVolume - {0, 1, 1, ToOnOff}, // ParameterLimiterEnable - {-20, 20, 1, TodB}, // ParameterLimiterPreGain - {-60, 0, 1, TodBFS}, // ParameterLimiterThresh - {1, 20, 1, ToRatio}, // ParameterLimiterRatio - {0, 1000, 5, ToMillisec}, // ParameterLimiterAttack - {0, 1000, 5, ToMillisec}, // ParameterLimiterRelease - {0, 1, 1, ToOnOff}, // ParameterLimiterHPFilterEnable + {0, 1, 1, ToOnOff}, // ParameterMasterCompressorEnable + {-20, 20, 1, TodB}, // ParameterMasterCompressorPreGain + {-60, 0, 1, TodBFS}, // ParameterMasterCompressorThresh + {1, 20, 1, ToRatio}, // ParameterMasterCompressorRatio + {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorAttack + {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorRelease + {0, 1, 1, ToOnOff}, // ParameterMasterCompressorHPFilterEnable {-24, 24, 1, TodB}, // ParameterMasterEQLow {-24, 24, 1, TodB}, // ParameterMasterEQMid {-24, 24, 1, TodB}, // ParameterMasterEQHigh @@ -1468,7 +1468,7 @@ void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) #ifdef ARM_ALLOW_MULTI_CORE if (m_pParentMenu == s_ReverbMenu || m_pParentMenu == s_MasterEQMenu || - m_pParentMenu == s_LimiterMenu || + m_pParentMenu == s_MasterCompressorMenu || m_pCurrentMenu == s_TGMenu) { bool bSaveCurrentSelection = m_pCurrentMenu == s_TGMenu; diff --git a/src/uimenu.h b/src/uimenu.h index e93ae7fab..3b1469672 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -169,7 +169,7 @@ class CUIMenu static const TMenuItem s_EQMenu[]; static const TMenuItem s_ReverbMenu[]; static const TMenuItem s_MasterEQMenu[]; - static const TMenuItem s_LimiterMenu[]; + static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; From c2e5918658be43068a2dcdfc6fad0b6bf3757342 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 4 Nov 2025 01:29:59 +0100 Subject: [PATCH 072/136] update circle-stdlib to v17.2 --- circle-stdlib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle-stdlib b/circle-stdlib index a957cd7d9..83efe0b46 160000 --- a/circle-stdlib +++ b/circle-stdlib @@ -1 +1 @@ -Subproject commit a957cd7d9c5d68ada943bb776ed8da71fea25ef1 +Subproject commit 83efe0b460555910878476fdcdbccbc185c92408 From 3d46e5a3ba03bb9e3471c6feb9393587350b5196 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 15 Aug 2025 23:45:40 +0200 Subject: [PATCH 073/136] sendfx --- src/config.h | 3 + src/effect.h | 29 ++++ src/midi.h | 3 +- src/mididevice.cpp | 12 +- src/minidexed.cpp | 331 +++++++++++++++++++++++++------------- src/minidexed.h | 24 ++- src/performanceconfig.cpp | 156 ++++++++---------- src/performanceconfig.h | 32 +--- src/uimenu.cpp | 103 ++++++++++-- src/uimenu.h | 3 + 10 files changed, 432 insertions(+), 264 deletions(-) create mode 100644 src/effect.h diff --git a/src/config.h b/src/config.h index ce89d7d91..b56a54b05 100644 --- a/src/config.h +++ b/src/config.h @@ -43,6 +43,7 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = 1; static const unsigned AllToneGenerators = 1; static const unsigned DefToneGenerators = AllToneGenerators; + static const unsigned FXChains = 0; #else #if (RASPPI==4 || RASPPI==5) // Pi 4 and 5 quad core @@ -54,6 +55,7 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = TGsCore1 + TGsCore1Opt + 2*TGsCore23 + 2*TGsCore23Opt; static const unsigned DefToneGenerators = MinToneGenerators; + static const unsigned FXChains = 2; #else // Pi 2 or 3 quad core static const unsigned TGsCore1 = 2; // process 2 TGs on core 1 @@ -63,6 +65,7 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = MinToneGenerators; static const unsigned DefToneGenerators = AllToneGenerators; + static const unsigned FXChains = 2; #endif #endif diff --git a/src/effect.h b/src/effect.h new file mode 100644 index 000000000..4760f107d --- /dev/null +++ b/src/effect.h @@ -0,0 +1,29 @@ +class FX +{ +public: + enum TFXParameter + { + FXParameterReverbEnable, + FXParameterReverbSize, + FXParameterReverbHighDamp, + FXParameterReverbLowDamp, + FXParameterReverbLowPass, + FXParameterReverbDiffusion, + FXParameterReverbLevel, + FXParameterUnknown, + }; + + typedef std::string TToString (int nValue, int nWidth); + + struct FXParameterType + { + int Minimum; + int Maximum; + int Default; + int Increment; + const char *Name; + TToString *ToString; + }; + + static FX::FXParameterType s_FXParameter[]; +}; diff --git a/src/midi.h b/src/midi.h index 4155616f1..7794c7952 100644 --- a/src/midi.h +++ b/src/midi.h @@ -41,7 +41,8 @@ #define MIDI_CC_HOLD2 69 #define MIDI_CC_RESONANCE 71 #define MIDI_CC_FREQUENCY_CUTOFF 74 -#define MIDI_CC_REVERB_LEVEL 91 +#define MIDI_CC_EFFECT1_SEND 91 +#define MIDI_CC_EFFECT2_SEND 92 #define MIDI_CC_DETUNE_LEVEL 94 #define MIDI_CC_ALL_SOUND_OFF 120 #define MIDI_CC_ALL_NOTES_OFF 123 diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 09e2bf232..d2da26ef3 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -571,11 +571,15 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign case MIDI_CC_FREQUENCY_CUTOFF: m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG); break; - - case MIDI_CC_REVERB_LEVEL: - m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG); + + case MIDI_CC_EFFECT1_SEND: + m_pSynthesizer->SetFXSend (maplong (pMessage[2], 0, 127, 0, 99), nTG, 0); break; - + + case MIDI_CC_EFFECT2_SEND: + m_pSynthesizer->SetFXSend (maplong (pMessage[2], 0, 127, 0, 99), nTG, 1); + break; + case MIDI_CC_DETUNE_LEVEL: if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) break; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 529719816..680eb13b7 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -66,9 +66,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), - reverb(nullptr), - tg_mixer(nullptr), - reverb_send_mixer(nullptr), + reverb {}, + tg_mixer {}, + sendfx_mixer {}, m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_MasterCompressor {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), @@ -130,7 +130,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nAftertouchRange[i]=99; m_nAftertouchTarget[i]=0; - m_nReverbSend[i] = 0; + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + m_nFXSend[i][nFX] = 0; + } m_bCompressorEnable[i] = 1; m_nCompressorPreGain[i] = 0; @@ -266,9 +269,18 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); // END setup tgmixer - // BEGIN setup reverb - reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); - reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); + for (unsigned nFX = 0; nFX < CConfig::FXChains; nFX++) + { + sendfx_mixer[nFX] = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); + reverb[nFX] = new AudioEffectPlateReverb(pConfig->GetSampleRate()); + + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + SetFXParameter (FX::TFXParameter(nParam), p.Default, nFX); + } + } + // END setup reverb SetParameter (ParameterMasterEQLow, 0); SetParameter (ParameterMasterEQMid, 0); @@ -279,15 +291,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); - SetParameter (ParameterReverbEnable, 1); - SetParameter (ParameterReverbSize, 70); - SetParameter (ParameterReverbHighDamp, 50); - SetParameter (ParameterReverbLowDamp, 50); - SetParameter (ParameterReverbLowPass, 30); - SetParameter (ParameterReverbDiffusion, 65); - SetParameter (ParameterReverbLevel, 99); - // END setup reverb - SetParameter (ParameterMasterCompressorEnable, 1); SetParameter (ParameterMasterCompressorPreGain, 0); SetParameter (ParameterMasterCompressorThresh, -3); @@ -363,8 +366,12 @@ bool CMiniDexed::Initialize (void) tg_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); tg_mixer->gain(i,1.0f); - reverb_send_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); - reverb_send_mixer->gain(i,mapfloat(m_nReverbSend[i],0,99,0.0f,1.0f)); + + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + sendfx_mixer[nFX]->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); + sendfx_mixer[nFX]->gain(i,mapfloat(m_nFXSend[i][nFX],0,99,0.0f,1.0f)); + } } m_PerformanceConfig.Init(m_nToneGenerators); @@ -490,7 +497,10 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) DoSetNewPerformance (); - reverb->reset(); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + reverb[nFX]->reset(); + } if (m_nSetNewPerformanceID == GetActualPerformanceID()) { @@ -782,21 +792,25 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) m_nPan[nTG] = nPan; tg_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); - reverb_send_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); + + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + sendfx_mixer[nFX]->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); + } m_UI.ParameterChanged (); } -void CMiniDexed::SetReverbSend (unsigned nReverbSend, unsigned nTG) +void CMiniDexed::SetFXSend (unsigned nFXSend, unsigned nTG, unsigned nFX) { - nReverbSend=constrain((int)nReverbSend,0,99); + nFXSend=constrain((int)nFXSend,0,99); assert (nTG < CConfig::AllToneGenerators); + assert (nFX < CConfig::FXChains); if (nTG >= m_nToneGenerators) return; // Not an active TG - m_nReverbSend[nTG] = nReverbSend; - - reverb_send_mixer->gain(nTG,mapfloat(nReverbSend,0,99,0.0f,1.0f)); + m_nFXSend[nTG][nFX] = nFXSend; + sendfx_mixer[nFX]->gain(nTG,mapfloat(nFXSend,0,99,0.0f,1.0f)); m_UI.ParameterChanged (); } @@ -1052,61 +1066,10 @@ void CMiniDexed::ControllersRefresh (unsigned nTG) void CMiniDexed::SetParameter (TParameter Parameter, int nValue) { - assert (reverb); - assert (Parameter < ParameterUnknown); switch (Parameter) { - case ParameterReverbEnable: - nValue=constrain((int)nValue,0,1); - m_ReverbSpinLock.Acquire (); - reverb->set_bypass (!nValue); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbSize: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->size (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbHighDamp: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->hidamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbLowDamp: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->lodamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbLowPass: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->lowpass (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbDiffusion: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->diffusion (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - - case ParameterReverbLevel: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->level (nValue / 99.0f); - m_ReverbSpinLock.Release (); - break; - case ParameterPerformanceSelectChannel: // Nothing more to do break; @@ -1233,9 +1196,78 @@ int CMiniDexed::GetParameter (TParameter Parameter) return m_nParameter[Parameter]; } +void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX) +{ + assert (nFX < CConfig::FXChains); + assert (Parameter < FX::FXParameterUnknown); + + const FX::FXParameterType &p = FX::s_FXParameter[Parameter]; + nValue = constrain((int)nValue, p.Minimum, p.Maximum); + + m_nFXParameter[nFX][Parameter] = nValue; + + switch (Parameter) + { + case FX::FXParameterReverbEnable: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->set_bypass (!nValue); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbSize: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->size (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbHighDamp: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->hidamp (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbLowDamp: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->lodamp (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbLowPass: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->lowpass (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbDiffusion: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->diffusion (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + case FX::FXParameterReverbLevel: + m_ReverbSpinLock.Acquire (); + reverb[nFX]->level (nValue / 99.0f); + m_ReverbSpinLock.Release (); + break; + + default: + assert (0); + break; + } +} + +int CMiniDexed::GetFXParameter (FX::TFXParameter Parameter, unsigned nFX) +{ + assert (nFX < CConfig::FXChains); + assert (Parameter < FX::FXParameterUnknown); + + return m_nFXParameter[nFX][Parameter]; +} + void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG unsigned nTGLink = m_nTGLink[nTG]; @@ -1302,7 +1334,8 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT SetMIDIChannel ((uint8_t) nValue, i); break; - case TGParameterReverbSend: SetReverbSend (nValue, i); break; + case TGParameterFX1Send: SetFXSend (nValue, i, 0); break; + case TGParameterFX2Send: SetFXSend (nValue, i, 1); break; case TGParameterCompressorEnable: SetCompressorEnable (nValue, i); break; case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, i); break; @@ -1342,7 +1375,8 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCutoff: return m_nCutoff[nTG]; case TGParameterResonance: return m_nResonance[nTG]; case TGParameterMIDIChannel: return m_nMIDIChannel[nTG]; - case TGParameterReverbSend: return m_nReverbSend[nTG]; + case TGParameterFX1Send: return m_nFXSend[nTG][0]; + case TGParameterFX2Send: return m_nFXSend[nTG][1]; case TGParameterPitchBendRange: return m_nPitchBendRange[nTG]; case TGParameterPitchBendStep: return m_nPitchBendStep[nTG]; case TGParameterPortamentoMode: return m_nPortamentoMode[nTG]; @@ -1620,33 +1654,33 @@ void CMiniDexed::ProcessSound (void) } // END TG mixing - // BEGIN adding reverb - if (m_nParameter[ParameterReverbEnable]) - { - float32_t ReverbBuffer[2][nFrames]; - - float32_t *ReverbSendBuffer[2]; - reverb_send_mixer->getBuffers(ReverbSendBuffer); - - reverb_send_mixer->zeroFill(); + // BEGIN adding sendFX + float32_t *FXSendBuffer[2]; - for (uint8_t i = 0; i < m_nToneGenerators; i++) + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + if (m_nFXParameter[nFX][FX::FXParameterReverbEnable]) { - reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); - } + sendfx_mixer[nFX]->getBuffers(FXSendBuffer); + sendfx_mixer[nFX]->zeroFill(); - m_ReverbSpinLock.Acquire (); + for (uint8_t i = 0; i < m_nToneGenerators; i++) + { + sendfx_mixer[nFX]->doAddMix(i,m_OutputLevel[i]); + } - reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames); + m_ReverbSpinLock.Acquire (); + reverb[nFX]->doReverb(FXSendBuffer[0], FXSendBuffer[1], FXSendBuffer[0], FXSendBuffer[1], nFrames); - // scale down and add left reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames); - arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames); - // scale down and add right reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames); - arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames); + // scale down and add left reverb buffer by reverb level + arm_scale_f32(FXSendBuffer[indexL], reverb[nFX]->get_level(), FXSendBuffer[indexL], nFrames); + arm_add_f32(SampleBuffer[indexL], FXSendBuffer[indexL], SampleBuffer[indexL], nFrames); + // scale down and add right reverb buffer by reverb level + arm_scale_f32(FXSendBuffer[indexR], reverb[nFX]->get_level(), FXSendBuffer[indexR], nFrames); + arm_add_f32(SampleBuffer[indexR], FXSendBuffer[indexR], SampleBuffer[indexR], nFrames); - m_ReverbSpinLock.Release (); + m_ReverbSpinLock.Release (); + } } // END adding reverb @@ -1803,7 +1837,10 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetAftertouchRange (m_nAftertouchRange[nTG], nTG); m_PerformanceConfig.SetAftertouchTarget (m_nAftertouchTarget[nTG], nTG); - m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG); + for (unsigned nFX = 0;nFX < CConfig::FXChains; ++nFX) + { + m_PerformanceConfig.SetFXSend (m_nFXSend[nTG][nFX], nTG, nFX); + } m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); m_PerformanceConfig.SetCompressorPreGain (m_nCompressorPreGain[nTG], nTG); @@ -1821,13 +1858,14 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetEQMidHighFreq (m_nEQMidHighFreq[nTG], nTG); } - m_PerformanceConfig.SetReverbEnable (!!m_nParameter[ParameterReverbEnable]); - m_PerformanceConfig.SetReverbSize (m_nParameter[ParameterReverbSize]); - m_PerformanceConfig.SetReverbHighDamp (m_nParameter[ParameterReverbHighDamp]); - m_PerformanceConfig.SetReverbLowDamp (m_nParameter[ParameterReverbLowDamp]); - m_PerformanceConfig.SetReverbLowPass (m_nParameter[ParameterReverbLowPass]); - m_PerformanceConfig.SetReverbDiffusion (m_nParameter[ParameterReverbDiffusion]); - m_PerformanceConfig.SetReverbLevel (m_nParameter[ParameterReverbLevel]); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + FX::TFXParameter param = FX::TFXParameter (nParam); + m_PerformanceConfig.SetFXParameter (param, GetFXParameter (param, nFX), nFX); + } + } m_PerformanceConfig.SetMasterEQLow (m_nParameter[ParameterMasterEQLow]); m_PerformanceConfig.SetMasterEQMid (m_nParameter[ParameterMasterEQMid]); @@ -2514,7 +2552,10 @@ void CMiniDexed::LoadPerformanceParameters(void) setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); setTGLink(m_PerformanceConfig.GetTGLink(nTG), nTG); - SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + SetFXSend (m_PerformanceConfig.GetFXSend (nTG, nFX), nTG, nFX); + } setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); @@ -2541,14 +2582,14 @@ void CMiniDexed::LoadPerformanceParameters(void) SetEQMidHighFreq (m_PerformanceConfig.GetEQMidHighFreq (nTG), nTG); } - // Effects - SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); - SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); - SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); - SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); - SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); - SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); - SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + for (unsigned nFX=0; nFX < CConfig::FXChains; ++nFX) + { + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + FX::TFXParameter param = FX::TFXParameter(nParam); + SetFXParameter (param, m_PerformanceConfig.GetFXParameter (param, nFX), nFX); + } + } SetParameter (ParameterMasterEQLow, m_PerformanceConfig.GetMasterEQLow ()); SetParameter (ParameterMasterEQMid, m_PerformanceConfig.GetMasterEQMid ()); @@ -3010,3 +3051,61 @@ bool CMiniDexed::InitNetwork() return false; } } + +std::string ToOnOff (int nValue, int nWidth) +{ + static const char *OnOff[] = {"Off", "On"}; + + assert ((unsigned) nValue < sizeof OnOff / sizeof OnOff[0]); + + return OnOff[nValue]; +} + +std::string ToDelayMode (int nValue, int nWidth) +{ + static const char *Mode[] = {"Dual", "Crossover", "PingPong"}; + + assert ((unsigned) nValue < sizeof Mode / sizeof Mode[0]); + + return Mode[nValue]; +} + +std::string ToDelayTime (int nValue, int nWidth) +{ + static const char *Sync[] = {"1/1", "1/1T", "1/2", "1/2T", "1/4", "1/4T", "1/8", "1/8T", "1/16", "1/16T", "1/32", "1/32T"}; + + assert (nValue >= 0 && nValue <= 112); + + if (nValue <= 100) + return std::to_string(nValue * 10) + " ms"; + + return Sync[nValue - 100 - 1]; +} + +std::string ToBPM(int nValue, int nWidth) +{ + return std::to_string(nValue) + " BPM"; +} + +std::string ToHz (int nValue, int nWidth) +{ + uint16_t hz = MIDI_EQ_HZ[nValue]; + char buf[20] = {}; + + if (hz < 1000) + return std::to_string (hz) + " Hz"; + + std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); + return buf; +} + +FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = +{ + {0, 1, 1, 1, "ReverbEnable", ToOnOff}, + {0, 99, 70, 1, "ReverbSize"}, + {0, 99, 50, 1, "ReverbHighDamp"}, + {0, 99, 50, 1, "ReverbLowDamp"}, + {0, 99, 30, 1, "ReverbLowPass"}, + {0, 99, 65, 1, "ReverbDiffusion"}, + {0, 99, 99, 1, "ReverbLevel"}, +}; diff --git a/src/minidexed.h b/src/minidexed.h index 769128464..c450bf79c 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -107,7 +107,7 @@ class CMiniDexed void setBreathController (uint8_t value, unsigned nTG); void setAftertouch (uint8_t value, unsigned nTG); - void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127 + void SetFXSend (unsigned nFXSend, unsigned nTG, unsigned nFX); // 0 .. 99 void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) @@ -184,13 +184,6 @@ class CMiniDexed // Must match the order in CUIMenu::TParameter enum TParameter { - ParameterReverbEnable, - ParameterReverbSize, - ParameterReverbHighDamp, - ParameterReverbLowDamp, - ParameterReverbLowPass, - ParameterReverbDiffusion, - ParameterReverbLevel, ParameterPerformanceSelectChannel, ParameterPerformanceBank, ParameterMasterVolume, @@ -219,6 +212,9 @@ class CMiniDexed bool DeletePerformance(unsigned nID); bool DoDeletePerformance(void); + void SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX); + int GetFXParameter (FX::TFXParameter Parameter, unsigned nFX); + // Must match the order in CUIMenu::TGParameter enum TTGParameter { @@ -232,7 +228,8 @@ class CMiniDexed TGParameterCutoff, TGParameterResonance, TGParameterMIDIChannel, - TGParameterReverbSend, + TGParameterFX1Send, + TGParameterFX2Send, TGParameterPitchBendRange, TGParameterPitchBendStep, TGParameterPortamentoMode, @@ -322,7 +319,8 @@ class CMiniDexed CConfig *m_pConfig; int m_nParameter[ParameterUnknown]; // global (non-TG) parameters - + int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; // FX parameters + unsigned m_nToneGenerators; unsigned m_nPolyphony; @@ -362,7 +360,7 @@ class CMiniDexed unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - unsigned m_nReverbSend[CConfig::AllToneGenerators]; + unsigned m_nFXSend[CConfig::AllToneGenerators][CConfig::FXChains]; bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; @@ -410,9 +408,9 @@ class CMiniDexed CPerformanceTimer m_GetChunkTimer; bool m_bProfileEnabled; - AudioEffectPlateReverb* reverb; + AudioEffectPlateReverb* reverb[CConfig::FXChains]; AudioStereoMixer* tg_mixer; - AudioStereoMixer* reverb_send_mixer; + AudioStereoMixer* sendfx_mixer[CConfig::FXChains]; CSpinLock m_ReverbSpinLock; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 4b99e1476..edc6c892e 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -161,9 +161,19 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("NoteShift%u", nTG+1); m_nNoteShift[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + PropertyName.Format ("FX%uSend%u", nFX+1, nTG+1); + m_nFXSend[nTG][nFX] = m_Properties.GetNumber (PropertyName, 50); + } + + // compatibility ReverbSend[n] => FX1Send[n] PropertyName.Format ("ReverbSend%u", nTG+1); - m_nReverbSend[nTG] = m_Properties.GetNumber (PropertyName, 50); - + if (m_Properties.IsSet (PropertyName) && CConfig::FXChains) + { + m_nFXSend[nTG][0] = m_Properties.GetNumber (PropertyName, 50); + } + PropertyName.Format ("PitchBendRange%u", nTG+1); m_nPitchBendRange[nTG] = m_Properties.GetNumber (PropertyName, 2); @@ -252,13 +262,18 @@ bool CPerformanceConfig::Load (void) m_nEQMidHighFreq[nTG] = m_Properties.GetNumber (PropertyName, 44); } - m_bReverbEnable = m_Properties.GetNumber ("ReverbEnable", 1) != 0; - m_nReverbSize = m_Properties.GetNumber ("ReverbSize", 70); - m_nReverbHighDamp = m_Properties.GetNumber ("ReverbHighDamp", 50); - m_nReverbLowDamp = m_Properties.GetNumber ("ReverbLowDamp", 50); - m_nReverbLowPass = m_Properties.GetNumber ("ReverbLowPass", 30); - m_nReverbDiffusion = m_Properties.GetNumber ("ReverbDiffusion", 65); - m_nReverbLevel = m_Properties.GetNumber ("ReverbLevel", 99); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + CString PropertyName; + + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + + PropertyName.Format ("FX%u%s", nFX+1, p.Name); + m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); + } + } m_nMasterEQLow = m_Properties.GetSignedNumber ("MasterEQLow", 0); m_nMasterEQMid = m_Properties.GetSignedNumber ("MasterEQMid", 0); @@ -284,6 +299,18 @@ bool CPerformanceConfig::Load (void) } } + if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) + { + // setup Reverb to FX1 + m_nFXParameter[0][FX::FXParameterReverbEnable] = m_Properties.GetNumber ("ReverbEnable", 1); + m_nFXParameter[0][FX::FXParameterReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); + m_nFXParameter[0][FX::FXParameterReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); + m_nFXParameter[0][FX::FXParameterReverbLowDamp] = m_Properties.GetNumber ("ReverbLowDamp", 50); + m_nFXParameter[0][FX::FXParameterReverbLowPass] = m_Properties.GetNumber ("ReverbLowPass", 30); + m_nFXParameter[0][FX::FXParameterReverbDiffusion] = m_Properties.GetNumber ("ReverbDiffusion", 65); + m_nFXParameter[0][FX::FXParameterReverbLevel] = m_Properties.GetNumber ("ReverbLevel", 99); + } + return bResult; } @@ -341,9 +368,12 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("NoteShift%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nNoteShift[nTG]); - PropertyName.Format ("ReverbSend%u", nTG+1); - m_Properties.SetNumber (PropertyName, m_nReverbSend[nTG]); - + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + PropertyName.Format ("FX%uSend%u", nFX+1, nTG+1); + m_Properties.SetNumber (PropertyName, m_nFXSend[nTG][nFX]); + } + PropertyName.Format ("PitchBendRange%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nPitchBendRange[nTG]); @@ -434,13 +464,18 @@ bool CPerformanceConfig::Save (void) } - m_Properties.SetNumber ("ReverbEnable", m_bReverbEnable ? 1 : 0); - m_Properties.SetNumber ("ReverbSize", m_nReverbSize); - m_Properties.SetNumber ("ReverbHighDamp", m_nReverbHighDamp); - m_Properties.SetNumber ("ReverbLowDamp", m_nReverbLowDamp); - m_Properties.SetNumber ("ReverbLowPass", m_nReverbLowPass); - m_Properties.SetNumber ("ReverbDiffusion", m_nReverbDiffusion); - m_Properties.SetNumber ("ReverbLevel", m_nReverbLevel); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + CString PropertyName; + + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + + PropertyName.Format ("FX%u%s", nFX+1, p.Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); + } + } m_Properties.SetSignedNumber ("MasterEQLow", m_nMasterEQLow); m_Properties.SetSignedNumber ("MasterEQMid", m_nMasterEQMid); @@ -526,10 +561,11 @@ int CPerformanceConfig::GetNoteShift (unsigned nTG) const return m_nNoteShift[nTG]; } -unsigned CPerformanceConfig::GetReverbSend (unsigned nTG) const +unsigned CPerformanceConfig::GetFXSend (unsigned nTG, unsigned nFX) const { assert (nTG < CConfig::AllToneGenerators); - return m_nReverbSend[nTG]; + assert (nFX < CConfig::FXChains); + return m_nFXSend[nTG][nFX]; } void CPerformanceConfig::SetBankNumber (unsigned nValue, unsigned nTG) @@ -598,10 +634,11 @@ void CPerformanceConfig::SetNoteShift (int nValue, unsigned nTG) m_nNoteShift[nTG] = nValue; } -void CPerformanceConfig::SetReverbSend (unsigned nValue, unsigned nTG) +void CPerformanceConfig::SetFXSend (unsigned nValue, unsigned nTG, unsigned nFX) { assert (nTG < CConfig::AllToneGenerators); - m_nReverbSend[nTG] = nValue; + assert (nFX < CConfig::FXChains); + m_nFXSend[nTG][nFX] = nValue; } int CPerformanceConfig::GetEQLow (unsigned nTG) const @@ -676,75 +713,18 @@ void CPerformanceConfig::SetEQMidHighFreq (unsigned nValue, unsigned nTG) m_nEQMidHighFreq[nTG] = nValue; } - -bool CPerformanceConfig::GetReverbEnable (void) const -{ - return m_bReverbEnable; -} - -unsigned CPerformanceConfig::GetReverbSize (void) const -{ - return m_nReverbSize; -} - -unsigned CPerformanceConfig::GetReverbHighDamp (void) const -{ - return m_nReverbHighDamp; -} - -unsigned CPerformanceConfig::GetReverbLowDamp (void) const -{ - return m_nReverbLowDamp; -} - -unsigned CPerformanceConfig::GetReverbLowPass (void) const -{ - return m_nReverbLowPass; -} - -unsigned CPerformanceConfig::GetReverbDiffusion (void) const -{ - return m_nReverbDiffusion; -} - -unsigned CPerformanceConfig::GetReverbLevel (void) const -{ - return m_nReverbLevel; -} - -void CPerformanceConfig::SetReverbEnable (bool bValue) -{ - m_bReverbEnable = bValue; -} - -void CPerformanceConfig::SetReverbSize (unsigned nValue) -{ - m_nReverbSize = nValue; -} - -void CPerformanceConfig::SetReverbHighDamp (unsigned nValue) -{ - m_nReverbHighDamp = nValue; -} - -void CPerformanceConfig::SetReverbLowDamp (unsigned nValue) -{ - m_nReverbLowDamp = nValue; -} - -void CPerformanceConfig::SetReverbLowPass (unsigned nValue) -{ - m_nReverbLowPass = nValue; -} - -void CPerformanceConfig::SetReverbDiffusion (unsigned nValue) +int CPerformanceConfig::GetFXParameter (FX::TFXParameter nParameter, unsigned nFX) const { - m_nReverbDiffusion = nValue; + assert (nFX < CConfig::FXChains); + assert (nParameter < FX::FXParameterUnknown); + return m_nFXParameter[nFX][nParameter]; } -void CPerformanceConfig::SetReverbLevel (unsigned nValue) +void CPerformanceConfig::SetFXParameter (FX::TFXParameter nParameter, int nValue, unsigned nFX) { - m_nReverbLevel = nValue; + assert (nFX < CConfig::FXChains); + assert (nParameter < FX::FXParameterUnknown); + m_nFXParameter[nFX][nParameter] = nValue; } int CPerformanceConfig::GetMasterEQLow () const diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 75d9de4cd..ee2074ef4 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -26,6 +26,7 @@ #include "config.h" #include #include +#include "effect.h" #define NUM_VOICE_PARAM 156 #define NUM_PERFORMANCES 128 #define NUM_PERFORMANCE_BANKS 128 @@ -54,7 +55,7 @@ class CPerformanceConfig // Performance configuration unsigned GetNoteLimitLow (unsigned nTG) const; // 0 .. 127 unsigned GetNoteLimitHigh (unsigned nTG) const; // 0 .. 127 int GetNoteShift (unsigned nTG) const; // -24 .. 24 - unsigned GetReverbSend (unsigned nTG) const; // 0 .. 127 + unsigned GetFXSend (unsigned nTG, unsigned nFX) const; // 0 .. 127 unsigned GetPitchBendRange (unsigned nTG) const; // 0 .. 12 unsigned GetPitchBendStep (unsigned nTG) const; // 0 .. 12 unsigned GetPortamentoMode (unsigned nTG) const; // 0 .. 1 @@ -91,7 +92,7 @@ class CPerformanceConfig // Performance configuration void SetNoteLimitLow (unsigned nValue, unsigned nTG); void SetNoteLimitHigh (unsigned nValue, unsigned nTG); void SetNoteShift (int nValue, unsigned nTG); - void SetReverbSend (unsigned nValue, unsigned nTG); + void SetFXSend (unsigned nValue, unsigned nTG, unsigned nFX); void SetPitchBendRange (unsigned nValue, unsigned nTG); void SetPitchBendStep (unsigned nValue, unsigned nTG); void SetPortamentoMode (unsigned nValue, unsigned nTG); @@ -134,21 +135,8 @@ class CPerformanceConfig // Performance configuration void SetEQMidHighFreq (unsigned nValue, unsigned nTG); // Effects - bool GetReverbEnable (void) const; - unsigned GetReverbSize (void) const; // 0 .. 99 - unsigned GetReverbHighDamp (void) const; // 0 .. 99 - unsigned GetReverbLowDamp (void) const; // 0 .. 99 - unsigned GetReverbLowPass (void) const; // 0 .. 99 - unsigned GetReverbDiffusion (void) const; // 0 .. 99 - unsigned GetReverbLevel (void) const; // 0 .. 99 - - void SetReverbEnable (bool bValue); - void SetReverbSize (unsigned nValue); - void SetReverbHighDamp (unsigned nValue); - void SetReverbLowDamp (unsigned nValue); - void SetReverbLowPass (unsigned nValue); - void SetReverbDiffusion (unsigned nValue); - void SetReverbLevel (unsigned nValue); + int GetFXParameter (FX::TFXParameter nParameter, unsigned nFX) const; + void SetFXParameter (FX::TFXParameter nParameter, int nValue, unsigned nFX); int GetMasterEQLow () const; int GetMasterEQMid () const; @@ -225,7 +213,7 @@ class CPerformanceConfig // Performance configuration unsigned m_nNoteLimitLow[CConfig::AllToneGenerators]; unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - int m_nReverbSend[CConfig::AllToneGenerators]; + int m_nFXSend[CConfig::AllToneGenerators][CConfig::FXChains]; unsigned m_nPitchBendRange[CConfig::AllToneGenerators]; unsigned m_nPitchBendStep[CConfig::AllToneGenerators]; unsigned m_nPortamentoMode[CConfig::AllToneGenerators]; @@ -272,13 +260,7 @@ class CPerformanceConfig // Performance configuration std::string NewPerformanceName=""; - bool m_bReverbEnable; - unsigned m_nReverbSize; - unsigned m_nReverbHighDamp; - unsigned m_nReverbLowDamp; - unsigned m_nReverbLowPass; - unsigned m_nReverbDiffusion; - unsigned m_nReverbLevel; + int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; int m_nMasterEQLow; int m_nMasterEQMid; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 59a9adba7..f241eaa07 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -77,7 +77,8 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Volume", EditTGParameter, 0, CMiniDexed::TGParameterVolume}, #ifdef ARM_ALLOW_MULTI_CORE {"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan}, - {"Reverb-Send", EditTGParameter, 0, CMiniDexed::TGParameterReverbSend}, + {"FX1-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX1Send}, + {"FX2-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX2Send}, #endif {"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune}, {"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff}, @@ -107,10 +108,17 @@ const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = +{ + {"Reverb", MenuHandler, s_ReverbMenu}, + {0}, +}; + const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { #ifdef ARM_ALLOW_MULTI_CORE - {"Reverb", MenuHandler, s_ReverbMenu}, + {"SendFX1", MenuHandler, s_FXMenu, 0}, + {"SendFX2", MenuHandler, s_FXMenu, 1}, {"EQ", MenuHandler, s_MasterEQMenu}, {"Compressor", MenuHandler, s_MasterCompressorMenu}, #endif @@ -173,13 +181,13 @@ const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = { - {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterReverbEnable}, - {"Size", EditGlobalParameter, 0, CMiniDexed::ParameterReverbSize}, - {"High damp", EditGlobalParameter, 0, CMiniDexed::ParameterReverbHighDamp}, - {"Low damp", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLowDamp}, - {"Low pass", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLowPass}, - {"Diffusion", EditGlobalParameter, 0, CMiniDexed::ParameterReverbDiffusion}, - {"Level", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLevel}, + {"Enable", EditFXParameter2, 0, FX::FXParameterReverbEnable}, + {"Size", EditFXParameter2, 0, FX::FXParameterReverbSize}, + {"High damp", EditFXParameter2, 0, FX::FXParameterReverbHighDamp}, + {"Low damp", EditFXParameter2, 0, FX::FXParameterReverbLowDamp}, + {"Low pass", EditFXParameter2, 0, FX::FXParameterReverbLowPass}, + {"Diffusion", EditFXParameter2, 0, FX::FXParameterReverbDiffusion}, + {"Level", EditFXParameter2, 0, FX::FXParameterReverbLevel}, {0} }; @@ -278,13 +286,6 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = // must match CMiniDexed::TParameter CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = { - {0, 1, 1, ToOnOff}, // ParameterReverbEnable - {0, 99, 1}, // ParameterReverbSize - {0, 99, 1}, // ParameterReverbHighDamp - {0, 99, 1}, // ParameterReverbLowDamp - {0, 99, 1}, // ParameterReverbLowPass - {0, 99, 1}, // ParameterReverbDiffusion - {0, 99, 1}, // ParameterReverbLevel {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank {0, 127, 8, ToVolume}, // ParameterMasterVolume @@ -316,7 +317,8 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 99, 1}, // TGParameterCutoff {0, 99, 1}, // TGParameterResonance {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // TGParameterMIDIChannel - {0, 99, 1}, // TGParameterReverbSend + {0, 99, 1}, // TGParameterFX1Send + {0, 99, 1}, // TGParameterFX2Send {0, 12, 1}, // TGParameterPitchBendRange {0, 12, 1}, // TGParameterPitchBendStep {0, 1, 1, ToPortaMode}, // TGParameterPortamentoMode @@ -1015,6 +1017,54 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me nValue > rParam.Minimum, nValue < rParam.Maximum); } +void CUIMenu::EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) +{ + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + case MenuEventStepDown: + nValue -= rParam.Increment; + if (nValue < rParam.Minimum) + { + nValue = rParam.Minimum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + case MenuEventStepUp: + nValue += rParam.Increment; + if (nValue > rParam.Maximum) + { + nValue = rParam.Maximum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + default: + return; + } + + std::string FX = std::string("FX") + std::to_string (nFX+1); + + std::string Value = GetFXValueString (Param, + pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), + pUIMenu->m_pConfig->GetLCDColumns() - 2); + + pUIMenu->m_pUI->DisplayWrite (FX.c_str (), + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + Value.c_str (), + nValue > rParam.Minimum, nValue < rParam.Maximum); +} + void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; @@ -1233,6 +1283,25 @@ std::string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nW return Result; } +std::string CUIMenu::GetFXValueString (unsigned nFXParameter, int nValue, int nWidth) +{ + std::string Result; + + assert (nFXParameter < FX::FXParameterUnknown); + + CUIMenu::TToString *pToString = FX::s_FXParameter[nFXParameter].ToString; + if (pToString) + { + Result = (*pToString) (nValue, nWidth); + } + else + { + Result = std::to_string (nValue); + } + + return Result; +} + std::string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth) { std::string Result; diff --git a/src/uimenu.h b/src/uimenu.h index 3b1469672..37e34dc2e 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -89,6 +89,7 @@ class CUIMenu static void EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event); + static void EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event); static void EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event); @@ -100,6 +101,7 @@ class CUIMenu static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); static std::string GetTGValueString (unsigned nTGParameter, int nValue, int nWidth); + static std::string GetFXValueString (unsigned nFXParameter, int nValue, int nWidth); static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth); static std::string GetOPValueString (unsigned nOPParameter, int nValue, int nWidth); @@ -165,6 +167,7 @@ class CUIMenu static const TMenuItem s_MenuRoot[]; static const TMenuItem s_MainMenu[]; static const TMenuItem s_TGMenu[]; + static const TMenuItem s_FXMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_EQMenu[]; static const TMenuItem s_ReverbMenu[]; From cfd26e7aa1340ad53df5b5bc84b5c7756ef4f9e6 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 01:49:33 +0200 Subject: [PATCH 074/136] add chorus --- src/effect_ykchorus.h | 69 +++++++++++++++++ src/ykchorus/Chorus.h | 143 ++++++++++++++++++++++++++++++++++++ src/ykchorus/ChorusEngine.h | 114 ++++++++++++++++++++++++++++ src/ykchorus/DCBlock.h | 45 ++++++++++++ src/ykchorus/OnePoleLP.h | 44 +++++++++++ 5 files changed, 415 insertions(+) create mode 100644 src/effect_ykchorus.h create mode 100644 src/ykchorus/Chorus.h create mode 100644 src/ykchorus/ChorusEngine.h create mode 100644 src/ykchorus/DCBlock.h create mode 100644 src/ykchorus/OnePoleLP.h diff --git a/src/effect_ykchorus.h b/src/effect_ykchorus.h new file mode 100644 index 000000000..05f567876 --- /dev/null +++ b/src/effect_ykchorus.h @@ -0,0 +1,69 @@ +/* + * YK Chorus Port + * Ported from https://github.com/SpotlightKid/ykchorus + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include "ykchorus/ChorusEngine.h" + +class AudioEffectYKChorus +{ +public: + AudioEffectYKChorus(float samplerate) : engine {samplerate} + { + setChorus1(true); + setChorus2(true); + setChorus1LFORate(0.5f); + setChorus2LFORate(0.83f); + setMix(0.0f); + } + + bool getChorus1() { return engine.isChorus1Enabled; } + bool getChorus2() { return engine.isChorus2Enabled; } + + void setChorus1(bool enable) { engine.setEnablesChorus(enable, engine.isChorus2Enabled); } + void setChorus2(bool enable) { engine.setEnablesChorus(engine.isChorus1Enabled, enable); } + + float getChorus1Rate() { return engine.chorus1L->rate; } + float getChorus2Rate() { return engine.chorus2L->rate; } + + void setChorus1LFORate(float32_t rate) { engine.setChorus1LfoRate(rate); } + void setChorus2LFORate(float32_t rate) { engine.setChorus2LfoRate(rate); } + + float32_t getMix() { return mix; } + + void setMix(float32_t value) + { + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } + } + + void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) + { + if (wet == 0.0f) return; + + if (!engine.isChorus1Enabled && !engine.isChorus2Enabled) return; + + for (uint16_t i = 0; i < len; i++) + { + engine.process(dry, wet, inblockL++, inblockR++); + } + } + +private: + ChorusEngine engine; + + float32_t mix, dry, wet; +}; diff --git a/src/ykchorus/Chorus.h b/src/ykchorus/Chorus.h new file mode 100644 index 000000000..603e6bb06 --- /dev/null +++ b/src/ykchorus/Chorus.h @@ -0,0 +1,143 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__Chorus_h) +#define __Chorus_h + +#include "OnePoleLP.h" +#include "math.h" + +class Chorus { +public: + float *delayLineStart; + float *delayLineEnd; + float *writePtr; + + int delayLineLength; + float rate; + float delayLineOutput; + + float sampleRate; + float delayTime; + + // Runtime variables + float offset, diff, frac, *ptr, *ptr2; + + int readPos; + + OnePoleLP *lp; + float z1; + float mult, sign; + + // lfo + float lfoPhase, lfoStepSize, lfoSign; + + Chorus(float sampleRate, float phase, float rate, float delayTime) { + this->rate = rate; + this->sampleRate = sampleRate; + this->delayTime = delayTime; + z1 = 0.0f; + sign = 0; + lfoPhase = phase * 2.0f - 1.0f; + lfoStepSize = (4.0f * rate / sampleRate); + lfoSign = 1.0f; + + // Compute required buffer size for desired delay and allocate it + // Add extra point to aid in interpolation later + delayLineLength = ((int)floorf(delayTime * sampleRate * 0.001f) * 2); + delayLineStart = new float[delayLineLength]; + + // Set up pointers for delay line + delayLineEnd = delayLineStart + delayLineLength; + writePtr = delayLineStart; + + // Zero out the buffer (silence) + do { + *writePtr = 0.0f; + } + while (++writePtr < delayLineEnd); + + // Set read pointer to end of delayline. Setting it to the end + // ensures the interpolation below works correctly to produce + // the first non-zero sample. + writePtr = delayLineStart + delayLineLength -1; + delayLineOutput = 0.0f; + lp = new OnePoleLP(); + } + + ~Chorus() { + delete[] delayLineStart; + delete lp; + } + + void setLfoRate(float rate) { + this->rate = rate; + lfoStepSize = (4.0f * rate / sampleRate); + } + + float process(float *sample) { + // Get delay time + offset = (nextLFO() * 0.3f + 0.4f) * delayTime * sampleRate * 0.001f; + + // Compute the largest read pointer based on the offset. If ptr + // is before the first delayline location, wrap around end point + ptr = writePtr - (int)floorf(offset); + if (ptr < delayLineStart) + ptr += delayLineLength; + + ptr2 = ptr - 1; + if (ptr2 < delayLineStart) + ptr2 += delayLineLength; + + frac = offset - (int)floorf(offset); + delayLineOutput = *ptr2 + *ptr * (1 - frac) - (1 - frac) * z1; + z1 = delayLineOutput; + + // Low pass + lp->tick(&delayLineOutput, 0.95f); + + // Write the input sample and any feedback to delayline + *writePtr = *sample; + + // Increment buffer index and wrap if necesary + if (++writePtr >= delayLineEnd) { + writePtr = delayLineStart; + } + return delayLineOutput; + } + + inline float nextLFO() { + if (lfoPhase >= 1.0f) + { + lfoSign = -1.0f; + } + else if (lfoPhase <= -1.0f) + { + lfoSign = +1.0f; + } + lfoPhase += lfoStepSize * lfoSign; + return lfoPhase; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/ChorusEngine.h b/src/ykchorus/ChorusEngine.h new file mode 100644 index 000000000..cb30c66e0 --- /dev/null +++ b/src/ykchorus/ChorusEngine.h @@ -0,0 +1,114 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__ChorusEngine_h) +#define __ChorusEngine_h + +#include "Chorus.h" +#include "DCBlock.h" + + +class ChorusEngine { +public: + Chorus *chorus1L; + Chorus *chorus1R; + Chorus *chorus2L; + Chorus *chorus2R; + + DCBlock *dcBlock1L; + DCBlock *dcBlock1R; + DCBlock *dcBlock2L; + DCBlock *dcBlock2R; + + bool isChorus1Enabled; + bool isChorus2Enabled; + + ChorusEngine(float sampleRate) { + dcBlock1L = new DCBlock(); + dcBlock1R = new DCBlock(); + dcBlock2L = new DCBlock(); + dcBlock2R = new DCBlock(); + + setUpChorus(sampleRate); + } + + ~ChorusEngine() { + delete chorus1L; + delete chorus1R; + delete chorus2L; + delete chorus2R; + delete dcBlock1L; + delete dcBlock1R; + delete dcBlock2L; + delete dcBlock2R; + } + + void setSampleRate(float sampleRate) { + setUpChorus(sampleRate); + } + + void setEnablesChorus(bool isChorus1Enabled, bool isChorus2Enabled) { + this->isChorus1Enabled = isChorus1Enabled; + this->isChorus2Enabled = isChorus2Enabled; + } + + void setChorus1LfoRate(float rate) { + chorus1L->setLfoRate(rate); + chorus1R->setLfoRate(rate); + } + + void setChorus2LfoRate(float rate) { + chorus2L->setLfoRate(rate); + chorus2R->setLfoRate(rate); + } + + void setUpChorus(float sampleRate) { + chorus1L = new Chorus(sampleRate, 1.0f, 0.5f, 7.0f); + chorus1R = new Chorus(sampleRate, 0.0f, 0.5f, 7.0f); + chorus2L = new Chorus(sampleRate, 0.0f, 0.83f, 7.0f); + chorus2R = new Chorus(sampleRate, 1.0f, 0.83f, 7.0f); + } + + inline void process(float dry, float wet, float *sampleL, float *sampleR) { + float resultR = 0.0f; + float resultL = 0.0f; + if (isChorus1Enabled) + { + resultL += chorus1L->process(sampleL); + resultR += chorus1R->process(sampleR); + dcBlock1L->tick(&resultL, 0.01f); + dcBlock1R->tick(&resultR, 0.01f); + } + if (isChorus2Enabled) + { + resultL += chorus2L->process(sampleL); + resultR += chorus2R->process(sampleR); + dcBlock2L->tick(&resultL, 0.01f); + dcBlock2R->tick(&resultR, 0.01f); + } + *sampleL = dry * *sampleL + wet * resultL * 1.4f; + *sampleR = dry * *sampleR + wet * resultR * 1.4f; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/DCBlock.h b/src/ykchorus/DCBlock.h new file mode 100644 index 000000000..40dc1e427 --- /dev/null +++ b/src/ykchorus/DCBlock.h @@ -0,0 +1,45 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__DCBlock_h) +#define __DCBlock_h + +class DCBlock { +public: + float inputs, outputs, lastOutput; + + DCBlock() { + lastOutput = inputs = outputs = 0.0f; + } + + ~DCBlock() {} + + inline void tick(float *sample, float cutoff) { + outputs = *sample - inputs + (0.999f - cutoff * 0.4f) * outputs; + inputs = *sample; + lastOutput = outputs; + *sample = lastOutput; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/OnePoleLP.h b/src/ykchorus/OnePoleLP.h new file mode 100644 index 000000000..955ed53cd --- /dev/null +++ b/src/ykchorus/OnePoleLP.h @@ -0,0 +1,44 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__OnePoleLP_h) +#define __OnePoleLP_h + +class OnePoleLP { +public: + float inputs, outputs, lastOutput; + + OnePoleLP() { + lastOutput = inputs = outputs = 0.0f; + } + + ~OnePoleLP() {} + + void tick(float *sample, float cutoff) { + float p = (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f); + outputs = (1.0f - p) * (*sample) + p * outputs; + *sample = outputs; + } +}; + +#endif \ No newline at end of file From 3b1b9fc5584bb87c60dd2a8df6bb018dc0048176 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 14:08:20 +0200 Subject: [PATCH 075/136] add lpf effect --- src/effect_lpf.h | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/effect_lpf.h diff --git a/src/effect_lpf.h b/src/effect_lpf.h new file mode 100644 index 000000000..46b1148c6 --- /dev/null +++ b/src/effect_lpf.h @@ -0,0 +1,130 @@ +/* + * Stereo Low Pass Filter + * Ported from (https://github.com/jnonis/MiniDexed) + */ + +#pragma once + +class AudioEffectLPF +{ +public: + static constexpr float32_t MIN_CUTOFF = 0.00001f; + static constexpr float32_t MAX_CUTOFF = 20000.0f; + static constexpr float32_t MIN_RES = 0.0f; + static constexpr float32_t MAX_RES = 1.0f; + + struct LPFState + { + float32_t y1; + float32_t y2; + float32_t y3; + float32_t y4; + float32_t oldx; + float32_t oldy1; + float32_t oldy2; + float32_t oldy3; + }; + + AudioEffectLPF(float32_t samplerate, float32_t cutoff_Hz, float32_t resonance): + samplerate{samplerate}, + cutoff{constrain(cutoff_Hz, MIN_CUTOFF, MAX_CUTOFF)}, + resonance{constrain(resonance, MIN_RES, MAX_RES)}, + stateL{}, + stateR{} + { + recalculate(); + } + + float32_t getCutoff_Hz() { return cutoff; } + + void setCutoff_Hz(float32_t value) + { + cutoff = constrain(value, MIN_CUTOFF, MAX_CUTOFF); + recalculate(); + } + + void setResonance(float32_t value) + { + resonance = constrain(value, MIN_RES, MAX_RES); + recalculate(); + } + + float32_t processSampleL(float32_t input) + { + return processSample(input, &stateL); + } + + float32_t processSampleR(float32_t input) + { + return processSample(input, &stateR); + } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + for (int i = 0; i < len; i++) + { + blockL[i] = processSample(blockL[i], &stateL); + blockR[i] = processSample(blockR[i], &stateR); + } + } + + void resetState() + { + stateL = {}; + stateR = {}; + } + +private: + void recalculate() + { + float32_t f = (cutoff + cutoff) / samplerate; + p = f * (1.8 - (0.8 * f)); + k = p + p - 1.0; + + float32_t t = (1.0 - p) * 1.386249; + float32_t t2 = 12.0 + t * t; + r = resonance * (t2 + 6.0 * t) / (t2 - 6.0 * t); + } + + float32_t processSample(float32_t input, LPFState* state) + { + float32_t y1 = state->y1; + float32_t y2 = state->y2; + float32_t y3 = state->y3; + float32_t y4 = state->y4; + float32_t oldx = state->oldx; + float32_t oldy1 = state->oldy1; + float32_t oldy2 = state->oldy2; + float32_t oldy3 = state->oldy3; + + // Process input + float32_t x = input - r * y4; + + // Four cascaded one pole filters (bilinear transform) + y1 = x * p + oldx * p - k * y1; + y2 = y1 * p + oldy1 * p - k * y2; + y3 = y2 * p + oldy2 * p - k * y3; + y4 = y3 * p + oldy3 * p - k * y4; + + // Clipper band limited sigmoid + y4 -= (y4 * y4 * y4) / 6.0; + + state->y1 = y1; + state->y2 = y2; + state->y3 = y3; + state->y4 = y4; + state->oldx = x; + state->oldy1 = y1; + state->oldy2 = y2; + state->oldy3 = y3; + + return y4; + } + + float32_t samplerate; + float32_t cutoff; + float32_t resonance; + float32_t r, p, k; + LPFState stateL; + LPFState stateR; +}; From aad20c72008f709cc16f8928e327ee9a2a785d56 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 14:08:39 +0200 Subject: [PATCH 076/136] add delay effect --- src/Makefile | 2 +- src/effect_dreamdelay.cpp | 174 ++++++++++++++++++++++++++++++++++++++ src/effect_dreamdelay.h | 65 ++++++++++++++ 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/effect_dreamdelay.cpp create mode 100644 src/effect_dreamdelay.h diff --git a/src/Makefile b/src/Makefile index ae723c1ee..e1c96d17e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ - effect_platervbstereo.o uibuttons.o midipin.o \ + effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o diff --git a/src/effect_dreamdelay.cpp b/src/effect_dreamdelay.cpp new file mode 100644 index 000000000..0d77acd71 --- /dev/null +++ b/src/effect_dreamdelay.cpp @@ -0,0 +1,174 @@ +#include "effect_dreamdelay.h" + +#include + +constexpr float32_t MAX_DELAY_TIME = 2.0f; + +AudioEffectDreamDelay::AudioEffectDreamDelay(float32_t samplerate): +samplerate{samplerate}, +mode{DUAL}, +bufferSize{(size_t)(samplerate * MAX_DELAY_TIME)}, +bufferL{new float32_t[bufferSize]{}}, +bufferR{new float32_t[bufferSize]{}}, +index{}, +timeLSync{}, +timeRSync{}, +feedback{0.6f}, +lpf{samplerate, 6300.0f, 0.0f}, +tempo{120} +{ + assert(bufferL); + assert(bufferR); + + setTimeL(0.36f); + setTimeR(0.36f); + setMix(0.0f); +} + +AudioEffectDreamDelay::~AudioEffectDreamDelay() +{ + delete bufferL; + delete bufferR; +} + +static float32_t calculateTime(AudioEffectDreamDelay::Sync sync, unsigned tempo) +{ + constexpr float32_t triplet = 2.0 / 3.0; + static constexpr float32_t denominators[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 16, 16, 32, 32, 1}; + return 240.0 / tempo / denominators[(int)sync] * ((int)sync % 2 ? 1 : triplet); +} + +void AudioEffectDreamDelay::setTimeL(float32_t time) +{ + timeL = constrain(time, 0.0f, MAX_DELAY_TIME); + int offset = index - timeL * samplerate - (timeL ? 0 : 1); + if (offset < 0) offset += bufferSize; + indexDL = offset; +} + +void AudioEffectDreamDelay::setTimeR(float32_t time) +{ + timeR = constrain(time, 0.0f, MAX_DELAY_TIME); + int offset = index - timeR * samplerate - (timeR ? 0 : 1); + if (offset < 0) offset += bufferSize; + indexDR = offset; +} + +void AudioEffectDreamDelay::setTimeLSync(Sync sync) +{ + timeLSync = sync; + if (sync != SYNC_NONE) + setTimeL(calculateTime(sync, tempo)); +} + +void AudioEffectDreamDelay::setTimeRSync(Sync sync) +{ + timeRSync = sync; + if (sync != SYNC_NONE) + setTimeR(calculateTime(sync, tempo)); +} + +void AudioEffectDreamDelay::setTempo(unsigned t) +{ + tempo = constrain(t, 30u, 240u); + setTimeLSync(timeLSync); + setTimeRSync(timeRSync); +} + +void AudioEffectDreamDelay::setMix(float32_t value) +{ + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } +} + +void AudioEffectDreamDelay::process(float32_t* blockL, float32_t* blockR, uint16_t len) +{ + if (wet == 0.0f) return; + + switch(mode) + { + case DUAL: + for (uint16_t i = 0; i < len; i++) + { + float32_t inL = blockL[i]; + float32_t inR = blockR[i]; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(inL) + delayL * feedback; + bufferR[index] = lpf.processSampleR(inR) + delayR * feedback; + + blockL[i] = inL * dry + delayL * wet; + blockR[i] = inR * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + case CROSSOVER: + for (uint16_t i = 0; i < len; i++) + { + float32_t inL = blockL[i]; + float32_t inR = blockR[i]; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(inL) + delayR * feedback; + bufferR[index] = lpf.processSampleR(inR) + delayL * feedback; + + blockL[i] = inL * dry + delayL * wet; + blockR[i] = inR * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + case PINGPONG: + for (uint16_t i = 0; i < len; i++) + { + float32_t in = (blockL[i] + blockR[i]) / 2; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(in) + delayR * feedback; + bufferR[index] = delayL; + + blockL[i] = in * dry + delayL * wet; + blockR[i] = in * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + default: + assert(0); + break; + } +} + +void AudioEffectDreamDelay::resetState() +{ + memset(bufferL, 0, bufferSize * sizeof *bufferL); + memset(bufferR, 0, bufferSize * sizeof *bufferR); + + lpf.resetState(); +} diff --git a/src/effect_dreamdelay.h b/src/effect_dreamdelay.h new file mode 100644 index 000000000..2056b53dd --- /dev/null +++ b/src/effect_dreamdelay.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include "common.h" +#include "effect_lpf.h" + +class AudioEffectDreamDelay +{ +public: + enum Mode { DUAL, CROSSOVER, PINGPONG, MODE_UNKNOWN }; + enum Sync { SYNC_NONE, T1_1, T1_1T, T1_2, T1_2T, T1_4, T1_4T, T1_8, T1_8T, T1_16, T1_16T, T1_32, T1_32T, SYNC_UNKNOWN }; + + AudioEffectDreamDelay(float32_t samplerate); + ~AudioEffectDreamDelay(); + + void setMode(Mode m) { mode = m; } + void setTimeL(float32_t time); + void setTimeLSync(Sync sync); + void setTimeR(float32_t time); + void setTimeRSync(Sync sync); + void setFeedback(float32_t fb) { feedback = constrain(fb, 0.0f, 1.0f); } + void setHighCut(float32_t highcut) { lpf.setCutoff_Hz(highcut); } + void setTempo(unsigned t); + void setMix(float32_t mix); + + Mode getMode() { return mode; } + float32_t getTimeL() { return timeL; } + float32_t getTimeR() { return timeR; } + float32_t getFeedback() { return feedback; } + float32_t getHighCut() { return lpf.getCutoff_Hz(); } + unsigned getTempo() { return tempo; } + float32_t getMix() { return mix; } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len); + + void resetState(); + +private: + float32_t samplerate; + + Mode mode; + + size_t bufferSize; + float32_t* bufferL; + float32_t* bufferR; + unsigned index; + unsigned indexDL; + unsigned indexDR; + + float32_t timeL; // Left delay time in seconds + float32_t timeR; // Right delay time in seconds + Sync timeLSync; + Sync timeRSync; + + float32_t feedback; // 0.0 - 1.0 + + AudioEffectLPF lpf; + + unsigned tempo; + + float32_t mix; + float32_t dry; + float32_t wet; +}; From 6230338b32cd79b848109bd6801fad0ab8a1f9d3 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 14:09:26 +0200 Subject: [PATCH 077/136] add fx chain --- src/effect.h | 30 +++-- src/effect_chain.h | 42 +++++++ src/effect_platervbstereo.cpp | 2 - src/effect_platervbstereo.h | 7 -- src/minidexed.cpp | 229 +++++++++++++++++++++++++--------- src/minidexed.h | 10 +- src/performanceconfig.cpp | 14 +-- src/uimenu.cpp | 75 +++++++---- src/uimenu.h | 4 +- 9 files changed, 298 insertions(+), 115 deletions(-) create mode 100644 src/effect_chain.h diff --git a/src/effect.h b/src/effect.h index 4760f107d..582f01676 100644 --- a/src/effect.h +++ b/src/effect.h @@ -1,15 +1,30 @@ class FX { public: + static const int FXComposite = 1 << 0; // updates multiple controls, it shouldn't update the controls at startup and performance load + enum TFXParameter { - FXParameterReverbEnable, - FXParameterReverbSize, - FXParameterReverbHighDamp, - FXParameterReverbLowDamp, - FXParameterReverbLowPass, - FXParameterReverbDiffusion, - FXParameterReverbLevel, + FXParameterYKChorusMix, + FXParameterYKChorusEnable1, + FXParameterYKChorusEnable2, + FXParameterYKChorusLFORate1, + FXParameterYKChorusLFORate2, + FXParameterDreamDelayMix, + FXParameterDreamDelayMode, + FXParameterDreamDelayTime, + FXParameterDreamDelayTimeL, + FXParameterDreamDelayTimeR, + FXParameterDreamDelayTempo, + FXParameterDreamDelayFeedback, + FXParameterDreamDelayHighCut, + FXParameterPlateReverbEnable, + FXParameterPlateReverbSize, + FXParameterPlateReverbHighDamp, + FXParameterPlateReverbLowDamp, + FXParameterPlateReverbLowPass, + FXParameterPlateReverbDiffusion, + FXParameterReturnLevel, FXParameterUnknown, }; @@ -23,6 +38,7 @@ class FX int Increment; const char *Name; TToString *ToString; + int Flags; }; static FX::FXParameterType s_FXParameter[]; diff --git a/src/effect_chain.h b/src/effect_chain.h new file mode 100644 index 000000000..51997b25b --- /dev/null +++ b/src/effect_chain.h @@ -0,0 +1,42 @@ +#pragma once + +#include "effect_dreamdelay.h" +#include "effect_platervbstereo.h" +#include "effect_ykchorus.h" + +class AudioFXChain +{ +public: + AudioFXChain(float samplerate): + yk_chorus{samplerate}, + dream_delay{samplerate}, + plate_reverb{samplerate}, + level{} + { + } + + float get_level() { return level; } + void set_level(float value) { level = constrain(value, 0.0f, 1.0f); } + + void process (float *inputL, float *inputR, uint16_t len) + { + yk_chorus.process(inputL, inputR, len); + dream_delay.process(inputL, inputR, len); + plate_reverb.doReverb(inputL, inputR, inputL, inputR, len); + arm_scale_f32(inputL, level, inputL, len); + arm_scale_f32(inputR, level, inputR, len); + } + + void resetState() + { + dream_delay.resetState(); + plate_reverb.reset(); + } + + AudioEffectYKChorus yk_chorus; + AudioEffectDreamDelay dream_delay; + AudioEffectPlateReverb plate_reverb; + +private: + float level; +}; diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index 6a69771ed..de4366397 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -152,8 +152,6 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) lfo1_adder = (UINT32_MAX + 1)/(samplerate * LFO1_FREQ_HZ); lfo2_phase_acc = 0; lfo2_adder = (UINT32_MAX + 1)/(samplerate * LFO2_FREQ_HZ); - - reverb_level = 0.0f; } // #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift)) diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 13bad8e72..476a132df 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -99,21 +99,14 @@ class AudioEffectPlateReverb loop_allp_k = n; } - void level(float n) - { - reverb_level = constrain(n, 0.0f, 1.0f); - } - float32_t get_size(void) {return rv_time_k;} bool get_bypass(void) {return bypass;} void set_bypass(bool state) {bypass = state;}; void tgl_bypass(void) {bypass ^=1;} - float32_t get_level(void) {return reverb_level;} void reset(); private: bool bypass = false; - float32_t reverb_level; float32_t input_attn; float32_t in_allp_k; // input allpass coeff diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 680eb13b7..fb47fd31e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -66,7 +66,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), - reverb {}, + fx_chain {}, tg_mixer {}, sendfx_mixer {}, m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, @@ -132,7 +132,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) { - m_nFXSend[i][nFX] = 0; + m_nFXSend[i][nFX] = 50; } m_bCompressorEnable[i] = 1; @@ -272,12 +272,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned nFX = 0; nFX < CConfig::FXChains; nFX++) { sendfx_mixer[nFX] = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); - reverb[nFX] = new AudioEffectPlateReverb(pConfig->GetSampleRate()); + fx_chain[nFX] = new AudioFXChain(pConfig->GetSampleRate()); for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) { const FX::FXParameterType &p = FX::s_FXParameter[nParam]; - SetFXParameter (FX::TFXParameter(nParam), p.Default, nFX); + bool bSaveOnly = p.Flags & FX::FXComposite; + SetFXParameter (FX::TFXParameter(nParam), p.Default, nFX, bSaveOnly); } } // END setup reverb @@ -499,7 +500,7 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) { - reverb[nFX]->reset(); + fx_chain[nFX]->resetState(); } if (m_nSetNewPerformanceID == GetActualPerformanceID()) @@ -1196,7 +1197,7 @@ int CMiniDexed::GetParameter (TParameter Parameter) return m_nParameter[Parameter]; } -void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX) +void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX, bool bSaveOnly) { assert (nFX < CConfig::FXChains); assert (Parameter < FX::FXParameterUnknown); @@ -1206,48 +1207,147 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_nFXParameter[nFX][Parameter] = nValue; + if (bSaveOnly) return; + switch (Parameter) { - case FX::FXParameterReverbEnable: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->set_bypass (!nValue); - m_ReverbSpinLock.Release (); + case FX::FXParameterYKChorusMix: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setMix (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusEnable1: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus1 (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusEnable2: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus2 (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusLFORate1: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus1LFORate (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusLFORate2: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus2LFORate (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayMix: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setMix (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayMode: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setMode ((AudioEffectDreamDelay::Mode)nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayTime: + SetFXParameter (FX::FXParameterDreamDelayTimeL, nValue, nFX); + SetFXParameter (FX::FXParameterDreamDelayTimeR, nValue, nFX); + break; + + case FX::FXParameterDreamDelayTimeL: + m_FXSpinLock.Acquire (); + + if (nValue <= 100) + { + fx_chain[nFX]->dream_delay.setTimeL (nValue / 100.f); + fx_chain[nFX]->dream_delay.setTimeLSync (AudioEffectDreamDelay::SYNC_NONE); + } + else + { + fx_chain[nFX]->dream_delay.setTimeLSync ((AudioEffectDreamDelay::Sync)(nValue - 100)); + } + + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayTimeR: + m_FXSpinLock.Acquire (); + + if (nValue <= 100) + { + fx_chain[nFX]->dream_delay.setTimeR (nValue / 100.f); + fx_chain[nFX]->dream_delay.setTimeRSync (AudioEffectDreamDelay::SYNC_NONE); + } + else + { + fx_chain[nFX]->dream_delay.setTimeRSync ((AudioEffectDreamDelay::Sync)(nValue - 100)); + } + + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayTempo: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setTempo (nValue); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbSize: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->size (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayFeedback: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setFeedback (nValue / 100.0f); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbHighDamp: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->hidamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayHighCut: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setHighCut (MIDI_EQ_HZ[nValue]); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbLowDamp: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->lodamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbEnable: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.set_bypass (!nValue); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbLowPass: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->lowpass (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbSize: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.size (nValue / 99.0f); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbDiffusion: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->diffusion (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbHighDamp: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.hidamp (nValue / 99.0f); + m_FXSpinLock.Release (); break; - case FX::FXParameterReverbLevel: - m_ReverbSpinLock.Acquire (); - reverb[nFX]->level (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbLowDamp: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.lodamp (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterPlateReverbLowPass: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.lowpass (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterPlateReverbDiffusion: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.diffusion (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterReturnLevel: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->set_level (nValue / 99.0f); + m_FXSpinLock.Release (); break; default: @@ -1659,28 +1759,22 @@ void CMiniDexed::ProcessSound (void) for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) { - if (m_nFXParameter[nFX][FX::FXParameterReverbEnable]) - { - sendfx_mixer[nFX]->getBuffers(FXSendBuffer); - sendfx_mixer[nFX]->zeroFill(); + if (fx_chain[nFX]->get_level() == 0.0f) continue; - for (uint8_t i = 0; i < m_nToneGenerators; i++) - { - sendfx_mixer[nFX]->doAddMix(i,m_OutputLevel[i]); - } + sendfx_mixer[nFX]->getBuffers(FXSendBuffer); + sendfx_mixer[nFX]->zeroFill(); - m_ReverbSpinLock.Acquire (); - reverb[nFX]->doReverb(FXSendBuffer[0], FXSendBuffer[1], FXSendBuffer[0], FXSendBuffer[1], nFrames); + for (uint8_t i = 0; i < m_nToneGenerators; i++) + { + sendfx_mixer[nFX]->doAddMix(i,m_OutputLevel[i]); + } - // scale down and add left reverb buffer by reverb level - arm_scale_f32(FXSendBuffer[indexL], reverb[nFX]->get_level(), FXSendBuffer[indexL], nFrames); - arm_add_f32(SampleBuffer[indexL], FXSendBuffer[indexL], SampleBuffer[indexL], nFrames); - // scale down and add right reverb buffer by reverb level - arm_scale_f32(FXSendBuffer[indexR], reverb[nFX]->get_level(), FXSendBuffer[indexR], nFrames); - arm_add_f32(SampleBuffer[indexR], FXSendBuffer[indexR], SampleBuffer[indexR], nFrames); + m_FXSpinLock.Acquire (); + fx_chain[nFX]->process(FXSendBuffer[0], FXSendBuffer[1], nFrames); - m_ReverbSpinLock.Release (); - } + arm_add_f32(SampleBuffer[0], FXSendBuffer[0], SampleBuffer[0], nFrames); + arm_add_f32(SampleBuffer[1], FXSendBuffer[1], SampleBuffer[1], nFrames); + m_FXSpinLock.Release (); } // END adding reverb @@ -2587,7 +2681,9 @@ void CMiniDexed::LoadPerformanceParameters(void) for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) { FX::TFXParameter param = FX::TFXParameter(nParam); - SetFXParameter (param, m_PerformanceConfig.GetFXParameter (param, nFX), nFX); + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + bool bSaveOnly = p.Flags & FX::FXComposite; + SetFXParameter (param, m_PerformanceConfig.GetFXParameter (param, nFX), nFX, bSaveOnly); } } @@ -3101,11 +3197,24 @@ std::string ToHz (int nValue, int nWidth) FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = { - {0, 1, 1, 1, "ReverbEnable", ToOnOff}, - {0, 99, 70, 1, "ReverbSize"}, - {0, 99, 50, 1, "ReverbHighDamp"}, - {0, 99, 50, 1, "ReverbLowDamp"}, - {0, 99, 30, 1, "ReverbLowPass"}, - {0, 99, 65, 1, "ReverbDiffusion"}, - {0, 99, 99, 1, "ReverbLevel"}, + {0, 100, 0, 1, "YKChorusMix"}, + {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, + {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, + {0, 100, 50, 1, "YKChorusLFORate1"}, + {0, 100, 83, 1, "YKChorusLFORate2"}, + {0, 100, 0, 1, "DreamDelayMix"}, + {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, + {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, + {0, 112, 36, 1, "DreamDelayTimeL", ToDelayTime}, + {0, 112, 36, 1, "DreamDelayTimeR", ToDelayTime}, + {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, + {0, 100, 60, 1, "DreamDelayFeedback"}, + {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, + {0, 1, 1, 1, "PlateReverbEnable", ToOnOff}, + {0, 99, 70, 1, "PlateReverbSize"}, + {0, 99, 50, 1, "PlateReverbHighDamp"}, + {0, 99, 50, 1, "PlateReverbLowDamp"}, + {0, 99, 30, 1, "PlateReverbLowPass"}, + {0, 99, 65, 1, "PlateReverbDiffusion"}, + {0, 99, 0, 1, "ReturnLevel"}, }; diff --git a/src/minidexed.h b/src/minidexed.h index c450bf79c..c004836c9 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -48,11 +48,11 @@ #include #include "common.h" #include "effect_mixer.hpp" -#include "effect_platervbstereo.h" #include "udpmididevice.h" #include "net/ftpdaemon.h" -#include "../Synth_Dexed/src/compressor.h" +#include "compressor.h" #include "effect_3bandeq.h" +#include "effect_chain.h" class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE @@ -212,7 +212,7 @@ class CMiniDexed bool DeletePerformance(unsigned nID); bool DoDeletePerformance(void); - void SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX); + void SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX, bool bSaveOnly = false); int GetFXParameter (FX::TFXParameter Parameter, unsigned nFX); // Must match the order in CUIMenu::TGParameter @@ -408,11 +408,11 @@ class CMiniDexed CPerformanceTimer m_GetChunkTimer; bool m_bProfileEnabled; - AudioEffectPlateReverb* reverb[CConfig::FXChains]; + AudioFXChain* fx_chain[CConfig::FXChains]; AudioStereoMixer* tg_mixer; AudioStereoMixer* sendfx_mixer[CConfig::FXChains]; - CSpinLock m_ReverbSpinLock; + CSpinLock m_FXSpinLock; AudioEffect3BandEQ m_MasterEQ[2]; CSpinLock m_EQSpinLock; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index edc6c892e..1ac2bca9d 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -302,13 +302,13 @@ bool CPerformanceConfig::Load (void) if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) { // setup Reverb to FX1 - m_nFXParameter[0][FX::FXParameterReverbEnable] = m_Properties.GetNumber ("ReverbEnable", 1); - m_nFXParameter[0][FX::FXParameterReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); - m_nFXParameter[0][FX::FXParameterReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); - m_nFXParameter[0][FX::FXParameterReverbLowDamp] = m_Properties.GetNumber ("ReverbLowDamp", 50); - m_nFXParameter[0][FX::FXParameterReverbLowPass] = m_Properties.GetNumber ("ReverbLowPass", 30); - m_nFXParameter[0][FX::FXParameterReverbDiffusion] = m_Properties.GetNumber ("ReverbDiffusion", 65); - m_nFXParameter[0][FX::FXParameterReverbLevel] = m_Properties.GetNumber ("ReverbLevel", 99); + m_nFXParameter[0][FX::FXParameterPlateReverbEnable] = m_Properties.GetNumber ("ReverbEnable", 1); + m_nFXParameter[0][FX::FXParameterPlateReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); + m_nFXParameter[0][FX::FXParameterPlateReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); + m_nFXParameter[0][FX::FXParameterPlateReverbLowDamp] = m_Properties.GetNumber ("ReverbLowDamp", 50); + m_nFXParameter[0][FX::FXParameterPlateReverbLowPass] = m_Properties.GetNumber ("ReverbLowPass", 30); + m_nFXParameter[0][FX::FXParameterPlateReverbDiffusion] = m_Properties.GetNumber ("ReverbDiffusion", 65); + m_nFXParameter[0][FX::FXParameterReturnLevel] = m_Properties.GetNumber ("ReverbEnable", 1) ? m_Properties.GetNumber ("ReverbLevel", 99) : 0; } return bResult; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index f241eaa07..645862f49 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -108,23 +108,6 @@ const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = {0} }; -const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = -{ - {"Reverb", MenuHandler, s_ReverbMenu}, - {0}, -}; - -const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = -{ -#ifdef ARM_ALLOW_MULTI_CORE - {"SendFX1", MenuHandler, s_FXMenu, 0}, - {"SendFX2", MenuHandler, s_FXMenu, 1}, - {"EQ", MenuHandler, s_MasterEQMenu}, - {"Compressor", MenuHandler, s_MasterCompressorMenu}, -#endif - {0} -}; - const CUIMenu::TMenuItem CUIMenu::s_EditPitchBendMenu[] = { {"Bend Range", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendRange}, @@ -179,15 +162,55 @@ const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = #ifdef ARM_ALLOW_MULTI_CORE -const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = +const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = +{ + {"SendFX1", MenuHandler, s_FXMenu, 0}, + {"SendFX2", MenuHandler, s_FXMenu, 1}, + {"EQ", MenuHandler, s_MasterEQMenu}, + {"Compressor", MenuHandler, s_MasterCompressorMenu}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = +{ + {"Return Level", EditFXParameter2, 0, FX::FXParameterReturnLevel}, + {"YKChorus", MenuHandler, s_YKChorusMenu}, + {"DreamDelay", MenuHandler, s_DreamDelayMenu}, + {"PlateReverb", MenuHandler, s_PlateReverbMenu}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_YKChorusMenu[] = +{ + {"Mix", EditFXParameter2, 0, FX::FXParameterYKChorusMix}, + {"Enable I", EditFXParameter2, 0, FX::FXParameterYKChorusEnable1}, + {"Enable II", EditFXParameter2, 0, FX::FXParameterYKChorusEnable2}, + {"LFO Rate I", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate1}, + {"LFO Rate II", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate2}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = +{ + {"Mix", EditFXParameter2, 0, FX::FXParameterDreamDelayMix}, + {"Mode", EditFXParameter2, 0, FX::FXParameterDreamDelayMode}, + {"Time", EditFXParameter2, 0, FX::FXParameterDreamDelayTime}, + {"Time Left", EditFXParameter2, 0, FX::FXParameterDreamDelayTimeL}, + {"Time Right", EditFXParameter2, 0, FX::FXParameterDreamDelayTimeR}, + {"Tempo", EditFXParameter2, 0, FX::FXParameterDreamDelayTempo}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterDreamDelayFeedback}, + {"HighCut", EditFXParameter2, 0, FX::FXParameterDreamDelayHighCut}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = { - {"Enable", EditFXParameter2, 0, FX::FXParameterReverbEnable}, - {"Size", EditFXParameter2, 0, FX::FXParameterReverbSize}, - {"High damp", EditFXParameter2, 0, FX::FXParameterReverbHighDamp}, - {"Low damp", EditFXParameter2, 0, FX::FXParameterReverbLowDamp}, - {"Low pass", EditFXParameter2, 0, FX::FXParameterReverbLowPass}, - {"Diffusion", EditFXParameter2, 0, FX::FXParameterReverbDiffusion}, - {"Level", EditFXParameter2, 0, FX::FXParameterReverbLevel}, + {"Enable", EditFXParameter2, 0, FX::FXParameterPlateReverbEnable}, + {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize}, + {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp}, + {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp}, + {"Low pass", EditFXParameter2, 0, FX::FXParameterPlateReverbLowPass}, + {"Diffusion", EditFXParameter2, 0, FX::FXParameterPlateReverbDiffusion}, {0} }; @@ -1535,7 +1558,7 @@ std::string CUIMenu::ToHz (int nValue, int nWidth) void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) { #ifdef ARM_ALLOW_MULTI_CORE - if (m_pParentMenu == s_ReverbMenu || + if (m_pParentMenu == s_PlateReverbMenu || m_pParentMenu == s_MasterEQMenu || m_pParentMenu == s_MasterCompressorMenu || m_pCurrentMenu == s_TGMenu) diff --git a/src/uimenu.h b/src/uimenu.h index 37e34dc2e..c6bc999a6 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -170,7 +170,9 @@ class CUIMenu static const TMenuItem s_FXMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_EQMenu[]; - static const TMenuItem s_ReverbMenu[]; + static const TMenuItem s_YKChorusMenu[]; + static const TMenuItem s_DreamDelayMenu[]; + static const TMenuItem s_PlateReverbMenu[]; static const TMenuItem s_MasterEQMenu[]; static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; From aa1b8228e523367662e67d57eb3685d8c92ea550 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 22:13:33 +0200 Subject: [PATCH 078/136] update default reverb parameters based on suggestions from Banana71 --- src/minidexed.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index fb47fd31e..e0980a190 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -3210,11 +3210,11 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, {0, 100, 60, 1, "DreamDelayFeedback"}, {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, - {0, 1, 1, 1, "PlateReverbEnable", ToOnOff}, - {0, 99, 70, 1, "PlateReverbSize"}, - {0, 99, 50, 1, "PlateReverbHighDamp"}, - {0, 99, 50, 1, "PlateReverbLowDamp"}, - {0, 99, 30, 1, "PlateReverbLowPass"}, + {0, 1, 0, 1, "PlateReverbEnable", ToOnOff}, + {0, 99, 50, 1, "PlateReverbSize"}, + {0, 99, 25, 1, "PlateReverbHighDamp"}, + {0, 99, 25, 1, "PlateReverbLowDamp"}, + {0, 99, 85, 1, "PlateReverbLowPass"}, {0, 99, 65, 1, "PlateReverbDiffusion"}, {0, 99, 0, 1, "ReturnLevel"}, }; From ef9dedaf82c70af992f4fb5a70d4639ea55201b1 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 16 Aug 2025 22:27:33 +0200 Subject: [PATCH 079/136] effect_mixer: use x^2 for gain modify the FxSends also to use values matching to x^2 --- src/effect_mixer.hpp | 8 ++++---- src/minidexed.cpp | 2 +- src/performanceconfig.cpp | 9 +++++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 27bca94a9..ab153f19b 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -84,12 +84,12 @@ template class AudioMixer gain = MAX_GAIN; else if (gain < MIN_GAIN) gain = MIN_GAIN; - multiplier[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + multiplier[channel] = powf(gain, 2); } void gain(float32_t gain) { - float32_t gain4 = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + float32_t gain4 = powf(gain, 2); for (uint8_t i = 0; i < NN; i++) { @@ -148,7 +148,7 @@ template class AudioStereoMixer : public AudioMixer gain = MAX_GAIN; else if (gain < MIN_GAIN) gain = MIN_GAIN; - multiplier[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + multiplier[channel] = powf(gain, 2); mp_w[channel][0] = multiplier[channel] * panorama[channel][0]; mp_w[channel][1] = multiplier[channel] * panorama[channel][1]; @@ -156,7 +156,7 @@ template class AudioStereoMixer : public AudioMixer void gain(float32_t gain) { - float32_t gain4 = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + float32_t gain4 = powf(gain, 2); for (uint8_t i = 0; i < NN; i++) { diff --git a/src/minidexed.cpp b/src/minidexed.cpp index e0980a190..a35f5532d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -132,7 +132,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) { - m_nFXSend[i][nFX] = 50; + m_nFXSend[i][nFX] = 25; } m_bCompressorEnable[i] = 1; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 1ac2bca9d..7b8be3edb 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -21,8 +21,10 @@ // along with this program. If not, see . // #include +#include #include "performanceconfig.h" #include "mididevice.h" +#include "common.h" #include #include @@ -164,14 +166,17 @@ bool CPerformanceConfig::Load (void) for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) { PropertyName.Format ("FX%uSend%u", nFX+1, nTG+1); - m_nFXSend[nTG][nFX] = m_Properties.GetNumber (PropertyName, 50); + m_nFXSend[nTG][nFX] = m_Properties.GetNumber (PropertyName, 25); } // compatibility ReverbSend[n] => FX1Send[n] PropertyName.Format ("ReverbSend%u", nTG+1); if (m_Properties.IsSet (PropertyName) && CConfig::FXChains) { - m_nFXSend[nTG][0] = m_Properties.GetNumber (PropertyName, 50); + // the volume calculated by x^4, but FxSend uses x^2 + float32_t reverbSend = m_Properties.GetNumber (PropertyName, 50); + reverbSend = pow(mapfloat(reverbSend, 0.0f, 99.0f, 0.0f, 1.0f), 2); + m_nFXSend[nTG][0] = mapfloat(reverbSend, 0.0f, 1.0f, 0, 99); } PropertyName.Format ("PitchBendRange%u", nTG+1); From d95fa2c56dcfe7994e6d2595c39b8bf681e094d8 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 3 Nov 2025 16:40:13 +0100 Subject: [PATCH 080/136] performanceconfig: set FX2Send[n] = 0 by default --- src/performanceconfig.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 7b8be3edb..500aafea9 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -163,11 +163,11 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("NoteShift%u", nTG+1); m_nNoteShift[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) - { - PropertyName.Format ("FX%uSend%u", nFX+1, nTG+1); - m_nFXSend[nTG][nFX] = m_Properties.GetNumber (PropertyName, 25); - } + PropertyName.Format ("FX1Send%u", nTG+1); + m_nFXSend[nTG][0] = m_Properties.GetNumber (PropertyName, 25); + + PropertyName.Format ("FX2Send%u", nTG+1); + m_nFXSend[nTG][1] = m_Properties.GetNumber (PropertyName, 0); // compatibility ReverbSend[n] => FX1Send[n] PropertyName.Format ("ReverbSend%u", nTG+1); From 658bb7ec9b607cdc0d51ced760b3224110ca0ee8 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 18 Aug 2025 00:36:18 +0200 Subject: [PATCH 081/136] reverb: replace disable/enable with a dry/wet mixer --- src/effect.h | 2 +- src/effect_chain.h | 2 +- src/effect_platervbstereo.cpp | 13 ++++++------- src/effect_platervbstereo.h | 23 ++++++++++++++++++----- src/minidexed.cpp | 6 +++--- src/performanceconfig.cpp | 2 +- src/uimenu.cpp | 2 +- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/effect.h b/src/effect.h index 582f01676..361230bdb 100644 --- a/src/effect.h +++ b/src/effect.h @@ -18,7 +18,7 @@ class FX FXParameterDreamDelayTempo, FXParameterDreamDelayFeedback, FXParameterDreamDelayHighCut, - FXParameterPlateReverbEnable, + FXParameterPlateReverbMix, FXParameterPlateReverbSize, FXParameterPlateReverbHighDamp, FXParameterPlateReverbLowDamp, diff --git a/src/effect_chain.h b/src/effect_chain.h index 51997b25b..d2712eccb 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -22,7 +22,7 @@ class AudioFXChain { yk_chorus.process(inputL, inputR, len); dream_delay.process(inputL, inputR, len); - plate_reverb.doReverb(inputL, inputR, inputL, inputR, len); + plate_reverb.process(inputL, inputR, inputL, inputR, len); arm_scale_f32(inputL, level, inputL, len); arm_scale_f32(inputR, level, inputR, len); } diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index de4366397..8b0a6ce4a 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -85,6 +85,8 @@ const int16_t AudioWaveformSine[257] = { AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) { + set_mix(0.0f); + input_attn = 0.5f; in_allp_k = INP_ALLP_COEFF; @@ -213,7 +215,7 @@ void AudioEffectPlateReverb::reset() lfo2_phase_acc = 0; } -void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len) +void AudioEffectPlateReverb::process(const float32_t *inblockL, const float32_t *inblockR, float32_t *outblockL, float32_t *outblockR, uint16_t len) { float32_t input, acc, temp1, temp2; uint16_t temp16; @@ -225,10 +227,7 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t int64_t y; uint32_t idx; - if (bypass) - { - return; - } + if (wet == 0.0f) return; rv_time = rv_time_k; @@ -435,7 +434,7 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_l; master_lowpass_l += temp1 * master_lowpass_f; - rvbblockL[i] = master_lowpass_l; + outblockL[i] = dry * inblockL[i] + wet * master_lowpass_l; // Channel R #ifdef TAP1_MODULATED @@ -479,6 +478,6 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_r; master_lowpass_r += temp1 * master_lowpass_f; - rvbblockR[i] = master_lowpass_r; + outblockR[i] = dry * inblockR[i] + wet * master_lowpass_r; } } diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 476a132df..0e7c51083 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -60,7 +60,7 @@ class AudioEffectPlateReverb { public: AudioEffectPlateReverb(float32_t samplerate); - void doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR,uint16_t len); + void process(const float32_t *inblockL, const float32_t *inblockR, float32_t *outblockL, float32_t *outblockR, uint16_t len); void size(float n) { @@ -100,13 +100,26 @@ class AudioEffectPlateReverb } float32_t get_size(void) {return rv_time_k;} - bool get_bypass(void) {return bypass;} - void set_bypass(bool state) {bypass = state;}; - void tgl_bypass(void) {bypass ^=1;} + + void set_mix(float32_t value) + { + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } + } void reset(); private: - bool bypass = false; + float32_t mix, dry, wet; float32_t input_attn; float32_t in_allp_k; // input allpass coeff diff --git a/src/minidexed.cpp b/src/minidexed.cpp index a35f5532d..644e0d804 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1308,9 +1308,9 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; - case FX::FXParameterPlateReverbEnable: + case FX::FXParameterPlateReverbMix: m_FXSpinLock.Acquire (); - fx_chain[nFX]->plate_reverb.set_bypass (!nValue); + fx_chain[nFX]->plate_reverb.set_mix (nValue / 100.0f); m_FXSpinLock.Release (); break; @@ -3210,7 +3210,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, {0, 100, 60, 1, "DreamDelayFeedback"}, {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, - {0, 1, 0, 1, "PlateReverbEnable", ToOnOff}, + {0, 100, 0, 1, "PlateReverbMix"}, {0, 99, 50, 1, "PlateReverbSize"}, {0, 99, 25, 1, "PlateReverbHighDamp"}, {0, 99, 25, 1, "PlateReverbLowDamp"}, diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 500aafea9..26f7a72c4 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -307,7 +307,7 @@ bool CPerformanceConfig::Load (void) if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) { // setup Reverb to FX1 - m_nFXParameter[0][FX::FXParameterPlateReverbEnable] = m_Properties.GetNumber ("ReverbEnable", 1); + m_nFXParameter[0][FX::FXParameterPlateReverbMix] = m_Properties.GetNumber ("ReverbEnable", 1) ? 100 : 0; m_nFXParameter[0][FX::FXParameterPlateReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); m_nFXParameter[0][FX::FXParameterPlateReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); m_nFXParameter[0][FX::FXParameterPlateReverbLowDamp] = m_Properties.GetNumber ("ReverbLowDamp", 50); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 645862f49..61684fc72 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -205,7 +205,7 @@ const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = { - {"Enable", EditFXParameter2, 0, FX::FXParameterPlateReverbEnable}, + {"Mix", EditFXParameter2, 0, FX::FXParameterPlateReverbMix}, {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize}, {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp}, {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp}, From d9e39974bb977bd22bf7bc56e798c659958672f5 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 18 Aug 2025 12:59:36 +0200 Subject: [PATCH 082/136] mixer: doAddMix(): skip processing if multiplier is 0 --- src/effect_mixer.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index ab153f19b..6d5483ea6 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -194,19 +194,25 @@ template class AudioStereoMixer : public AudioMixer assert(in); - if (mp[channel][0] == mp_w[channel][0]) - arm_scale_f32(in, mp[channel][0], tmp, buffer_length); - else - scale_ramp_f32(in, &mp[channel][0], mp_w[channel][0], ramp, tmp, buffer_length); + if (mp[channel][0] != 0.0f || mp_w[channel][0] != 0.0f) + { + if (mp[channel][0] == mp_w[channel][0]) + arm_scale_f32(in, mp[channel][0], tmp, buffer_length); + else + scale_ramp_f32(in, &mp[channel][0], mp_w[channel][0], ramp, tmp, buffer_length); - arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); + arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); + } - if (mp[channel][1] == mp_w[channel][1]) - arm_scale_f32(in, mp[channel][1], tmp, buffer_length); - else - scale_ramp_f32(in, &mp[channel][1], mp_w[channel][1], ramp, tmp, buffer_length); + if (mp[channel][1] != 0.0f || mp_w[channel][1] != 0.0f) + { + if (mp[channel][1] == mp_w[channel][1]) + arm_scale_f32(in, mp[channel][1], tmp, buffer_length); + else + scale_ramp_f32(in, &mp[channel][1], mp_w[channel][1], ramp, tmp, buffer_length); - arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + } } void getMix(float32_t* bufferL, float32_t* bufferR) From 5a79ef17e9712d9e1831cfee7dae1a6b10299837 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 18 Aug 2025 17:26:46 +0200 Subject: [PATCH 083/136] add MixerDryLevel control --- src/minidexed.cpp | 9 +++++++++ src/minidexed.h | 1 + src/performanceconfig.cpp | 14 ++++++++++++++ src/performanceconfig.h | 5 +++++ src/uimenu.cpp | 10 ++++++---- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 644e0d804..52f0e3c81 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1183,6 +1183,11 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_EQSpinLock.Release(); break; + case ParameterMixerDryLevel: + nValue = constrain(nValue, 0, 99); + tg_mixer->gain(mapfloat(nValue,0,99,0.0f,1.0f)); + break; + default: assert (0); break; @@ -1976,6 +1981,8 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetMasterCompressorRelease (m_nParameter[ParameterMasterCompressorRelease]); m_PerformanceConfig.SetMasterCompressorHPFilterEnable (m_nParameter[ParameterMasterCompressorHPFilterEnable]); + m_PerformanceConfig.SetMixerDryLevel (m_nParameter[ParameterMixerDryLevel]); + if(m_bSaveAsDeault) { m_PerformanceConfig.SetNewPerformanceBank(0); @@ -2702,6 +2709,8 @@ void CMiniDexed::LoadPerformanceParameters(void) SetParameter (ParameterMasterCompressorRelease, m_PerformanceConfig.GetMasterCompressorRelease ()); SetParameter (ParameterMasterCompressorHPFilterEnable, m_PerformanceConfig.GetMasterCompressorHPFilterEnable ()); + SetParameter (ParameterMixerDryLevel, m_PerformanceConfig.GetMixerDryLevel ()); + m_UI.DisplayChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index c004836c9..e26e3c5d4 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -200,6 +200,7 @@ class CMiniDexed ParameterMasterEQGain, ParameterMasterEQLowMidFreq, ParameterMasterEQMidHighFreq, + ParameterMixerDryLevel, ParameterUnknown }; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 26f7a72c4..1c1c211a6 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -295,6 +295,8 @@ bool CPerformanceConfig::Load (void) m_nMasterCompressorRelease = m_Properties.GetNumber ("MasterCompressorRelease", 5); m_bMasterCompressorHPFilterEnable = m_Properties.GetNumber ("MasterCompressorHPFilterEnable", 0); + m_nMixerDryLevel = m_Properties.GetNumber ("MixerDryLevel", 99); + // Compatibility if (m_Properties.IsSet ("CompressorEnable") && m_Properties.GetNumber ("CompressorEnable", 1) == 0) { @@ -497,6 +499,8 @@ bool CPerformanceConfig::Save (void) m_Properties.SetNumber ("MasterCompressorRelease", m_nMasterCompressorRelease); m_Properties.SetNumber ("MasterCompressorHPFilterEnable", m_bMasterCompressorHPFilterEnable); + m_Properties.SetNumber ("MixerDryLevel", m_nMixerDryLevel); + return m_Properties.Save (); } @@ -862,6 +866,16 @@ void CPerformanceConfig::SetMasterCompressorHPFilterEnable (bool nValue) m_bMasterCompressorHPFilterEnable = nValue; } +unsigned CPerformanceConfig::GetMixerDryLevel () const +{ + return m_nMixerDryLevel; +} + +void CPerformanceConfig::SetMixerDryLevel (unsigned nValue) +{ + m_nMixerDryLevel = nValue; +} + // Pitch bender and portamento: void CPerformanceConfig::SetPitchBendRange (unsigned nValue, unsigned nTG) { diff --git a/src/performanceconfig.h b/src/performanceconfig.h index ee2074ef4..afd140161 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -168,6 +168,9 @@ class CPerformanceConfig // Performance configuration void SetMasterCompressorRelease (unsigned nValue); void SetMasterCompressorHPFilterEnable (bool nValue); + unsigned GetMixerDryLevel () const; + void SetMixerDryLevel (unsigned nValue); + bool VoiceDataFilled(unsigned nTG); bool ListPerformances(); //std::string m_DirName; @@ -276,6 +279,8 @@ class CPerformanceConfig // Performance configuration unsigned m_nMasterCompressorAttack; unsigned m_nMasterCompressorRelease; bool m_bMasterCompressorHPFilterEnable; + + unsigned m_nMixerDryLevel; }; #endif diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 61684fc72..4427ced30 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -164,10 +164,11 @@ const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { - {"SendFX1", MenuHandler, s_FXMenu, 0}, - {"SendFX2", MenuHandler, s_FXMenu, 1}, - {"EQ", MenuHandler, s_MasterEQMenu}, - {"Compressor", MenuHandler, s_MasterCompressorMenu}, + {"Dry Level", EditGlobalParameter, 0, CMiniDexed::ParameterMixerDryLevel}, + {"SendFX1", MenuHandler, s_FXMenu, 0}, + {"SendFX2", MenuHandler, s_FXMenu, 1}, + {"EQ", MenuHandler, s_MasterEQMenu}, + {"Compressor", MenuHandler, s_MasterCompressorMenu}, {0} }; @@ -325,6 +326,7 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {-24, 24, 1, TodB}, // ParameterMasterEQGain {0, 46, 1, ToHz}, // ParameterMasterEQLowMidFreq {28, 59, 1, ToHz}, // ParameterMasterEQMidHighFreq + {0, 99, 1}, // ParameterMixerDryLevel }; // must match CMiniDexed::TTGParameter From e77947247af2c725bc211f61a3d68f521817c240 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 18 Aug 2025 21:18:01 +0200 Subject: [PATCH 084/136] Menu: show mix values as Dry:Wet format --- src/minidexed.cpp | 23 ++++++++++++++++++++--- src/uimenu.cpp | 6 +++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 52f0e3c81..878df451b 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -3204,14 +3204,31 @@ std::string ToHz (int nValue, int nWidth) return buf; } +std::string ToDryWet (int nValue, int nWidth) +{ + unsigned dry, wet; + if (nValue <= 50) + { + dry = 100; + wet = nValue * 2; + } + else + { + dry = 100 - ((nValue - 50) * 2); + wet = 100; + } + + return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); +} + FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = { - {0, 100, 0, 1, "YKChorusMix"}, + {0, 100, 0, 1, "YKChorusMix", ToDryWet}, {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, {0, 100, 50, 1, "YKChorusLFORate1"}, {0, 100, 83, 1, "YKChorusLFORate2"}, - {0, 100, 0, 1, "DreamDelayMix"}, + {0, 100, 0, 1, "DreamDelayMix", ToDryWet}, {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, {0, 112, 36, 1, "DreamDelayTimeL", ToDelayTime}, @@ -3219,7 +3236,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, {0, 100, 60, 1, "DreamDelayFeedback"}, {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, - {0, 100, 0, 1, "PlateReverbMix"}, + {0, 100, 0, 1, "PlateReverbMix", ToDryWet}, {0, 99, 50, 1, "PlateReverbSize"}, {0, 99, 25, 1, "PlateReverbHighDamp"}, {0, 99, 25, 1, "PlateReverbLowDamp"}, diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 4427ced30..5e9a5185c 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -183,7 +183,7 @@ const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = const CUIMenu::TMenuItem CUIMenu::s_YKChorusMenu[] = { - {"Mix", EditFXParameter2, 0, FX::FXParameterYKChorusMix}, + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterYKChorusMix}, {"Enable I", EditFXParameter2, 0, FX::FXParameterYKChorusEnable1}, {"Enable II", EditFXParameter2, 0, FX::FXParameterYKChorusEnable2}, {"LFO Rate I", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate1}, @@ -193,7 +193,7 @@ const CUIMenu::TMenuItem CUIMenu::s_YKChorusMenu[] = const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = { - {"Mix", EditFXParameter2, 0, FX::FXParameterDreamDelayMix}, + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterDreamDelayMix}, {"Mode", EditFXParameter2, 0, FX::FXParameterDreamDelayMode}, {"Time", EditFXParameter2, 0, FX::FXParameterDreamDelayTime}, {"Time Left", EditFXParameter2, 0, FX::FXParameterDreamDelayTimeL}, @@ -206,7 +206,7 @@ const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = { - {"Mix", EditFXParameter2, 0, FX::FXParameterPlateReverbMix}, + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterPlateReverbMix}, {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize}, {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp}, {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp}, From 4b3e9f99396a77852d0ebf342936d5abb7640280 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 22 Aug 2025 19:53:52 +0200 Subject: [PATCH 085/136] Add AudioEffectCloudSeed --- .gitmodules | 3 + CloudSeedCore | 1 + src/Makefile | 1 + src/effect.h | 81 ++++ src/effect_chain.h | 7 + src/effect_cloudseed2.h | 937 ++++++++++++++++++++++++++++++++++++++ src/minidexed.cpp | 106 +++++ src/performanceconfig.cpp | 12 +- src/uimenu.cpp | 100 ++++ src/uimenu.h | 9 + 10 files changed, 1255 insertions(+), 2 deletions(-) create mode 160000 CloudSeedCore create mode 100644 src/effect_cloudseed2.h diff --git a/.gitmodules b/.gitmodules index 064ffe47b..f9dbe8367 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "CMSIS_5"] path = CMSIS_5 url = https://github.com/ARM-software/CMSIS_5 +[submodule "CloudSeedCore"] + path = CloudSeedCore + url = https://github.com/DreamDexed/CloudSeedCore diff --git a/CloudSeedCore b/CloudSeedCore new file mode 160000 index 000000000..57cec73a2 --- /dev/null +++ b/CloudSeedCore @@ -0,0 +1 @@ +Subproject commit 57cec73a2bcdef6f83e355ff55b6bcd696cc3148 diff --git a/src/Makefile b/src/Makefile index e1c96d17e..517bbcb96 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,6 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ + ../CloudSeedCore/DSP/Biquad.o ../CloudSeedCore/DSP/RandomBuffer.o ../CloudSeedCore/DSP/FastSin.o \ arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o diff --git a/src/effect.h b/src/effect.h index 361230bdb..fbc973407 100644 --- a/src/effect.h +++ b/src/effect.h @@ -24,6 +24,52 @@ class FX FXParameterPlateReverbLowDamp, FXParameterPlateReverbLowPass, FXParameterPlateReverbDiffusion, + FXParameterCloudSeed2Preset, + FXParameterCloudSeed2Interpolation, + FXParameterCloudSeed2LowCutEnabled, + FXParameterCloudSeed2HighCutEnabled, + FXParameterCloudSeed2InputMix, + FXParameterCloudSeed2LowCut, + FXParameterCloudSeed2HighCut, + FXParameterCloudSeed2DryOut, + FXParameterCloudSeed2EarlyOut, + FXParameterCloudSeed2LateOut, + FXParameterCloudSeed2TapEnabled, + FXParameterCloudSeed2TapCount, + FXParameterCloudSeed2TapDecay, + FXParameterCloudSeed2TapPredelay, + FXParameterCloudSeed2TapLength, + FXParameterCloudSeed2EarlyDiffuseEnabled, + FXParameterCloudSeed2EarlyDiffuseCount, + FXParameterCloudSeed2EarlyDiffuseDelay, + FXParameterCloudSeed2EarlyDiffuseModAmount, + FXParameterCloudSeed2EarlyDiffuseFeedback, + FXParameterCloudSeed2EarlyDiffuseModRate, + FXParameterCloudSeed2LateMode, + FXParameterCloudSeed2LateLineCount, + FXParameterCloudSeed2LateDiffuseEnabled, + FXParameterCloudSeed2LateDiffuseCount, + FXParameterCloudSeed2LateLineSize, + FXParameterCloudSeed2LateLineModAmount, + FXParameterCloudSeed2LateDiffuseDelay, + FXParameterCloudSeed2LateDiffuseModAmount, + FXParameterCloudSeed2LateLineDecay, + FXParameterCloudSeed2LateLineModRate, + FXParameterCloudSeed2LateDiffuseFeedback, + FXParameterCloudSeed2LateDiffuseModRate, + FXParameterCloudSeed2EqLowShelfEnabled, + FXParameterCloudSeed2EqHighShelfEnabled, + FXParameterCloudSeed2EqLowpassEnabled, + FXParameterCloudSeed2EqLowFreq, + FXParameterCloudSeed2EqHighFreq, + FXParameterCloudSeed2EqCutoff, + FXParameterCloudSeed2EqLowGain, + FXParameterCloudSeed2EqHighGain, + FXParameterCloudSeed2EqCrossSeed, + FXParameterCloudSeed2SeedTap, + FXParameterCloudSeed2SeedDiffusion, + FXParameterCloudSeed2SeedDelay, + FXParameterCloudSeed2SeedPostDiffusion, FXParameterReturnLevel, FXParameterUnknown, }; @@ -42,4 +88,39 @@ class FX }; static FX::FXParameterType s_FXParameter[]; + + static constexpr const char *s_CS2PresetNames[] = { + "Init", + "FXDivineInspiration", + "FXLawsOfPhysics", + "FXSlowBraaam", + "FXTheUpsideDown", + "LBigSoundStage", + "LDiffusionCyclone", + "LScreamIntoTheVoid", + "M90sDigitalReverb", + "MAiryAmbience", + "MDarkPlate", + "MGhostly", + "MTappedLines", + "SFastAttack", + "SSmallPlate", + "SSnappyAttack", + }; + static constexpr unsigned cs2_preset_num = sizeof s_CS2PresetNames / sizeof *s_CS2PresetNames; + + static std::string getCS2PresetName (int nValue, int nWidth) + { + assert (nValue >= 0 && (unsigned)nValue < cs2_preset_num); + return s_CS2PresetNames[nValue]; + } + + static unsigned getIDFromCS2PresetName(const char *presetName) + { + for (unsigned i = 0; i < cs2_preset_num; ++i) + if (strcmp(s_CS2PresetNames[i], presetName) == 0) + return i; + + return 0; + } }; diff --git a/src/effect_chain.h b/src/effect_chain.h index d2712eccb..9bab4db77 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -1,5 +1,6 @@ #pragma once +#include "effect_cloudseed2.h" #include "effect_dreamdelay.h" #include "effect_platervbstereo.h" #include "effect_ykchorus.h" @@ -11,6 +12,7 @@ class AudioFXChain yk_chorus{samplerate}, dream_delay{samplerate}, plate_reverb{samplerate}, + cloudseed2{samplerate}, level{} { } @@ -23,6 +25,7 @@ class AudioFXChain yk_chorus.process(inputL, inputR, len); dream_delay.process(inputL, inputR, len); plate_reverb.process(inputL, inputR, inputL, inputR, len); + cloudseed2.process(inputL, inputR, len); arm_scale_f32(inputL, level, inputL, len); arm_scale_f32(inputR, level, inputR, len); } @@ -31,11 +34,15 @@ class AudioFXChain { dream_delay.resetState(); plate_reverb.reset(); + + cloudseed2.setRampedDown(); + cloudseed2.setNeedBufferClear(); } AudioEffectYKChorus yk_chorus; AudioEffectDreamDelay dream_delay; AudioEffectPlateReverb plate_reverb; + AudioEffectCloudSeed2 cloudseed2; private: float level; diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h new file mode 100644 index 000000000..c3da4c045 --- /dev/null +++ b/src/effect_cloudseed2.h @@ -0,0 +1,937 @@ +/* + * CloudSeed + * Ported from https://github.com/GhostNoteAudio/CloudSeedCore + */ + +#pragma once + +#define BUFFER_SIZE 128 +#define SLOW_CLEAR_SIZE 192000 // may need to be adjusted for other Pis + +#include "../CloudSeedCore/DSP/ReverbController.h" +#include + +namespace Parameter = Cloudseed::Parameter; + +static const float UInit[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.0, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.5, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.4957000017166138, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.146699994802475, + [Parameter::EarlyDiffuseModAmount] = 0.1559000015258789, + [Parameter::EarlyDiffuseFeedback] = 0.7066999673843384, + [Parameter::EarlyDiffuseModRate] = 0.1626999974250793, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.4599999785423279, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.2226999998092651, + [Parameter::LateLineSize] = 0.5, + [Parameter::LateLineModAmount] = 0.1560000032186508, + [Parameter::LateDiffuseDelay] = 0.510699987411499, + [Parameter::LateDiffuseModAmount] = 0.1600999981164932, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.1652999967336655, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1507000029087067, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3199999928474426, + [Parameter::EqHighFreq] = 0.5151999592781067, + [Parameter::EqCutoff] = 0.8260999917984009, + [Parameter::EqLowGain] = 0.8495000004768372, + [Parameter::EqHighGain] = 0.8504999876022339, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.01009999960660934, + [Parameter::SeedDiffusion] = 0.05059999972581863, + [Parameter::SeedDelay] = 0.1002999991178513, + [Parameter::SeedPostDiffusion] = 0.1500999927520752, +}; + +static const float FXDivineInspiration[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.687999963760376, + [Parameter::LateLineModAmount] = 0.7547000050544739, + [Parameter::LateDiffuseDelay] = 0.6279999613761902, + [Parameter::LateDiffuseModAmount] = 0.4614000022411346, + [Parameter::LateLineDecay] = 0.8199999928474426, + [Parameter::LateLineModRate] = 0.6279999613761902, + [Parameter::LateDiffuseFeedback] = 0.6319999694824219, + [Parameter::LateDiffuseModRate] = 0.3267000019550323, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float FXLawsOfPhysics[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7999999523162842, + [Parameter::LateOut] = 0.6439999938011169, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 1.0, + [Parameter::TapDecay] = 0.5040000081062317, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.7706999778747559, + [Parameter::EarlyDiffuseModAmount] = 0.6158999800682068, + [Parameter::EarlyDiffuseFeedback] = 0.5026999711990356, + [Parameter::EarlyDiffuseModRate] = 0.3666999936103821, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3240000009536743, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5759999752044678, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float FXSlowBraaam[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.1319999992847443, + [Parameter::LowCut] = 0.3599999845027924, + [Parameter::HighCut] = 0.1400000005960464, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6839999556541443, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5839999914169312, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7759999632835388, + [Parameter::EarlyDiffuseDelay] = 0.4986999928951263, + [Parameter::EarlyDiffuseModAmount] = 0.4838999807834625, + [Parameter::EarlyDiffuseFeedback] = 0.5467000007629395, + [Parameter::EarlyDiffuseModRate] = 0.3026999831199646, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.1519999951124191, + [Parameter::LateDiffuseDelay] = 0.363999992609024, + [Parameter::LateDiffuseModAmount] = 0.4387999773025513, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.7106999754905701, + [Parameter::LateDiffuseModRate] = 0.1826999932527542, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.5813999772071838, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8479999899864197, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float FXTheUpsideDown[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 0.3759999871253967, + [Parameter::DryOut] = 0.7080000042915344, + [Parameter::EarlyOut] = 0.9559999704360962, + [Parameter::LateOut] = 0.6279999613761902, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.1599999964237213, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.9466999769210815, + [Parameter::EarlyDiffuseModAmount] = 0.5598999857902527, + [Parameter::EarlyDiffuseFeedback] = 0.510699987411499, + [Parameter::EarlyDiffuseModRate] = 0.4587000012397766, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3919999897480011, + [Parameter::LateLineModAmount] = 0.3319999873638153, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.1412999927997589, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.1319999992847443, + [Parameter::SeedTap] = 0.8539999723434448, + [Parameter::SeedDiffusion] = 0.1129999980330467, + [Parameter::SeedDelay] = 0.3800999820232391, + [Parameter::SeedPostDiffusion] = 0.2633000016212463, +}; + +static const float LBigSoundStage[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.687999963760376, + [Parameter::LateOut] = 0.7559999823570251, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4172999858856201, + [Parameter::EarlyDiffuseDelay] = 0.6947000026702881, + [Parameter::EarlyDiffuseModAmount] = 0.3425999879837036, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.3506999909877777, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6240000128746033, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 1.0, + [Parameter::LateLineSize] = 0.2479999959468842, + [Parameter::LateLineModAmount] = 0.0, + [Parameter::LateDiffuseDelay] = 0.1759999990463257, + [Parameter::LateDiffuseModAmount] = 0.1959999948740005, + [Parameter::LateLineDecay] = 0.4120000004768372, + [Parameter::LateLineModRate] = 0.0, + [Parameter::LateDiffuseFeedback] = 0.8840000033378601, + [Parameter::LateDiffuseModRate] = 0.2586999833583832, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.2639999985694885, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.9720000028610229, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float LDiffusionCyclone[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0746999979019165, + [Parameter::LowCut] = 0.1292999982833862, + [Parameter::HighCut] = 0.6119999885559082, + [Parameter::DryOut] = 0.9079999923706055, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2132999897003174, + [Parameter::EarlyDiffuseDelay] = 0.2906999886035919, + [Parameter::EarlyDiffuseModAmount] = 0.1145999953150749, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2226999998092651, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.3199999928474426, + [Parameter::LateLineModAmount] = 0.2586999833583832, + [Parameter::LateDiffuseDelay] = 0.3759999871253967, + [Parameter::LateDiffuseModAmount] = 0.2893999814987183, + [Parameter::LateLineDecay] = 0.7519999742507935, + [Parameter::LateLineModRate] = 0.2239999920129776, + [Parameter::LateDiffuseFeedback] = 0.7080000042915344, + [Parameter::LateDiffuseModRate] = 0.2506999969482422, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.0, + [Parameter::SeedDiffusion] = 0.1219999939203262, + [Parameter::SeedDelay] = 0.3039999902248383, + [Parameter::SeedPostDiffusion] = 0.3409999907016754, +}; + +static const float LScreamIntoTheVoid[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.4852999746799469, + [Parameter::DryOut] = 0.6998999714851379, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.3999999761581421, + [Parameter::LateLineModAmount] = 0.146699994802475, + [Parameter::LateDiffuseDelay] = 0.3519999980926514, + [Parameter::LateDiffuseModAmount] = 0.3653999865055084, + [Parameter::LateLineDecay] = 0.7199999690055847, + [Parameter::LateLineModRate] = 0.1959999948740005, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.5012999773025513, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.07299999892711639, + [Parameter::SeedDelay] = 0.1939999908208847, + [Parameter::SeedPostDiffusion] = 0.3039999902248383, +}; + +static const float M90sDigitalReverb[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.4959999918937683, + [Parameter::LateOut] = 0.6173999905586243, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.3120000064373016, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MAiryAmbience[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.07069999724626541, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.9785999655723572, + [Parameter::EarlyOut] = 0.5559999942779541, + [Parameter::LateOut] = 0.4280999898910522, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2360000014305115, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.1079999953508377, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.5879999995231628, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1959999948740005, + [Parameter::EqHighFreq] = 0.7013999819755554, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.687999963760376, + [Parameter::EqHighGain] = 0.2746999859809875, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MDarkPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.6399999856948853, + [Parameter::HighCut] = 0.2933000028133392, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6613999605178833, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4693999886512756, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.6345999836921692, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MGhostly[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 0.1920000016689301, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7199999690055847, + [Parameter::LateOut] = 0.4799999892711639, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.03599999845027924, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.7080000042915344, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.1560000032186508, + [Parameter::EarlyDiffuseDelay] = 0.5986999869346619, + [Parameter::EarlyDiffuseModAmount] = 0.927899956703186, + [Parameter::EarlyDiffuseFeedback] = 0.6987000107765198, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.335999995470047, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.6413999795913696, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8319999575614929, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float MTappedLines[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.6092999577522278, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 1.0, + [Parameter::LateOut] = 0.5679999589920044, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06399999558925629, + [Parameter::TapDecay] = 0.7719999551773071, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.8586999773979187, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4839999973773956, + [Parameter::EarlyDiffuseDelay] = 0.2307000011205673, + [Parameter::EarlyDiffuseModAmount] = 0.6678999662399292, + [Parameter::EarlyDiffuseFeedback] = 0.7426999807357788, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.515999972820282, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.171999990940094, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.2572999894618988, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.6599999666213989, + [Parameter::SeedTap] = 0.4639999866485596, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.09409999847412109, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float SFastAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.6800000071525574, + [Parameter::LateOut] = 0.5399999618530273, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06799999624490738, + [Parameter::TapDecay] = 0.9559999704360962, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.6520000100135803, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3079999983310699, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4079999923706055, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.4439999759197235, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSmallPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.687999963760376, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.3680000007152557, + [Parameter::LateOut] = 0.5281000137329102, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.543999969959259, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.7053999900817871, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.8906999826431274, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSnappyAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.3026999831199646, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.371999979019165, + [Parameter::LateOut] = 0.6319999694824219, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5239999890327454, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.3226999938488007, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2119999974966049, + [Parameter::EarlyDiffuseDelay] = 0.0, + [Parameter::EarlyDiffuseModAmount] = 0.2198999971151352, + [Parameter::EarlyDiffuseFeedback] = 0.7106999754905701, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3279999792575836, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.03199999779462814, + [Parameter::LateLineSize] = 0.3014000058174133, + [Parameter::LateLineModAmount] = 0.1159999966621399, + [Parameter::LateDiffuseDelay] = 0.3479999899864197, + [Parameter::LateDiffuseModAmount] = 0.2547999918460846, + [Parameter::LateLineDecay] = 0.2425999939441681, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7306999564170837, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.5879999995231628, + [Parameter::SeedDiffusion] = 0.2549999952316284, + [Parameter::SeedDelay] = 0.09809999912977219, + [Parameter::SeedPostDiffusion] = 0.189300000667572, +}; + +static const float *Presets[] = { + UInit, + FXDivineInspiration, + FXLawsOfPhysics, + FXSlowBraaam, + FXTheUpsideDown, + LBigSoundStage, + LDiffusionCyclone, + LScreamIntoTheVoid, + M90sDigitalReverb, + MAiryAmbience, + MDarkPlate, + MGhostly, + MTappedLines, + SFastAttack, + SSmallPlate, + SSnappyAttack, +}; + +class AudioEffectCloudSeed2 +{ +public: + static std::string GetLateMode (int nValue, int nWidth) + { + return nValue ? "Post" : "Pre"; + } + + AudioEffectCloudSeed2(float samplerate): + samplerate{samplerate}, + ramp_dt{10.0f / samplerate}, + engine{(int)samplerate}, + targetVol{}, + needBufferClear{}, + waitBufferClear{}, + needParameterLoad{}, + preset{}, + vol{} + { + } + + void setParameter(unsigned paramID, float param) + { + engine.SetParameter(paramID, param); + } + + float getParameter(unsigned paramID) + { + return engine.GetAllParameters()[paramID]; + } + + void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) + { + if (targetVol == 0.0f && vol > 0.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::max(0.0f, vol - ramp_dt); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (needBufferClear) + { + engine.StartSlowClear(); + needBufferClear = false; + waitBufferClear = true; + } + + if (waitBufferClear) + { + if (engine.SlowClearDone(SLOW_CLEAR_SIZE)) + waitBufferClear = false; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + return; + } + + if (needParameterLoad) + { + unsigned needParam = needParameterLoad; + unsigned paramID = Parameter::COUNT - needParam; + engine.SetParameter(paramID, Presets[preset][paramID]); + needParameterLoad = needParam - 1; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + if (!needParameterLoad) + targetVol = 1.0f; + + return; + } + + if (targetVol == 1.0f && vol < 1.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::min(vol + ramp_dt, 1.0f); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (isDisabled()) return; + + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + } + + void loadPreset(unsigned p) + { + preset = constrain(p, 0u, sizeof Presets / sizeof *Presets - 1); + + targetVol = 0.0f; + needBufferClear = true; + needParameterLoad = Parameter::COUNT; + } + + void setNeedBufferClear() + { + needBufferClear = true; + } + + void setRampedDown() + { + vol = 0.0f; + } + + bool isDisabled() + { + double *params = engine.GetAllParameters(); + return params[Parameter::DryOut] == 1.0f && params[Parameter::EarlyOut] == 0.0f && params[Parameter::LateOut] == 0.0f; + } + +private: + float samplerate; + float ramp_dt; + Cloudseed::ReverbController engine; + std::atomic targetVol; + std::atomic needBufferClear; + bool waitBufferClear; + std::atomic needParameterLoad; + std::atomic preset; + + std::atomic vol; +}; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 878df451b..bc03b067a 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1349,6 +1349,58 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; + case FX::FXParameterCloudSeed2Preset: + fx_chain[nFX]->cloudseed2.loadPreset (nValue); + break; + + case FX::FXParameterCloudSeed2Interpolation: + case FX::FXParameterCloudSeed2LowCutEnabled: + case FX::FXParameterCloudSeed2HighCutEnabled: + case FX::FXParameterCloudSeed2InputMix: + case FX::FXParameterCloudSeed2LowCut: + case FX::FXParameterCloudSeed2HighCut: + case FX::FXParameterCloudSeed2DryOut: + case FX::FXParameterCloudSeed2EarlyOut: + case FX::FXParameterCloudSeed2LateOut: + case FX::FXParameterCloudSeed2TapEnabled: + case FX::FXParameterCloudSeed2TapCount: + case FX::FXParameterCloudSeed2TapDecay: + case FX::FXParameterCloudSeed2TapPredelay: + case FX::FXParameterCloudSeed2TapLength: + case FX::FXParameterCloudSeed2EarlyDiffuseEnabled: + case FX::FXParameterCloudSeed2EarlyDiffuseCount: + case FX::FXParameterCloudSeed2EarlyDiffuseDelay: + case FX::FXParameterCloudSeed2EarlyDiffuseModAmount: + case FX::FXParameterCloudSeed2EarlyDiffuseFeedback: + case FX::FXParameterCloudSeed2EarlyDiffuseModRate: + case FX::FXParameterCloudSeed2LateMode: + case FX::FXParameterCloudSeed2LateLineCount: + case FX::FXParameterCloudSeed2LateDiffuseEnabled: + case FX::FXParameterCloudSeed2LateDiffuseCount: + case FX::FXParameterCloudSeed2LateLineSize: + case FX::FXParameterCloudSeed2LateLineModAmount: + case FX::FXParameterCloudSeed2LateDiffuseDelay: + case FX::FXParameterCloudSeed2LateDiffuseModAmount: + case FX::FXParameterCloudSeed2LateLineDecay: + case FX::FXParameterCloudSeed2LateLineModRate: + case FX::FXParameterCloudSeed2LateDiffuseFeedback: + case FX::FXParameterCloudSeed2LateDiffuseModRate: + case FX::FXParameterCloudSeed2EqLowShelfEnabled: + case FX::FXParameterCloudSeed2EqHighShelfEnabled: + case FX::FXParameterCloudSeed2EqLowpassEnabled: + case FX::FXParameterCloudSeed2EqLowFreq: + case FX::FXParameterCloudSeed2EqHighFreq: + case FX::FXParameterCloudSeed2EqCutoff: + case FX::FXParameterCloudSeed2EqLowGain: + case FX::FXParameterCloudSeed2EqHighGain: + case FX::FXParameterCloudSeed2EqCrossSeed: + case FX::FXParameterCloudSeed2SeedTap: + case FX::FXParameterCloudSeed2SeedDiffusion: + case FX::FXParameterCloudSeed2SeedDelay: + case FX::FXParameterCloudSeed2SeedPostDiffusion: + fx_chain[nFX]->cloudseed2.setParameter (Parameter - FX::FXParameterCloudSeed2Interpolation, mapfloat(nValue, p.Minimum, p.Maximum, 0.0f, 1.0f)); + break; + case FX::FXParameterReturnLevel: m_FXSpinLock.Acquire (); fx_chain[nFX]->set_level (nValue / 99.0f); @@ -1366,6 +1418,12 @@ int CMiniDexed::GetFXParameter (FX::TFXParameter Parameter, unsigned nFX) assert (nFX < CConfig::FXChains); assert (Parameter < FX::FXParameterUnknown); + if (Parameter >= FX::FXParameterCloudSeed2Interpolation && Parameter <= FX::FXParameterCloudSeed2SeedPostDiffusion) + { + const FX::FXParameterType &p = FX::s_FXParameter[Parameter]; + return mapfloat(fx_chain[nFX]->cloudseed2.getParameter (Parameter - FX::FXParameterCloudSeed2Interpolation), 0.0f, 1.0f, p.Minimum, p.Maximum); + } + return m_nFXParameter[nFX][Parameter]; } @@ -3221,6 +3279,8 @@ std::string ToDryWet (int nValue, int nWidth) return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); } +constexpr const char *FX::s_CS2PresetNames[]; + FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = { {0, 100, 0, 1, "YKChorusMix", ToDryWet}, @@ -3242,5 +3302,51 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {0, 99, 25, 1, "PlateReverbLowDamp"}, {0, 99, 85, 1, "PlateReverbLowPass"}, {0, 99, 65, 1, "PlateReverbDiffusion"}, + {0, FX::cs2_preset_num - 1, 0, 1, "CloudSeed2Preset", FX::getCS2PresetName, FX::FXComposite}, + {0, 1, 0, 1, "CloudSeed2Interpolation", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2LowCutEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2HighCutEnabled", ToOnOff}, + {0, 127, 0, 1, "CloudSeed2InputMix"}, + {0, 127, 0, 1, "CloudSeed2LowCut"}, + {0, 127, 127, 1, "CloudSeed2HighCut"}, + {0, 127, 127, 1, "CloudSeed2DryOut"}, + {0, 127, 0, 1, "CloudSeed2EarlyOut"}, + {0, 127, 0, 1, "CloudSeed2LateOut"}, + {0, 1, 0, 1, "CloudSeed2TapEnabled", ToOnOff}, + {0, 127, 64, 1, "CloudSeed2TapCount"}, + {0, 127, 127, 1, "CloudSeed2TapDecay"}, + {0, 127, 0, 1, "CloudSeed2TapPredelay"}, + {0, 127, 62, 1, "CloudSeed2TapLength"}, + {0, 1, 0, 1, "CloudSeed2EarlyDiffuseEnabled", ToOnOff}, + {1, 12, 4, 1, "CloudSeed2EarlyDiffuseCount"}, + {0, 127, 18, 1, "CloudSeed2EarlyDiffuseDelay"}, + {0, 127, 19, 1, "CloudSeed2EarlyDiffuseModAmount"}, + {0, 127, 89, 1, "CloudSeed2EarlyDiffuseFeedback"}, + {0, 127, 20, 1, "CloudSeed2EarlyDiffuseModRate"}, + {0, 1, 1, 1, "CloudSeed2LateMode", AudioEffectCloudSeed2::GetLateMode}, + {1, 12, 6, 1, "CloudSeed2LateLineCount"}, + {0, 1, 0, 1, "CloudSeed2LateDiffuseEnabled", ToOnOff}, + {1, 8, 2, 1, "CloudSeed2LateDiffuseCount"}, + {0, 127, 64, 1, "CloudSeed2LateLineSize"}, + {0, 127, 19, 1, "CloudSeed2LateLineModAmount"}, + {0, 127, 64, 1, "CloudSeed2LateDiffuseDelay"}, + {0, 127, 20, 1, "CloudSeed2LateDiffuseModAmount"}, + {0, 127, 62, 1, "CloudSeed2LateLineDecay"}, + {0, 127, 20, 1, "CloudSeed2LateLineModRate"}, + {0, 127, 90, 1, "CloudSeed2LateDiffuseFeedback"}, + {0, 127, 19, 1, "CloudSeed2LateDiffuseModRate"}, + {0, 1, 0, 1, "CloudSeed2EqLowShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqHighShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqLowpassEnabled", ToOnOff}, + {0, 127, 40, 1, "CloudSeed2EqLowFreq"}, + {0, 127, 65, 1, "CloudSeed2EqHighFreq"}, + {0, 127, 104, 1, "CloudSeed2EqCutoff"}, + {0, 127, 107, 1, "CloudSeed2EqLowGain"}, + {0, 127, 108, 1, "CloudSeed2EqHighGain"}, + {0, 127, 0, 1, "CloudSeed2EqCrossSeed"}, + {0, 127, 62, 1, "CloudSeed2SeedTap"}, + {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, + {0, 127, 12, 1, "CloudSeed2SeedDelay"}, + {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, {0, 99, 0, 1, "ReturnLevel"}, }; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 1c1c211a6..17ec99006 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -276,7 +276,11 @@ bool CPerformanceConfig::Load (void) const FX::FXParameterType &p = FX::s_FXParameter[nParam]; PropertyName.Format ("FX%u%s", nFX+1, p.Name); - m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); + + if (nParam == FX::FXParameterCloudSeed2Preset) + m_nFXParameter[nFX][nParam] = FX::getIDFromCS2PresetName(m_Properties.GetString (PropertyName, "")); + else + m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); } } @@ -480,7 +484,11 @@ bool CPerformanceConfig::Save (void) const FX::FXParameterType &p = FX::s_FXParameter[nParam]; PropertyName.Format ("FX%u%s", nFX+1, p.Name); - m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); + + if (nParam == FX::FXParameterCloudSeed2Preset) + m_Properties.SetString (PropertyName, FX::getCS2PresetName(m_nFXParameter[nFX][nParam], 0).c_str()); + else + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); } } diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 5e9a5185c..6d6dc3224 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -178,6 +178,7 @@ const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = {"YKChorus", MenuHandler, s_YKChorusMenu}, {"DreamDelay", MenuHandler, s_DreamDelayMenu}, {"PlateReverb", MenuHandler, s_PlateReverbMenu}, + {"CloudSeed2", MenuHandler, s_CloudSeed2Menu}, {0}, }; @@ -215,6 +216,105 @@ const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2Menu[] = +{ + {"Load Preset", EditFXParameter2, 0, FX::FXParameterCloudSeed2Preset}, + {"Dry Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2DryOut}, + {"Early Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyOut}, + {"Late Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateOut}, + {"Early FB", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseFeedback}, + {"Late FB", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseFeedback}, + {"Tap Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapDecay}, + {"Late Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineDecay}, + {"Late Lines", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineCount}, + {"Input", MenuHandler, s_CloudSeed2InputMenu}, + {"Multitap Delay", MenuHandler, s_CloudSeed2MultitapMenu}, + {"Early Diffusion", MenuHandler, s_CloudSeed2EarlyDiffusionMenu}, + {"Late Diffusion", MenuHandler, s_CloudSeed2LateDiffusionMenu}, + {"Late Lines", MenuHandler, s_CloudSeed2LateLineMenu}, + {"Low Shelf", MenuHandler, s_CloudSeed2LowShelfMenu}, + {"High Shelf", MenuHandler, s_CloudSeed2HighShelfMenu}, + {"Low Pass", MenuHandler, s_CloudSeed2LowPassMenu}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2InputMenu[] = +{ + {"Interpolation", EditFXParameter2, 0, FX::FXParameterCloudSeed2Interpolation}, + {"L/R Input Mix", EditFXParameter2, 0, FX::FXParameterCloudSeed2InputMix}, + {"High Cut Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2HighCutEnabled}, + {"High Cut", EditFXParameter2, 0, FX::FXParameterCloudSeed2HighCut}, + {"Low Cut Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2LowCutEnabled}, + {"Low Cut", EditFXParameter2, 0, FX::FXParameterCloudSeed2LowCut}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2MultitapMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapEnabled}, + {"Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapCount}, + {"Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapDecay}, + {"Predelay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapPredelay}, + {"Length", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapLength}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2EarlyDiffusionMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseEnabled}, + {"Stage Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseCount}, + {"Delay", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseDelay}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseFeedback}, + {"Mod Amount", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LateDiffusionMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseEnabled}, + {"Stage Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseCount}, + {"Delay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseDelay}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseFeedback}, + {"Mod Amount", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LateLineMenu[] = +{ + {"Mode", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateMode}, + {"Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineCount}, + {"Size", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineSize}, + {"Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineDecay}, + {"Mod Amt", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LowShelfMenu[] = +{ + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowShelfEnabled}, + {"Freq", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowFreq}, + {"Gain", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowGain}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2HighShelfMenu[] = +{ + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighShelfEnabled}, + {"Freq", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighFreq}, + {"Gain", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighGain}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LowPassMenu[] = +{ + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowpassEnabled}, + {"Cutoff", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqCutoff}, + {0}, +}; + const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = { {"Low Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLow}, diff --git a/src/uimenu.h b/src/uimenu.h index c6bc999a6..b77502ec8 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -173,6 +173,15 @@ class CUIMenu static const TMenuItem s_YKChorusMenu[]; static const TMenuItem s_DreamDelayMenu[]; static const TMenuItem s_PlateReverbMenu[]; + static const TMenuItem s_CloudSeed2Menu[]; + static const TMenuItem s_CloudSeed2InputMenu[]; + static const TMenuItem s_CloudSeed2MultitapMenu[]; + static const TMenuItem s_CloudSeed2EarlyDiffusionMenu[]; + static const TMenuItem s_CloudSeed2LateDiffusionMenu[]; + static const TMenuItem s_CloudSeed2LateLineMenu[]; + static const TMenuItem s_CloudSeed2LowShelfMenu[]; + static const TMenuItem s_CloudSeed2HighShelfMenu[]; + static const TMenuItem s_CloudSeed2LowPassMenu[]; static const TMenuItem s_MasterEQMenu[]; static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; From 5c89f136abb70b44109137d152c0b547e6998479 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 31 Oct 2025 01:01:49 +0100 Subject: [PATCH 086/136] add SendFX slots --- src/effect.h | 35 +++++++++++ src/effect_chain.h | 30 +++++++-- src/minidexed.cpp | 10 +++ src/performanceconfig.cpp | 39 +++++++++--- src/uimenu.cpp | 125 +++++++++++++++++++++++++++++++++++++- src/uimenu.h | 11 +++- 6 files changed, 236 insertions(+), 14 deletions(-) diff --git a/src/effect.h b/src/effect.h index fbc973407..2dff4d376 100644 --- a/src/effect.h +++ b/src/effect.h @@ -5,6 +5,9 @@ class FX enum TFXParameter { + FXParameterSlot0, + FXParameterSlot1, + FXParameterSlot2, FXParameterYKChorusMix, FXParameterYKChorusEnable1, FXParameterYKChorusEnable2, @@ -89,6 +92,38 @@ class FX static FX::FXParameterType s_FXParameter[]; + struct EffectType + { + const char *Name; + const unsigned MinID; + const unsigned MaxID; + }; + + static constexpr const EffectType s_effects[] = { + {"None"}, + {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusLFORate2}, + {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayHighCut}, + {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, + {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, + }; + static constexpr uint8_t effects_num = sizeof s_effects / sizeof *s_effects; + static constexpr uint8_t slots_num = 3; + + static std::string getEffectName (int nValue, int nWidth) + { + assert (nValue >= 0 && nValue < effects_num); + return s_effects[nValue].Name; + } + + static uint8_t getIDFromEffectName(const char* name) + { + for(uint8_t i = 0; i < effects_num; ++i) + if (strcmp(s_effects[i].Name, name) == 0) + return i; + + return 0; + } + static constexpr const char *s_CS2PresetNames[] = { "Init", "FXDivineInspiration", diff --git a/src/effect_chain.h b/src/effect_chain.h index 9bab4db77..3fc5925e8 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "effect_cloudseed2.h" #include "effect_dreamdelay.h" #include "effect_platervbstereo.h" @@ -8,11 +10,20 @@ class AudioFXChain { public: + typedef std::function process_t; + AudioFXChain(float samplerate): yk_chorus{samplerate}, dream_delay{samplerate}, plate_reverb{samplerate}, cloudseed2{samplerate}, + funcs{ + [this](float *inputL, float *inputR, uint16_t len) {}, + [this](float *inputL, float *inputR, uint16_t len) { yk_chorus.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { dream_delay.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { plate_reverb.process(inputL, inputR, inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { cloudseed2.process(inputL, inputR, len); }, + }, level{} { } @@ -22,10 +33,10 @@ class AudioFXChain void process (float *inputL, float *inputR, uint16_t len) { - yk_chorus.process(inputL, inputR, len); - dream_delay.process(inputL, inputR, len); - plate_reverb.process(inputL, inputR, inputL, inputR, len); - cloudseed2.process(inputL, inputR, len); + for (int i = 0; i < FX::slots_num; ++i) + if (uint8_t id = slots[i]) + funcs[id](inputL, inputR, len); + arm_scale_f32(inputL, level, inputL, len); arm_scale_f32(inputR, level, inputR, len); } @@ -39,11 +50,22 @@ class AudioFXChain cloudseed2.setNeedBufferClear(); } + void setSlot(uint8_t slot, uint8_t effect_id) + { + assert(slot < FX::slots_num); + assert(effect_id < FX::effects_num); + + slots[slot] = effect_id; + } + AudioEffectYKChorus yk_chorus; AudioEffectDreamDelay dream_delay; AudioEffectPlateReverb plate_reverb; AudioEffectCloudSeed2 cloudseed2; private: + std::atomic slots[FX::slots_num]; + const process_t funcs[FX::effects_num]; + float level; }; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index bc03b067a..4fa1c7e70 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1216,6 +1216,12 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne switch (Parameter) { + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + fx_chain[nFX]->setSlot(Parameter - FX::FXParameterSlot0, nValue); + break; + case FX::FXParameterYKChorusMix: m_FXSpinLock.Acquire (); fx_chain[nFX]->yk_chorus.setMix (nValue / 100.0f); @@ -3279,10 +3285,14 @@ std::string ToDryWet (int nValue, int nWidth) return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); } +constexpr const FX::EffectType FX::s_effects[]; constexpr const char *FX::s_CS2PresetNames[]; FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = { + {0, FX::effects_num - 1, 0, 1, "Slot1", FX::getEffectName}, + {0, FX::effects_num - 1, 0, 1, "Slot2", FX::getEffectName}, + {0, FX::effects_num - 1, 0, 1, "Slot3", FX::getEffectName}, {0, 100, 0, 1, "YKChorusMix", ToDryWet}, {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 17ec99006..6442d0c7e 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -277,7 +277,9 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("FX%u%s", nFX+1, p.Name); - if (nParam == FX::FXParameterCloudSeed2Preset) + if (nParam >= FX::FXParameterSlot0 && nParam <= FX::FXParameterSlot2) + m_nFXParameter[nFX][nParam] = FX::getIDFromEffectName(m_Properties.GetString (PropertyName, "")); + else if (nParam == FX::FXParameterCloudSeed2Preset) m_nFXParameter[nFX][nParam] = FX::getIDFromCS2PresetName(m_Properties.GetString (PropertyName, "")); else m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); @@ -313,6 +315,7 @@ bool CPerformanceConfig::Load (void) if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) { // setup Reverb to FX1 + m_nFXParameter[0][FX::FXParameterSlot0] = FX::getIDFromEffectName("PlateReverb"); m_nFXParameter[0][FX::FXParameterPlateReverbMix] = m_Properties.GetNumber ("ReverbEnable", 1) ? 100 : 0; m_nFXParameter[0][FX::FXParameterPlateReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); m_nFXParameter[0][FX::FXParameterPlateReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); @@ -479,17 +482,37 @@ bool CPerformanceConfig::Save (void) { CString PropertyName; - for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + for (unsigned nSlot = 0; nSlot < 3; ++nSlot) { - const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + unsigned nSlotParam = FX::FXParameterSlot0 + nSlot; + unsigned nEffectID = m_nFXParameter[nFX][nSlotParam]; + const FX::EffectType &effect = FX::s_effects[nEffectID]; - PropertyName.Format ("FX%u%s", nFX+1, p.Name); + PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[nSlotParam].Name); + m_Properties.SetString (PropertyName, effect.Name); + } - if (nParam == FX::FXParameterCloudSeed2Preset) - m_Properties.SetString (PropertyName, FX::getCS2PresetName(m_nFXParameter[nFX][nParam], 0).c_str()); - else - m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); + for (unsigned nSlot = 0; nSlot < 3; ++nSlot) + { + unsigned nSlotParam = FX::FXParameterSlot0 + nSlot; + unsigned nEffectID = m_nFXParameter[nFX][nSlotParam]; + const FX::EffectType &effect = FX::s_effects[nEffectID]; + + if (nEffectID == 0) continue; + + for (unsigned nParam = effect.MinID; nParam <= effect.MaxID; ++nParam) + { + PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[nParam].Name); + + if (nParam == FX::FXParameterCloudSeed2Preset) + m_Properties.SetString (PropertyName, FX::getCS2PresetName(m_nFXParameter[nFX][nParam], 0).c_str()); + else + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); + } } + + PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[FX::FXParameterReturnLevel].Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterReturnLevel]); } m_Properties.SetSignedNumber ("MasterEQLow", m_nMasterEQLow); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 6d6dc3224..2f063329d 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -174,7 +174,16 @@ const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = { + {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Return Level", EditFXParameter2, 0, FX::FXParameterReturnLevel}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_FXListMenu[] = +{ + {"None"}, {"YKChorus", MenuHandler, s_YKChorusMenu}, {"DreamDelay", MenuHandler, s_DreamDelayMenu}, {"PlateReverb", MenuHandler, s_PlateReverbMenu}, @@ -693,7 +702,8 @@ void CUIMenu::EventHandler (TMenuEvent Event) break; default: - (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); + if (m_pParentMenu[m_nCurrentMenuItem].Handler) + (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); break; } } @@ -724,9 +734,18 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem; pUIMenu->m_nCurrentMenuItem = pUIMenu->m_nCurrentSelection; pUIMenu->m_nCurrentSelection = 0; + + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect) + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect (pUIMenu, Event); break; case MenuEventStepDown: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepDown) + { + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepDown (pUIMenu, Event); + break; + } + if (pUIMenu->m_nCurrentSelection == 0) { // If in main mennu, wrap around @@ -757,6 +776,12 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) break; case MenuEventStepUp: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepUp) + { + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepUp (pUIMenu, Event); + break; + } + ++pUIMenu->m_nCurrentSelection; if (!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name) // more entries? { @@ -2052,6 +2077,104 @@ void CUIMenu::InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); } +#ifdef ARM_ALLOW_MULTI_CORE + +void CUIMenu::SelectCurrentEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + if (!nValue) return; + + assert ((size_t)nValue < sizeof s_FXListMenu / sizeof *s_FXListMenu); + + pUIMenu->m_nCurrentSelection = nValue; +} + +void CUIMenu::StepDownEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + int nValue = pUIMenu->m_nCurrentSelection; + int increment = rParam.Increment; + + while (true) + { + if (nValue - increment < rParam.Minimum) + { + increment = 0; + break; + } + + if (!FXSlotFilter(pUIMenu, Event, nValue - increment)) + break; + + increment += rParam.Increment; + } + + pUIMenu->m_nCurrentSelection -= increment; + + pUIMenu->m_pMiniDexed->SetFXParameter (Param, pUIMenu->m_nCurrentSelection, nFX); +} + +void CUIMenu::StepUpEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + int nValue = pUIMenu->m_nCurrentSelection; + int increment = rParam.Increment; + + while (true) + { + if (nValue + increment > rParam.Maximum) + { + increment = 0; + break; + } + + if (!FXSlotFilter(pUIMenu, Event, nValue + increment)) + break; + + increment += rParam.Increment; + } + + pUIMenu->m_nCurrentSelection += increment; + + pUIMenu->m_pMiniDexed->SetFXParameter (Param, pUIMenu->m_nCurrentSelection, nFX); +} + +bool CUIMenu::FXSlotFilter (CUIMenu *pUIMenu, TMenuEvent Event, int nValue) +{ + assert (pUIMenu); + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + + if (nValue == 0) return false; + + if (Param != FX::FXParameterSlot0 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot0, nFX)) + return true; + + if (Param != FX::FXParameterSlot1 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot1, nFX)) + return true; + + if (Param != FX::FXParameterSlot2 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot2, nFX)) + return true; + + return false; +} + +#endif + void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); diff --git a/src/uimenu.h b/src/uimenu.h index b77502ec8..179f0573d 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -33,7 +33,7 @@ class CUserInterface; class CUIMenu { private: - static const unsigned MaxMenuDepth = 5; + static const unsigned MaxMenuDepth = 6; public: enum TMenuEvent @@ -71,6 +71,8 @@ class CUIMenu const TMenuItem *MenuItem; unsigned Parameter; TMenuHandler* OnSelect; + TMenuHandler* StepDown; + TMenuHandler* StepUp; }; typedef std::string TToString (int nValue, int nWidth); @@ -144,6 +146,12 @@ class CUIMenu static void InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); static void InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); + + static void SelectCurrentEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static void StepDownEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static void StepUpEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static bool FXSlotFilter (CUIMenu *pUIMenu, TMenuEvent Event, int nValue); + private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; @@ -168,6 +176,7 @@ class CUIMenu static const TMenuItem s_MainMenu[]; static const TMenuItem s_TGMenu[]; static const TMenuItem s_FXMenu[]; + static const TMenuItem s_FXListMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_EQMenu[]; static const TMenuItem s_YKChorusMenu[]; From 1bdc2ae9d9d3d4b87699e8396c7f1e91e3534fc2 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 3 Nov 2025 14:17:13 +0100 Subject: [PATCH 087/136] CUserInterface::DisplayWrite: limit the lines to LCDColumns length --- src/userinterface.cpp | 84 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/src/userinterface.cpp b/src/userinterface.cpp index d65c9d30c..5dc1ce4fa 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -239,52 +239,64 @@ void CUserInterface::DisplayWrite (const char *pMenu, const char *pParam, const assert (pParam); assert (pValue); - CString Msg ("\x1B[H\E[?25l"); // cursor home and off + size_t nLineMaxLen = m_pConfig->GetLCDColumns (); - // first line - Msg.Append (pParam); + const char* pHdr = "\x1B[H\E[?25l"; // cursor home and off + size_t nHdrLen = strlen(pHdr); - size_t nLen = strlen (pParam) + strlen (pMenu); - if (nLen < m_pConfig->GetLCDColumns ()) - { - for (unsigned i = m_pConfig->GetLCDColumns ()-nLen; i > 0; i--) - { - Msg.Append (" "); - } - } + const char* pClear = "\x1B[K"; // clear end of line + size_t nClearLen = strlen(pClear); - Msg.Append (pMenu); + size_t nParamLen = std::min (nLineMaxLen, strlen (pParam)); + size_t nMenuLen = strlen (pMenu); + size_t nFill1Len = nLineMaxLen > nParamLen + nMenuLen ? + nLineMaxLen - nParamLen - nMenuLen : 1; - // second line - CString Value (" "); - if (bArrowDown) - { - Value = "<"; // arrow left character - } + nFill1Len = std:: min (nLineMaxLen - nParamLen, nFill1Len); + nMenuLen = std::min (nLineMaxLen - nParamLen - nFill1Len, nMenuLen); - Value.Append (pValue); + size_t nLine1Len = nParamLen + nFill1Len + nMenuLen; - if (bArrowUp) - { - if (Value.GetLength () < m_pConfig->GetLCDColumns ()-1) - { - for (unsigned i = m_pConfig->GetLCDColumns ()-Value.GetLength ()-1; i > 0; i--) - { - Value.Append (" "); - } - } + size_t nArrowsLen = 2; + size_t nValueLen = std::min (nLineMaxLen - nArrowsLen, strlen (pValue)); + size_t nFill2Len = bArrowUp ? nLineMaxLen - nArrowsLen - nValueLen : 0; + size_t nLine2Len = nValueLen + nFill2Len + nArrowsLen; - Value.Append (">"); // arrow right character - } + if (nLine2Len >= nLineMaxLen) + nClearLen = 0; - Msg.Append (Value); + size_t nOffset = 0; - if (Value.GetLength () < m_pConfig->GetLCDColumns ()) - { - Msg.Append ("\x1B[K"); // clear end of line - } + char pLines[nHdrLen + nLine1Len + nLine2Len + nClearLen + 1]; + + memcpy (pLines, pHdr, nHdrLen); + nOffset += nHdrLen; + + memcpy (pLines + nOffset, pParam, nParamLen); + nOffset += nParamLen; + + memset (pLines + nOffset, ' ', nFill1Len); + nOffset += nFill1Len; + + memcpy (pLines + nOffset, pMenu, nMenuLen); + nOffset += nMenuLen; + + pLines[nOffset++] = bArrowDown ? '<' : ' '; + + memcpy (pLines + nOffset, pValue, nValueLen); + nOffset += nValueLen; + + memset (pLines + nOffset, ' ', nFill2Len); + nOffset += nFill2Len; + + pLines[nOffset++] = bArrowUp ? '>' : ' '; + + memcpy (pLines + nOffset, pClear, nClearLen); + nOffset += nClearLen; + + pLines[nOffset++] = 0; - LCDWrite (Msg); + LCDWrite ((const char *)pLines); } void CUserInterface::LCDWrite (const char *pString) From f3e6c8cf708069e7a4e7b311986396e56e11884a Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 3 Nov 2025 16:41:24 +0100 Subject: [PATCH 088/136] performanceconfig: use the MasterCompressor as Minidexed performance Compressor --- src/dexedadapter.h | 2 +- src/minidexed.cpp | 2 +- src/performanceconfig.cpp | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 7a6a038fb..1214b4629 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -40,7 +40,7 @@ class CDexedAdapter : public Dexed Dexed (maxnotes, samplerate), EQ {samplerate}, Compr {(float)samplerate}, - m_bCompressorEnable {true} + m_bCompressorEnable {} { } diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 4fa1c7e70..b6e698962 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -135,7 +135,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nFXSend[i][nFX] = 25; } - m_bCompressorEnable[i] = 1; + m_bCompressorEnable[i] = 0; m_nCompressorPreGain[i] = 0; m_nCompressorThresh[i] = -20; m_nCompressorRatio[i] = 5; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 6442d0c7e..17ea32b36 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -228,7 +228,7 @@ bool CPerformanceConfig::Load (void) m_nAftertouchTarget[nTG] = m_Properties.GetNumber (PropertyName, 0); PropertyName.Format ("CompressorEnable%u", nTG+1); - m_bCompressorEnable[nTG] = m_Properties.GetNumber (PropertyName, 1); + m_bCompressorEnable[nTG] = m_Properties.GetNumber (PropertyName, 0); PropertyName.Format ("CompressorPreGain%u", nTG+1); m_nCompressorPreGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); @@ -304,11 +304,21 @@ bool CPerformanceConfig::Load (void) m_nMixerDryLevel = m_Properties.GetNumber ("MixerDryLevel", 99); // Compatibility - if (m_Properties.IsSet ("CompressorEnable") && m_Properties.GetNumber ("CompressorEnable", 1) == 0) + if (m_Properties.IsSet ("CompressorEnable")) { - for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) + if (m_Properties.GetNumber ("CompressorEnable", 1)) { - m_bCompressorEnable[nTG] = 0; + m_bMasterCompressorEnable = 1; + m_nMasterCompressorPreGain = 0; + m_nMasterCompressorThresh = -20; + m_nMasterCompressorRatio = 5; + m_nMasterCompressorAttack = 5; + m_nMasterCompressorRelease = 200; + m_bMasterCompressorHPFilterEnable = 1; + } + else + { + m_bMasterCompressorEnable = 0; } } From 1fe34a1424abbd81c81e6bd18e7d254594b838af Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 3 Nov 2025 17:19:04 +0100 Subject: [PATCH 089/136] UIMenu: add Mixer menu --- src/uimenu.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/uimenu.h | 3 +++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 2f063329d..7a9d80738 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -62,10 +62,10 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG16", MenuHandler, s_TGMenu, 15}, #endif #endif + {"Mixer", MenuHandler, s_MixerMenu}, #ifdef ARM_ALLOW_MULTI_CORE {"Effects", MenuHandler, s_EffectsMenu}, #endif - {"Master Volume", EditGlobalParameter, 0, CMiniDexed::ParameterMasterVolume}, {"Performance", MenuHandler, s_PerformanceMenu}, {0} }; @@ -160,11 +160,21 @@ const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_MixerMenu[] = +{ + {"Master Volume", EditGlobalParameter, 0, CMiniDexed::ParameterMasterVolume}, +#ifdef ARM_ALLOW_MULTI_CORE + {"Dry Level", EditGlobalParameter, 0, CMiniDexed::ParameterMixerDryLevel}, + {"FX1 Return", EditFXParameterG, 0, FX::FXParameterReturnLevel, .Parameter2=0}, + {"FX2 Return", EditFXParameterG, 0, FX::FXParameterReturnLevel, .Parameter2=1}, +#endif + {0} +}; + #ifdef ARM_ALLOW_MULTI_CORE const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { - {"Dry Level", EditGlobalParameter, 0, CMiniDexed::ParameterMixerDryLevel}, {"SendFX1", MenuHandler, s_FXMenu, 0}, {"SendFX2", MenuHandler, s_FXMenu, 1}, {"EQ", MenuHandler, s_MasterEQMenu}, @@ -1215,6 +1225,54 @@ void CUIMenu::EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) nValue > rParam.Minimum, nValue < rParam.Maximum); } +void CUIMenu::EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event) +{ + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + unsigned nFX = pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Parameter2; + + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + case MenuEventStepDown: + nValue -= rParam.Increment; + if (nValue < rParam.Minimum) + { + nValue = rParam.Minimum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + case MenuEventStepUp: + nValue += rParam.Increment; + if (nValue > rParam.Maximum) + { + nValue = rParam.Maximum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + default: + return; + } + + std::string FX = std::string("FX") + std::to_string (nFX+1); + + std::string Value = GetFXValueString (Param, + pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), + pUIMenu->m_pConfig->GetLCDColumns() - 2); + + pUIMenu->m_pUI->DisplayWrite (FX.c_str (), + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + Value.c_str (), + nValue > rParam.Minimum, nValue < rParam.Maximum); +} + void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; diff --git a/src/uimenu.h b/src/uimenu.h index 179f0573d..981be60b1 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -73,6 +73,7 @@ class CUIMenu TMenuHandler* OnSelect; TMenuHandler* StepDown; TMenuHandler* StepUp; + unsigned Parameter2; }; typedef std::string TToString (int nValue, int nWidth); @@ -92,6 +93,7 @@ class CUIMenu static void EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event); + static void EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event); static void EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event); @@ -177,6 +179,7 @@ class CUIMenu static const TMenuItem s_TGMenu[]; static const TMenuItem s_FXMenu[]; static const TMenuItem s_FXListMenu[]; + static const TMenuItem s_MixerMenu[]; static const TMenuItem s_EffectsMenu[]; static const TMenuItem s_EQMenu[]; static const TMenuItem s_YKChorusMenu[]; From b81f2efd9ab5ce45ae0c86ca5d2a0b809b08d716 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 4 Nov 2025 17:08:57 +0100 Subject: [PATCH 090/136] README: update status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6353b001a..97ad4368d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with th - [x] Master Compressor - [x] 3-band EQ (per TG and Master) - [x] TG-Link -- [ ] Two Effect Send with Chrous, Delay, Reverb +- [x] Two Effect Sends with YKChrous, DreamDelay, PlateReverb, CloudSeed2 - [ ] 8 channel mixer (Rpi4+) - [ ] Multiple parts (RPi4+) - [ ] Overlay Menu for easier parameter changes From e25cb4b6f4d64b24a613a3f443b2e235ee3b694c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 4 Nov 2025 17:14:54 +0100 Subject: [PATCH 091/136] PerformanceConfig: use MiniDexed compressor settings in MiniDexed compatibility mode --- src/performanceconfig.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 17ea32b36..1782b1289 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -306,20 +306,13 @@ bool CPerformanceConfig::Load (void) // Compatibility if (m_Properties.IsSet ("CompressorEnable")) { - if (m_Properties.GetNumber ("CompressorEnable", 1)) - { - m_bMasterCompressorEnable = 1; - m_nMasterCompressorPreGain = 0; - m_nMasterCompressorThresh = -20; - m_nMasterCompressorRatio = 5; - m_nMasterCompressorAttack = 5; - m_nMasterCompressorRelease = 200; - m_bMasterCompressorHPFilterEnable = 1; - } - else - { - m_bMasterCompressorEnable = 0; - } + m_bMasterCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1); + m_nMasterCompressorPreGain = 0; + m_nMasterCompressorThresh = -20; + m_nMasterCompressorRatio = 5; + m_nMasterCompressorAttack = 5; + m_nMasterCompressorRelease = 200; + m_bMasterCompressorHPFilterEnable = 1; } if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) From 865bfbbd02b4ef0204b39e02c09628f6d59bf51b Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 4 Nov 2025 16:10:33 +0100 Subject: [PATCH 092/136] status menu --- src/uimenu.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/uimenu.h | 4 +++ 2 files changed, 78 insertions(+) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 7a9d80738..02d606472 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -28,6 +28,7 @@ #include "config.h" #include #include +#include #include #include @@ -62,6 +63,7 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG16", MenuHandler, s_TGMenu, 15}, #endif #endif + {"Status", MenuHandler, s_StatusMenu}, {"Mixer", MenuHandler, s_MixerMenu}, #ifdef ARM_ALLOW_MULTI_CORE {"Effects", MenuHandler, s_EffectsMenu}, @@ -606,6 +608,70 @@ const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_StatusMenu[] = +{ + {"CPU Temp", ShowCPUTemp, 0, 0}, + {"CPU Speed", ShowCPUSpeed, 0, 0}, + {0} +}; + +void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + char info[17]; + snprintf(info, sizeof(info), "%d/%d C", pCPUT->GetTemperature (), pCPUT->GetMaxTemperature ()); + + const char *pMenuName = + pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] + [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; + + pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + info, + false, false); + + CTimer::Get ()->StartKernelTimer (MSEC2HZ (1000), TimerHandlerUpdate, 0, pUIMenu); +} + +void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + char info[17]; + snprintf(info, sizeof(info), "%d/%d MHz", pCPUT->GetClockRate () / 1000000, pCPUT->GetMaxClockRate() / 1000000); + + const char *pMenuName = + pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] + [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; + + pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + info, + false, false); + + CTimer::Get ()->StartKernelTimer (MSEC2HZ (1000), TimerHandlerUpdate, 0, pUIMenu); +} CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), @@ -2104,6 +2170,14 @@ void CUIMenu::TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pCont pThis->EventHandler (MenuEventBack); } +void CUIMenu::TimerHandlerUpdate (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + CUIMenu *pThis = static_cast (pContext); + assert (pThis); + + pThis->EventHandler (MenuEventUpdate); +} + void CUIMenu::TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext) { CUIMenu *pThis = static_cast (pContext); diff --git a/src/uimenu.h b/src/uimenu.h index 981be60b1..e1be5f2d1 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -102,6 +102,8 @@ class CUIMenu static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event); static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); static std::string GetTGValueString (unsigned nTGParameter, int nValue, int nWidth); @@ -142,6 +144,7 @@ class CUIMenu void TGUpDownHandler (TMenuEvent Event); static void TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext); + static void TimerHandlerUpdate (TKernelTimerHandle hTimer, void *pParam, void *pContext); static void InputTxt (CUIMenu *pUIMenu, TMenuEvent Event); static void TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext); @@ -204,6 +207,7 @@ class CUIMenu static const TMenuItem s_EditPortamentoMenu[]; static const TMenuItem s_EditNoteLimitMenu[]; static const TMenuItem s_PerformanceMenu[]; + static const TMenuItem s_StatusMenu[]; static const TMenuItem s_ModulationMenu[]; static const TMenuItem s_ModulationMenuParameters[]; From bb661dbc69f5c0620d2ff6cd944b7b08cb5e3434 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 5 Nov 2025 16:14:15 +0100 Subject: [PATCH 093/136] CMiniDexed: use the compressor ratio value 31 as infinity --- src/minidexed.cpp | 8 ++++---- src/minidexed.h | 2 ++ src/uimenu.cpp | 7 +++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b6e698962..4e557687e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1105,10 +1105,10 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) break; case ParameterMasterCompressorRatio: - nValue=constrain(nValue,1,20); + nValue=constrain(nValue,1,(int)CompressorRatioInf); m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_MasterCompressor[i].setCompressionRatio(nValue); + m_MasterCompressor[i].setCompressionRatio(nValue == CompressorRatioInf ? INFINITY : nValue); m_MasterCompressorSpinLock.Release (); break; @@ -2093,13 +2093,13 @@ void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) { - ratio = constrain (ratio, 1u, 20u); + ratio = constrain (ratio, 1u, CMiniDexed::CompressorRatioInf); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG assert (m_pTG[nTG]); m_nCompressorRatio[nTG] = ratio; - m_pTG[nTG]->Compr.setCompressionRatio (ratio); + m_pTG[nTG]->Compr.setCompressionRatio (ratio == CompressorRatioInf ? INFINITY : ratio); m_UI.ParameterChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index e26e3c5d4..841846527 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -204,6 +204,8 @@ class CMiniDexed ParameterUnknown }; + static const unsigned CompressorRatioInf = 31; + void SetParameter (TParameter Parameter, int nValue); int GetParameter (TParameter Parameter); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 02d606472..fae2b3293 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -437,7 +437,7 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, 1, 1, ToOnOff}, // ParameterMasterCompressorEnable {-20, 20, 1, TodB}, // ParameterMasterCompressorPreGain {-60, 0, 1, TodBFS}, // ParameterMasterCompressorThresh - {1, 20, 1, ToRatio}, // ParameterMasterCompressorRatio + {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // ParameterMasterCompressorRatio {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorAttack {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorRelease {0, 1, 1, ToOnOff}, // ParameterMasterCompressorHPFilterEnable @@ -494,7 +494,7 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable {-20, 20, 1, TodB}, // TGParameterCompressorPreGain {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh - {1, 20, 1, ToRatio}, // TGParameterCompressorRatio + {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // TGParameterCompressorRatio {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain @@ -1791,6 +1791,9 @@ std::string CUIMenu::ToMillisec (int nValue, int nWidth) std::string CUIMenu::ToRatio (int nValue, int nWidth) { + if (nValue == CMiniDexed::CompressorRatioInf) + return "INF:1"; + return std::to_string (nValue) + ":1"; } From 98522dcf60c9b086f792bf3625d05670661b057c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 5 Nov 2025 16:15:29 +0100 Subject: [PATCH 094/136] CMiniDexed: set max compressor release parameter to 2000 ms --- src/minidexed.cpp | 4 ++-- src/uimenu.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 4e557687e..2043b49c8 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1121,7 +1121,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) break; case ParameterMasterCompressorRelease: - nValue=constrain(nValue,0,1000); + nValue=constrain(nValue,0,2000); m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) m_MasterCompressor[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); @@ -2117,7 +2117,7 @@ void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) { - release = constrain (release, 0u, 1000u); + release = constrain (release, 0u, 2000u); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG diff --git a/src/uimenu.cpp b/src/uimenu.cpp index fae2b3293..e5932c112 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -439,7 +439,7 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {-60, 0, 1, TodBFS}, // ParameterMasterCompressorThresh {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // ParameterMasterCompressorRatio {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorAttack - {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorRelease + {0, 2000, 5, ToMillisec}, // ParameterMasterCompressorRelease {0, 1, 1, ToOnOff}, // ParameterMasterCompressorHPFilterEnable {-24, 24, 1, TodB}, // ParameterMasterEQLow {-24, 24, 1, TodB}, // ParameterMasterEQMid @@ -496,7 +496,7 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // TGParameterCompressorRatio {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack - {0, 1000, 5, ToMillisec}, // TGParameterCompressorRelease + {0, 2000, 5, ToMillisec}, // TGParameterCompressorRelease {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain {-24, 24, 1, TodB}, // TGParameterEQLow {-24, 24, 1, TodB}, // TGParameterEQMid From 370027008fc7cd154e2a098d342ecf0c60a619de Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 5 Nov 2025 16:15:51 +0100 Subject: [PATCH 095/136] CMiniDexed: set min compressor attack/release time to 1 ms --- src/minidexed.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2043b49c8..a09df506e 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1116,7 +1116,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) nValue=constrain(nValue,0,1000); m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_MasterCompressor[i].setAttack_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_MasterCompressor[i].setAttack_sec((nValue ?: 1) / 1000.0f, m_pConfig->GetSampleRate()); m_MasterCompressorSpinLock.Release (); break; @@ -1124,7 +1124,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) nValue=constrain(nValue,0,2000); m_MasterCompressorSpinLock.Acquire (); for (int i=0; i<2; ++i) - m_MasterCompressor[i].setRelease_sec(nValue / 1000.0f, m_pConfig->GetSampleRate()); + m_MasterCompressor[i].setRelease_sec((nValue ?: 1) / 1000.0f, m_pConfig->GetSampleRate()); m_MasterCompressorSpinLock.Release (); break; @@ -2111,7 +2111,7 @@ void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorAttack[nTG] = attack; - m_pTG[nTG]->Compr.setAttack_sec (attack / 1000.0, m_pConfig->GetSampleRate ()); + m_pTG[nTG]->Compr.setAttack_sec ((attack ?: 1) / 1000.0f, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } @@ -2123,7 +2123,7 @@ void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) assert (m_pTG[nTG]); m_nCompressorRelease[nTG] = release; - m_pTG[nTG]->Compr.setRelease_sec (release / 1000.0, m_pConfig->GetSampleRate ()); + m_pTG[nTG]->Compr.setRelease_sec ((release ?: 1) / 1000.0, m_pConfig->GetSampleRate ()); m_UI.ParameterChanged (); } From 730e25c2d7dc58a96009f8da99b7959ef5d3dda3 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 5 Nov 2025 16:24:11 +0100 Subject: [PATCH 096/136] PerformanceConfig: refine compressor settings in MiniDexed compatibility mode --- src/performanceconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 1782b1289..f13e9d50f 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -308,9 +308,9 @@ bool CPerformanceConfig::Load (void) { m_bMasterCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1); m_nMasterCompressorPreGain = 0; - m_nMasterCompressorThresh = -20; + m_nMasterCompressorThresh = -7; m_nMasterCompressorRatio = 5; - m_nMasterCompressorAttack = 5; + m_nMasterCompressorAttack = 0; m_nMasterCompressorRelease = 200; m_bMasterCompressorHPFilterEnable = 1; } From fa4fee3c87a831280c29c8d0aec70fa1bffc20cf Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 10 Nov 2025 02:38:20 +0100 Subject: [PATCH 097/136] CUIMenu: show TG-Link in Voice menu --- src/uimenu.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index e5932c112..cb79f6397 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1036,6 +1036,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterProgram, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -1093,26 +1094,22 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) } else { // Format: 000:000 TG1 (bank:voice padded, TGx right-aligned) int nBank = pUIMenu->m_pMiniDexed->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG); - std::string left = "000"; - left += std::to_string(nBank+1); - left = left.substr(left.length()-3,3); - left += ":"; + std::string voice = "000"; + voice += std::to_string(nBank+1); + voice = voice.substr(voice.length()-3,3); + voice += ":"; std::string voiceNum = "000"; voiceNum += std::to_string(nValue+1); voiceNum = voiceNum.substr(voiceNum.length()-3,3); - left += voiceNum; + voice += voiceNum; - std::string tgLabel = "TG" + std::to_string(nTG+1); - unsigned lcdCols = pUIMenu->m_pConfig->GetLCDColumns(); - unsigned pad = 0; - if (lcdCols > left.length() + tgLabel.length()) - pad = lcdCols - (unsigned)(left.length() + tgLabel.length()); - std::string topLine = left + std::string(pad, ' ') + tgLabel; + std::string TG = "TG" + std::to_string(nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); - pUIMenu->m_pUI->DisplayWrite (topLine.c_str(), - "", + pUIMenu->m_pUI->DisplayWrite (TG.c_str(), + voice.c_str(), Value.c_str(), nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank); } From c2bb6e5e1e3f9f89b18aef7d0e7901bb8b77de74 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 6 Nov 2025 23:51:10 +0100 Subject: [PATCH 098/136] CUIMenu: ShowCPU*: retrieve values from CStatus --- src/minidexed.cpp | 5 +++++ src/minidexed.h | 3 +++ src/status.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++ src/uimenu.cpp | 16 ++++++++----- 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/status.h diff --git a/src/minidexed.cpp b/src/minidexed.cpp index a09df506e..2cddf19c8 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -523,6 +523,9 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) m_GetChunkTimer.Dump (); pScheduler->Yield(); } + + m_Status.Update(); + if (m_pNet) { UpdateNetwork(); } @@ -3285,6 +3288,8 @@ std::string ToDryWet (int nValue, int nWidth) return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); } +CStatus *CStatus::s_pThis = 0; + constexpr const FX::EffectType FX::s_effects[]; constexpr const char *FX::s_CS2PresetNames[]; diff --git a/src/minidexed.h b/src/minidexed.h index 841846527..a55b70ea5 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -47,6 +47,7 @@ #include "net/mdnspublisher.h" #include #include "common.h" +#include "status.h" #include "effect_mixer.hpp" #include "udpmididevice.h" #include "net/ftpdaemon.h" @@ -423,6 +424,8 @@ class CMiniDexed Compressor m_MasterCompressor[2]; CSpinLock m_MasterCompressorSpinLock; + CStatus m_Status; + // Network CNetSubSystem* m_pNet; CNetDevice* m_pNetDevice; diff --git a/src/status.h b/src/status.h new file mode 100644 index 000000000..b35800441 --- /dev/null +++ b/src/status.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +class CStatus +{ +public: + CStatus (unsigned nUpdateSecs = 3): + nCPUMaxTemp{CCPUThrottle::Get ()->GetMaxTemperature ()}, + nCPUMaxClockRate{CCPUThrottle::Get ()->GetMaxClockRate ()}, + m_nUpdateTicks{nUpdateSecs*CLOCKHZ}, + m_nLastTicks{} + { + assert (s_pThis == 0); + s_pThis = this; + assert (s_pThis != 0); + } + + ~CStatus () + { + s_pThis = 0; + } + + void Update () + { + unsigned nTicks = CTimer::GetClockTicks (); + + if (nTicks - m_nLastTicks >= m_nUpdateTicks) + { + m_nLastTicks = nTicks; + + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + nCPUTemp = pCPUT->GetTemperature (); + nCPUClockRate = pCPUT->GetClockRate (); + } + } + + static CStatus *Get () + { + assert (s_pThis != 0); + return s_pThis; + } + + std::atomic nCPUTemp; + const unsigned nCPUMaxTemp; + std::atomic nCPUClockRate; + const unsigned nCPUMaxClockRate; + +private: + unsigned m_nUpdateTicks; + unsigned m_nLastTicks; + + static CStatus *s_pThis; +}; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index cb79f6397..5dd49693e 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -627,10 +627,10 @@ void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) return; } - CCPUThrottle *pCPUT = CCPUThrottle::Get (); + CStatus *pStatus = CStatus::Get (); char info[17]; - snprintf(info, sizeof(info), "%d/%d C", pCPUT->GetTemperature (), pCPUT->GetMaxTemperature ()); + snprintf(info, sizeof(info), "%d/%d C", pStatus->nCPUTemp.load(), pStatus->nCPUMaxTemp); const char *pMenuName = pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] @@ -641,7 +641,9 @@ void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) info, false, false); - CTimer::Get ()->StartKernelTimer (MSEC2HZ (1000), TimerHandlerUpdate, 0, pUIMenu); + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); } void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) @@ -656,10 +658,10 @@ void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) return; } - CCPUThrottle *pCPUT = CCPUThrottle::Get (); + CStatus *pStatus = CStatus::Get (); char info[17]; - snprintf(info, sizeof(info), "%d/%d MHz", pCPUT->GetClockRate () / 1000000, pCPUT->GetMaxClockRate() / 1000000); + snprintf(info, sizeof(info), "%d/%d MHz", pStatus->nCPUClockRate.load() / 1000000, pStatus->nCPUMaxClockRate / 1000000); const char *pMenuName = pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] @@ -670,7 +672,9 @@ void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) info, false, false); - CTimer::Get ()->StartKernelTimer (MSEC2HZ (1000), TimerHandlerUpdate, 0, pUIMenu); + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); } CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) From 47f1afec68e5d0fe3b914d117954c887d0b6ed42 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 20:36:56 +0100 Subject: [PATCH 099/136] effect: move functions and arrays into the appropriate files --- src/Makefile | 2 +- src/effect.cpp | 192 ++++++++++++++++++++++++++++++++++++++ src/effect.h | 59 ++---------- src/effect_cloudseed2.h | 46 ++++++++- src/minidexed.cpp | 140 --------------------------- src/performanceconfig.cpp | 13 ++- 6 files changed, 253 insertions(+), 199 deletions(-) create mode 100644 src/effect.cpp diff --git a/src/Makefile b/src/Makefile index 517bbcb96..1103783c2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ - effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ + effect.o effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ ../CloudSeedCore/DSP/Biquad.o ../CloudSeedCore/DSP/RandomBuffer.o ../CloudSeedCore/DSP/FastSin.o \ arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o diff --git a/src/effect.cpp b/src/effect.cpp new file mode 100644 index 000000000..77cbaba51 --- /dev/null +++ b/src/effect.cpp @@ -0,0 +1,192 @@ +#include + +#include "effect.h" +#include "effect_cloudseed2.h" +#include "midi.h" + +static std::string ToOnOff (int nValue, int nWidth) +{ + static const char *OnOff[] = {"Off", "On"}; + + assert ((unsigned) nValue < sizeof OnOff / sizeof OnOff[0]); + + return OnOff[nValue]; +} + +static std::string ToDelayMode (int nValue, int nWidth) +{ + static const char *Mode[] = {"Dual", "Crossover", "PingPong"}; + + assert ((unsigned) nValue < sizeof Mode / sizeof Mode[0]); + + return Mode[nValue]; +} + +static std::string ToDelayTime (int nValue, int nWidth) +{ + static const char *Sync[] = {"1/1", "1/1T", "1/2", "1/2T", "1/4", "1/4T", "1/8", "1/8T", "1/16", "1/16T", "1/32", "1/32T"}; + + assert (nValue >= 0 && nValue <= 112); + + if (nValue <= 100) + return std::to_string(nValue * 10) + " ms"; + + return Sync[nValue - 100 - 1]; +} + +static std::string ToBPM(int nValue, int nWidth) +{ + return std::to_string(nValue) + " BPM"; +} + +static std::string ToHz (int nValue, int nWidth) +{ + uint16_t hz = MIDI_EQ_HZ[nValue]; + char buf[20] = {}; + + if (hz < 1000) + return std::to_string (hz) + " Hz"; + + std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); + return buf; +} + +static std::string ToDryWet (int nValue, int nWidth) +{ + unsigned dry, wet; + if (nValue <= 50) + { + dry = 100; + wet = nValue * 2; + } + else + { + dry = 100 - ((nValue - 50) * 2); + wet = 100; + } + + return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); +} + +static std::string ToEffectName (int nValue, int nWidth) +{ + assert (nValue >= 0 && nValue < FX::effects_num); + return FX::s_effects[nValue].Name; +} + +FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = +{ + {0, FX::effects_num - 1, 0, 1, "Slot1", ToEffectName, FX::FXSaveAsString}, + {0, FX::effects_num - 1, 0, 1, "Slot2", ToEffectName, FX::FXSaveAsString}, + {0, FX::effects_num - 1, 0, 1, "Slot3", ToEffectName, FX::FXSaveAsString}, + {0, 100, 0, 1, "YKChorusMix", ToDryWet}, + {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, + {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, + {0, 100, 50, 1, "YKChorusLFORate1"}, + {0, 100, 83, 1, "YKChorusLFORate2"}, + {0, 100, 0, 1, "DreamDelayMix", ToDryWet}, + {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, + {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, + {0, 112, 36, 1, "DreamDelayTimeL", ToDelayTime}, + {0, 112, 36, 1, "DreamDelayTimeR", ToDelayTime}, + {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, + {0, 100, 60, 1, "DreamDelayFeedback"}, + {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, + {0, 100, 0, 1, "PlateReverbMix", ToDryWet}, + {0, 99, 50, 1, "PlateReverbSize"}, + {0, 99, 25, 1, "PlateReverbHighDamp"}, + {0, 99, 25, 1, "PlateReverbLowDamp"}, + {0, 99, 85, 1, "PlateReverbLowPass"}, + {0, 99, 65, 1, "PlateReverbDiffusion"}, + {0, AudioEffectCloudSeed2::presets_num - 1, 0, 1, "CloudSeed2Preset", AudioEffectCloudSeed2::getPresetName, FX::FXComposite | FX::FXSaveAsString}, + {0, 1, 0, 1, "CloudSeed2Interpolation", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2LowCutEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2HighCutEnabled", ToOnOff}, + {0, 127, 0, 1, "CloudSeed2InputMix"}, + {0, 127, 0, 1, "CloudSeed2LowCut"}, + {0, 127, 127, 1, "CloudSeed2HighCut"}, + {0, 127, 127, 1, "CloudSeed2DryOut"}, + {0, 127, 0, 1, "CloudSeed2EarlyOut"}, + {0, 127, 0, 1, "CloudSeed2LateOut"}, + {0, 1, 0, 1, "CloudSeed2TapEnabled", ToOnOff}, + {0, 127, 64, 1, "CloudSeed2TapCount"}, + {0, 127, 127, 1, "CloudSeed2TapDecay"}, + {0, 127, 0, 1, "CloudSeed2TapPredelay"}, + {0, 127, 62, 1, "CloudSeed2TapLength"}, + {0, 1, 0, 1, "CloudSeed2EarlyDiffuseEnabled", ToOnOff}, + {1, 12, 4, 1, "CloudSeed2EarlyDiffuseCount"}, + {0, 127, 18, 1, "CloudSeed2EarlyDiffuseDelay"}, + {0, 127, 19, 1, "CloudSeed2EarlyDiffuseModAmount"}, + {0, 127, 89, 1, "CloudSeed2EarlyDiffuseFeedback"}, + {0, 127, 20, 1, "CloudSeed2EarlyDiffuseModRate"}, + {0, 1, 1, 1, "CloudSeed2LateMode", AudioEffectCloudSeed2::GetLateMode}, + {1, 12, 6, 1, "CloudSeed2LateLineCount"}, + {0, 1, 0, 1, "CloudSeed2LateDiffuseEnabled", ToOnOff}, + {1, 8, 2, 1, "CloudSeed2LateDiffuseCount"}, + {0, 127, 64, 1, "CloudSeed2LateLineSize"}, + {0, 127, 19, 1, "CloudSeed2LateLineModAmount"}, + {0, 127, 64, 1, "CloudSeed2LateDiffuseDelay"}, + {0, 127, 20, 1, "CloudSeed2LateDiffuseModAmount"}, + {0, 127, 62, 1, "CloudSeed2LateLineDecay"}, + {0, 127, 20, 1, "CloudSeed2LateLineModRate"}, + {0, 127, 90, 1, "CloudSeed2LateDiffuseFeedback"}, + {0, 127, 19, 1, "CloudSeed2LateDiffuseModRate"}, + {0, 1, 0, 1, "CloudSeed2EqLowShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqHighShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqLowpassEnabled", ToOnOff}, + {0, 127, 40, 1, "CloudSeed2EqLowFreq"}, + {0, 127, 65, 1, "CloudSeed2EqHighFreq"}, + {0, 127, 104, 1, "CloudSeed2EqCutoff"}, + {0, 127, 107, 1, "CloudSeed2EqLowGain"}, + {0, 127, 108, 1, "CloudSeed2EqHighGain"}, + {0, 127, 0, 1, "CloudSeed2EqCrossSeed"}, + {0, 127, 62, 1, "CloudSeed2SeedTap"}, + {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, + {0, 127, 12, 1, "CloudSeed2SeedDelay"}, + {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, + {0, 99, 0, 1, "ReturnLevel"}, +}; + +constexpr const FX::EffectType FX::s_effects[]; + +uint8_t getIDFromEffectName(const char* name) +{ + for(uint8_t i = 0; i < FX::effects_num; ++i) + if (strcmp(FX::s_effects[i].Name, name) == 0) + return i; + + return 0; +} + +int FX::getIDFromName(TFXParameter param, const char* name) +{ + switch (param) + { + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + return getIDFromEffectName(name); + case FX::FXParameterCloudSeed2Preset: + return AudioEffectCloudSeed2::getIDFromPresetName(name); + default: + assert(false); + } + return 0; +} + +const char *FX::getNameFromID(TFXParameter param, int nID) +{ + switch (param) + { + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + assert (nID < FX::effects_num); + return FX::s_effects[nID].Name; + case FX::FXParameterCloudSeed2Preset: + return AudioEffectCloudSeed2::getPresetNameChar(nID); + default: + assert(false); + } + return 0; +} diff --git a/src/effect.h b/src/effect.h index 2dff4d376..ec1a167e8 100644 --- a/src/effect.h +++ b/src/effect.h @@ -1,7 +1,13 @@ +#pragma once + +#include +#include + class FX { public: - static const int FXComposite = 1 << 0; // updates multiple controls, it shouldn't update the controls at startup and performance load + static constexpr int FXComposite = 1 << 0; // updates multiple controls, it shouldn't update the controls at startup and performance load + static constexpr int FXSaveAsString = 1 << 1; // save this parameter as string in the performace file enum TFXParameter { @@ -109,53 +115,6 @@ class FX static constexpr uint8_t effects_num = sizeof s_effects / sizeof *s_effects; static constexpr uint8_t slots_num = 3; - static std::string getEffectName (int nValue, int nWidth) - { - assert (nValue >= 0 && nValue < effects_num); - return s_effects[nValue].Name; - } - - static uint8_t getIDFromEffectName(const char* name) - { - for(uint8_t i = 0; i < effects_num; ++i) - if (strcmp(s_effects[i].Name, name) == 0) - return i; - - return 0; - } - - static constexpr const char *s_CS2PresetNames[] = { - "Init", - "FXDivineInspiration", - "FXLawsOfPhysics", - "FXSlowBraaam", - "FXTheUpsideDown", - "LBigSoundStage", - "LDiffusionCyclone", - "LScreamIntoTheVoid", - "M90sDigitalReverb", - "MAiryAmbience", - "MDarkPlate", - "MGhostly", - "MTappedLines", - "SFastAttack", - "SSmallPlate", - "SSnappyAttack", - }; - static constexpr unsigned cs2_preset_num = sizeof s_CS2PresetNames / sizeof *s_CS2PresetNames; - - static std::string getCS2PresetName (int nValue, int nWidth) - { - assert (nValue >= 0 && (unsigned)nValue < cs2_preset_num); - return s_CS2PresetNames[nValue]; - } - - static unsigned getIDFromCS2PresetName(const char *presetName) - { - for (unsigned i = 0; i < cs2_preset_num; ++i) - if (strcmp(s_CS2PresetNames[i], presetName) == 0) - return i; - - return 0; - } + static const char *getNameFromID(TFXParameter param, int nID); + static int getIDFromName(TFXParameter param, const char* name); }; diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h index c3da4c045..00984b08c 100644 --- a/src/effect_cloudseed2.h +++ b/src/effect_cloudseed2.h @@ -800,6 +800,25 @@ static const float *Presets[] = { SSnappyAttack, }; +static const char *CS2PresetNames[] = { + "Init", + "FXDivineInspiration", + "FXLawsOfPhysics", + "FXSlowBraaam", + "FXTheUpsideDown", + "LBigSoundStage", + "LDiffusionCyclone", + "LScreamIntoTheVoid", + "M90sDigitalReverb", + "MAiryAmbience", + "MDarkPlate", + "MGhostly", + "MTappedLines", + "SFastAttack", + "SSmallPlate", + "SSnappyAttack", +}; + class AudioEffectCloudSeed2 { public: @@ -808,6 +827,30 @@ class AudioEffectCloudSeed2 return nValue ? "Post" : "Pre"; } + static std::string getPresetName (int nValue, int nWidth) + { + assert (nValue >= 0 && (unsigned)nValue < presets_num); + return CS2PresetNames[nValue]; + } + + static const char *getPresetNameChar (int nValue) + { + assert (nValue >= 0 && (unsigned)nValue < presets_num); + return CS2PresetNames[nValue]; + } + + static unsigned getIDFromPresetName(const char *presetName) + { + for (unsigned i = 0; i < presets_num; ++i) + if (strcmp(CS2PresetNames[i], presetName) == 0) + return i; + + return 0; + } + + static constexpr unsigned presets_num = sizeof CS2PresetNames / sizeof *CS2PresetNames; + + AudioEffectCloudSeed2(float samplerate): samplerate{samplerate}, ramp_dt{10.0f / samplerate}, @@ -900,7 +943,8 @@ class AudioEffectCloudSeed2 void loadPreset(unsigned p) { - preset = constrain(p, 0u, sizeof Presets / sizeof *Presets - 1); + assert(p < presets_num); + preset = p; targetVol = 0.0f; needBufferClear = true; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2cddf19c8..b8e200a72 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -3224,144 +3224,4 @@ bool CMiniDexed::InitNetwork() } } -std::string ToOnOff (int nValue, int nWidth) -{ - static const char *OnOff[] = {"Off", "On"}; - - assert ((unsigned) nValue < sizeof OnOff / sizeof OnOff[0]); - - return OnOff[nValue]; -} - -std::string ToDelayMode (int nValue, int nWidth) -{ - static const char *Mode[] = {"Dual", "Crossover", "PingPong"}; - - assert ((unsigned) nValue < sizeof Mode / sizeof Mode[0]); - - return Mode[nValue]; -} - -std::string ToDelayTime (int nValue, int nWidth) -{ - static const char *Sync[] = {"1/1", "1/1T", "1/2", "1/2T", "1/4", "1/4T", "1/8", "1/8T", "1/16", "1/16T", "1/32", "1/32T"}; - - assert (nValue >= 0 && nValue <= 112); - - if (nValue <= 100) - return std::to_string(nValue * 10) + " ms"; - - return Sync[nValue - 100 - 1]; -} - -std::string ToBPM(int nValue, int nWidth) -{ - return std::to_string(nValue) + " BPM"; -} - -std::string ToHz (int nValue, int nWidth) -{ - uint16_t hz = MIDI_EQ_HZ[nValue]; - char buf[20] = {}; - - if (hz < 1000) - return std::to_string (hz) + " Hz"; - - std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); - return buf; -} - -std::string ToDryWet (int nValue, int nWidth) -{ - unsigned dry, wet; - if (nValue <= 50) - { - dry = 100; - wet = nValue * 2; - } - else - { - dry = 100 - ((nValue - 50) * 2); - wet = 100; - } - - return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); -} - CStatus *CStatus::s_pThis = 0; - -constexpr const FX::EffectType FX::s_effects[]; -constexpr const char *FX::s_CS2PresetNames[]; - -FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = -{ - {0, FX::effects_num - 1, 0, 1, "Slot1", FX::getEffectName}, - {0, FX::effects_num - 1, 0, 1, "Slot2", FX::getEffectName}, - {0, FX::effects_num - 1, 0, 1, "Slot3", FX::getEffectName}, - {0, 100, 0, 1, "YKChorusMix", ToDryWet}, - {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, - {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, - {0, 100, 50, 1, "YKChorusLFORate1"}, - {0, 100, 83, 1, "YKChorusLFORate2"}, - {0, 100, 0, 1, "DreamDelayMix", ToDryWet}, - {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, - {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, - {0, 112, 36, 1, "DreamDelayTimeL", ToDelayTime}, - {0, 112, 36, 1, "DreamDelayTimeR", ToDelayTime}, - {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, - {0, 100, 60, 1, "DreamDelayFeedback"}, - {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, - {0, 100, 0, 1, "PlateReverbMix", ToDryWet}, - {0, 99, 50, 1, "PlateReverbSize"}, - {0, 99, 25, 1, "PlateReverbHighDamp"}, - {0, 99, 25, 1, "PlateReverbLowDamp"}, - {0, 99, 85, 1, "PlateReverbLowPass"}, - {0, 99, 65, 1, "PlateReverbDiffusion"}, - {0, FX::cs2_preset_num - 1, 0, 1, "CloudSeed2Preset", FX::getCS2PresetName, FX::FXComposite}, - {0, 1, 0, 1, "CloudSeed2Interpolation", ToOnOff}, - {0, 1, 0, 1, "CloudSeed2LowCutEnabled", ToOnOff}, - {0, 1, 0, 1, "CloudSeed2HighCutEnabled", ToOnOff}, - {0, 127, 0, 1, "CloudSeed2InputMix"}, - {0, 127, 0, 1, "CloudSeed2LowCut"}, - {0, 127, 127, 1, "CloudSeed2HighCut"}, - {0, 127, 127, 1, "CloudSeed2DryOut"}, - {0, 127, 0, 1, "CloudSeed2EarlyOut"}, - {0, 127, 0, 1, "CloudSeed2LateOut"}, - {0, 1, 0, 1, "CloudSeed2TapEnabled", ToOnOff}, - {0, 127, 64, 1, "CloudSeed2TapCount"}, - {0, 127, 127, 1, "CloudSeed2TapDecay"}, - {0, 127, 0, 1, "CloudSeed2TapPredelay"}, - {0, 127, 62, 1, "CloudSeed2TapLength"}, - {0, 1, 0, 1, "CloudSeed2EarlyDiffuseEnabled", ToOnOff}, - {1, 12, 4, 1, "CloudSeed2EarlyDiffuseCount"}, - {0, 127, 18, 1, "CloudSeed2EarlyDiffuseDelay"}, - {0, 127, 19, 1, "CloudSeed2EarlyDiffuseModAmount"}, - {0, 127, 89, 1, "CloudSeed2EarlyDiffuseFeedback"}, - {0, 127, 20, 1, "CloudSeed2EarlyDiffuseModRate"}, - {0, 1, 1, 1, "CloudSeed2LateMode", AudioEffectCloudSeed2::GetLateMode}, - {1, 12, 6, 1, "CloudSeed2LateLineCount"}, - {0, 1, 0, 1, "CloudSeed2LateDiffuseEnabled", ToOnOff}, - {1, 8, 2, 1, "CloudSeed2LateDiffuseCount"}, - {0, 127, 64, 1, "CloudSeed2LateLineSize"}, - {0, 127, 19, 1, "CloudSeed2LateLineModAmount"}, - {0, 127, 64, 1, "CloudSeed2LateDiffuseDelay"}, - {0, 127, 20, 1, "CloudSeed2LateDiffuseModAmount"}, - {0, 127, 62, 1, "CloudSeed2LateLineDecay"}, - {0, 127, 20, 1, "CloudSeed2LateLineModRate"}, - {0, 127, 90, 1, "CloudSeed2LateDiffuseFeedback"}, - {0, 127, 19, 1, "CloudSeed2LateDiffuseModRate"}, - {0, 1, 0, 1, "CloudSeed2EqLowShelfEnabled", ToOnOff}, - {0, 1, 0, 1, "CloudSeed2EqHighShelfEnabled", ToOnOff}, - {0, 1, 0, 1, "CloudSeed2EqLowpassEnabled", ToOnOff}, - {0, 127, 40, 1, "CloudSeed2EqLowFreq"}, - {0, 127, 65, 1, "CloudSeed2EqHighFreq"}, - {0, 127, 104, 1, "CloudSeed2EqCutoff"}, - {0, 127, 107, 1, "CloudSeed2EqLowGain"}, - {0, 127, 108, 1, "CloudSeed2EqHighGain"}, - {0, 127, 0, 1, "CloudSeed2EqCrossSeed"}, - {0, 127, 62, 1, "CloudSeed2SeedTap"}, - {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, - {0, 127, 12, 1, "CloudSeed2SeedDelay"}, - {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, - {0, 99, 0, 1, "ReturnLevel"}, -}; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index f13e9d50f..8ca946495 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -277,10 +277,8 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("FX%u%s", nFX+1, p.Name); - if (nParam >= FX::FXParameterSlot0 && nParam <= FX::FXParameterSlot2) - m_nFXParameter[nFX][nParam] = FX::getIDFromEffectName(m_Properties.GetString (PropertyName, "")); - else if (nParam == FX::FXParameterCloudSeed2Preset) - m_nFXParameter[nFX][nParam] = FX::getIDFromCS2PresetName(m_Properties.GetString (PropertyName, "")); + if (p.Flags & FX::FXSaveAsString) + m_nFXParameter[nFX][nParam] = FX::getIDFromName(FX::TFXParameter(nParam), m_Properties.GetString (PropertyName, "")); else m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); } @@ -318,7 +316,7 @@ bool CPerformanceConfig::Load (void) if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) { // setup Reverb to FX1 - m_nFXParameter[0][FX::FXParameterSlot0] = FX::getIDFromEffectName("PlateReverb"); + m_nFXParameter[0][FX::FXParameterSlot0] = FX::getIDFromName(FX::FXParameterSlot0, "PlateReverb"); m_nFXParameter[0][FX::FXParameterPlateReverbMix] = m_Properties.GetNumber ("ReverbEnable", 1) ? 100 : 0; m_nFXParameter[0][FX::FXParameterPlateReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); m_nFXParameter[0][FX::FXParameterPlateReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); @@ -505,10 +503,11 @@ bool CPerformanceConfig::Save (void) for (unsigned nParam = effect.MinID; nParam <= effect.MaxID; ++nParam) { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[nParam].Name); - if (nParam == FX::FXParameterCloudSeed2Preset) - m_Properties.SetString (PropertyName, FX::getCS2PresetName(m_nFXParameter[nFX][nParam], 0).c_str()); + if (p.Flags & FX::FXSaveAsString) + m_Properties.SetString (PropertyName, FX::getNameFromID(FX::TFXParameter(nParam), m_nFXParameter[nFX][nParam])); else m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); } From 1268b218b348e570c3c584077848c945d10d191d Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 21:09:44 +0100 Subject: [PATCH 100/136] effect_cloudseed2: move presets to cpp --- src/Makefile | 2 +- src/effect_cloudseed2.cpp | 792 +++++++++++++++++++++++++++++++++++ src/effect_cloudseed2.h | 849 ++------------------------------------ 3 files changed, 825 insertions(+), 818 deletions(-) create mode 100644 src/effect_cloudseed2.cpp diff --git a/src/Makefile b/src/Makefile index 1103783c2..4cae38b5a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ - effect.o effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ + effect.o effect_cloudseed2.o effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ ../CloudSeedCore/DSP/Biquad.o ../CloudSeedCore/DSP/RandomBuffer.o ../CloudSeedCore/DSP/FastSin.o \ arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o diff --git a/src/effect_cloudseed2.cpp b/src/effect_cloudseed2.cpp new file mode 100644 index 000000000..357468c54 --- /dev/null +++ b/src/effect_cloudseed2.cpp @@ -0,0 +1,792 @@ +#include "effect_cloudseed2.h" + +namespace Parameter = Cloudseed::Parameter; + +static const float UInit[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.0, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.5, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.4957000017166138, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.146699994802475, + [Parameter::EarlyDiffuseModAmount] = 0.1559000015258789, + [Parameter::EarlyDiffuseFeedback] = 0.7066999673843384, + [Parameter::EarlyDiffuseModRate] = 0.1626999974250793, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.4599999785423279, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.2226999998092651, + [Parameter::LateLineSize] = 0.5, + [Parameter::LateLineModAmount] = 0.1560000032186508, + [Parameter::LateDiffuseDelay] = 0.510699987411499, + [Parameter::LateDiffuseModAmount] = 0.1600999981164932, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.1652999967336655, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1507000029087067, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3199999928474426, + [Parameter::EqHighFreq] = 0.5151999592781067, + [Parameter::EqCutoff] = 0.8260999917984009, + [Parameter::EqLowGain] = 0.8495000004768372, + [Parameter::EqHighGain] = 0.8504999876022339, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.01009999960660934, + [Parameter::SeedDiffusion] = 0.05059999972581863, + [Parameter::SeedDelay] = 0.1002999991178513, + [Parameter::SeedPostDiffusion] = 0.1500999927520752, +}; + +static const float FXDivineInspiration[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.687999963760376, + [Parameter::LateLineModAmount] = 0.7547000050544739, + [Parameter::LateDiffuseDelay] = 0.6279999613761902, + [Parameter::LateDiffuseModAmount] = 0.4614000022411346, + [Parameter::LateLineDecay] = 0.8199999928474426, + [Parameter::LateLineModRate] = 0.6279999613761902, + [Parameter::LateDiffuseFeedback] = 0.6319999694824219, + [Parameter::LateDiffuseModRate] = 0.3267000019550323, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float FXLawsOfPhysics[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7999999523162842, + [Parameter::LateOut] = 0.6439999938011169, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 1.0, + [Parameter::TapDecay] = 0.5040000081062317, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.7706999778747559, + [Parameter::EarlyDiffuseModAmount] = 0.6158999800682068, + [Parameter::EarlyDiffuseFeedback] = 0.5026999711990356, + [Parameter::EarlyDiffuseModRate] = 0.3666999936103821, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3240000009536743, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5759999752044678, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float FXSlowBraaam[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.1319999992847443, + [Parameter::LowCut] = 0.3599999845027924, + [Parameter::HighCut] = 0.1400000005960464, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6839999556541443, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5839999914169312, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7759999632835388, + [Parameter::EarlyDiffuseDelay] = 0.4986999928951263, + [Parameter::EarlyDiffuseModAmount] = 0.4838999807834625, + [Parameter::EarlyDiffuseFeedback] = 0.5467000007629395, + [Parameter::EarlyDiffuseModRate] = 0.3026999831199646, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.1519999951124191, + [Parameter::LateDiffuseDelay] = 0.363999992609024, + [Parameter::LateDiffuseModAmount] = 0.4387999773025513, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.7106999754905701, + [Parameter::LateDiffuseModRate] = 0.1826999932527542, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.5813999772071838, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8479999899864197, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float FXTheUpsideDown[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 0.3759999871253967, + [Parameter::DryOut] = 0.7080000042915344, + [Parameter::EarlyOut] = 0.9559999704360962, + [Parameter::LateOut] = 0.6279999613761902, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.1599999964237213, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.9466999769210815, + [Parameter::EarlyDiffuseModAmount] = 0.5598999857902527, + [Parameter::EarlyDiffuseFeedback] = 0.510699987411499, + [Parameter::EarlyDiffuseModRate] = 0.4587000012397766, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3919999897480011, + [Parameter::LateLineModAmount] = 0.3319999873638153, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.1412999927997589, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.1319999992847443, + [Parameter::SeedTap] = 0.8539999723434448, + [Parameter::SeedDiffusion] = 0.1129999980330467, + [Parameter::SeedDelay] = 0.3800999820232391, + [Parameter::SeedPostDiffusion] = 0.2633000016212463, +}; + +static const float LBigSoundStage[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.687999963760376, + [Parameter::LateOut] = 0.7559999823570251, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4172999858856201, + [Parameter::EarlyDiffuseDelay] = 0.6947000026702881, + [Parameter::EarlyDiffuseModAmount] = 0.3425999879837036, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.3506999909877777, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6240000128746033, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 1.0, + [Parameter::LateLineSize] = 0.2479999959468842, + [Parameter::LateLineModAmount] = 0.0, + [Parameter::LateDiffuseDelay] = 0.1759999990463257, + [Parameter::LateDiffuseModAmount] = 0.1959999948740005, + [Parameter::LateLineDecay] = 0.4120000004768372, + [Parameter::LateLineModRate] = 0.0, + [Parameter::LateDiffuseFeedback] = 0.8840000033378601, + [Parameter::LateDiffuseModRate] = 0.2586999833583832, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.2639999985694885, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.9720000028610229, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float LDiffusionCyclone[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0746999979019165, + [Parameter::LowCut] = 0.1292999982833862, + [Parameter::HighCut] = 0.6119999885559082, + [Parameter::DryOut] = 0.9079999923706055, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2132999897003174, + [Parameter::EarlyDiffuseDelay] = 0.2906999886035919, + [Parameter::EarlyDiffuseModAmount] = 0.1145999953150749, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2226999998092651, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.3199999928474426, + [Parameter::LateLineModAmount] = 0.2586999833583832, + [Parameter::LateDiffuseDelay] = 0.3759999871253967, + [Parameter::LateDiffuseModAmount] = 0.2893999814987183, + [Parameter::LateLineDecay] = 0.7519999742507935, + [Parameter::LateLineModRate] = 0.2239999920129776, + [Parameter::LateDiffuseFeedback] = 0.7080000042915344, + [Parameter::LateDiffuseModRate] = 0.2506999969482422, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.0, + [Parameter::SeedDiffusion] = 0.1219999939203262, + [Parameter::SeedDelay] = 0.3039999902248383, + [Parameter::SeedPostDiffusion] = 0.3409999907016754, +}; + +static const float LScreamIntoTheVoid[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.4852999746799469, + [Parameter::DryOut] = 0.6998999714851379, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.3999999761581421, + [Parameter::LateLineModAmount] = 0.146699994802475, + [Parameter::LateDiffuseDelay] = 0.3519999980926514, + [Parameter::LateDiffuseModAmount] = 0.3653999865055084, + [Parameter::LateLineDecay] = 0.7199999690055847, + [Parameter::LateLineModRate] = 0.1959999948740005, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.5012999773025513, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.07299999892711639, + [Parameter::SeedDelay] = 0.1939999908208847, + [Parameter::SeedPostDiffusion] = 0.3039999902248383, +}; + +static const float M90sDigitalReverb[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.4959999918937683, + [Parameter::LateOut] = 0.6173999905586243, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.3120000064373016, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MAiryAmbience[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.07069999724626541, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.9785999655723572, + [Parameter::EarlyOut] = 0.5559999942779541, + [Parameter::LateOut] = 0.4280999898910522, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2360000014305115, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.1079999953508377, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.5879999995231628, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1959999948740005, + [Parameter::EqHighFreq] = 0.7013999819755554, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.687999963760376, + [Parameter::EqHighGain] = 0.2746999859809875, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MDarkPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.6399999856948853, + [Parameter::HighCut] = 0.2933000028133392, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6613999605178833, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4693999886512756, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.6345999836921692, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MGhostly[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 0.1920000016689301, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7199999690055847, + [Parameter::LateOut] = 0.4799999892711639, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.03599999845027924, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.7080000042915344, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.1560000032186508, + [Parameter::EarlyDiffuseDelay] = 0.5986999869346619, + [Parameter::EarlyDiffuseModAmount] = 0.927899956703186, + [Parameter::EarlyDiffuseFeedback] = 0.6987000107765198, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.335999995470047, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.6413999795913696, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8319999575614929, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float MTappedLines[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.6092999577522278, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 1.0, + [Parameter::LateOut] = 0.5679999589920044, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06399999558925629, + [Parameter::TapDecay] = 0.7719999551773071, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.8586999773979187, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4839999973773956, + [Parameter::EarlyDiffuseDelay] = 0.2307000011205673, + [Parameter::EarlyDiffuseModAmount] = 0.6678999662399292, + [Parameter::EarlyDiffuseFeedback] = 0.7426999807357788, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.515999972820282, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.171999990940094, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.2572999894618988, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.6599999666213989, + [Parameter::SeedTap] = 0.4639999866485596, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.09409999847412109, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float SFastAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.6800000071525574, + [Parameter::LateOut] = 0.5399999618530273, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06799999624490738, + [Parameter::TapDecay] = 0.9559999704360962, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.6520000100135803, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3079999983310699, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4079999923706055, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.4439999759197235, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSmallPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.687999963760376, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.3680000007152557, + [Parameter::LateOut] = 0.5281000137329102, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.543999969959259, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.7053999900817871, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.8906999826431274, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSnappyAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.3026999831199646, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.371999979019165, + [Parameter::LateOut] = 0.6319999694824219, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5239999890327454, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.3226999938488007, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2119999974966049, + [Parameter::EarlyDiffuseDelay] = 0.0, + [Parameter::EarlyDiffuseModAmount] = 0.2198999971151352, + [Parameter::EarlyDiffuseFeedback] = 0.7106999754905701, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3279999792575836, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.03199999779462814, + [Parameter::LateLineSize] = 0.3014000058174133, + [Parameter::LateLineModAmount] = 0.1159999966621399, + [Parameter::LateDiffuseDelay] = 0.3479999899864197, + [Parameter::LateDiffuseModAmount] = 0.2547999918460846, + [Parameter::LateLineDecay] = 0.2425999939441681, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7306999564170837, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.5879999995231628, + [Parameter::SeedDiffusion] = 0.2549999952316284, + [Parameter::SeedDelay] = 0.09809999912977219, + [Parameter::SeedPostDiffusion] = 0.189300000667572, +}; + +const float *AudioEffectCloudSeed2::Presets[] = { + UInit, + FXDivineInspiration, + FXLawsOfPhysics, + FXSlowBraaam, + FXTheUpsideDown, + LBigSoundStage, + LDiffusionCyclone, + LScreamIntoTheVoid, + M90sDigitalReverb, + MAiryAmbience, + MDarkPlate, + MGhostly, + MTappedLines, + SFastAttack, + SSmallPlate, + SSnappyAttack, +}; + +constexpr const char *AudioEffectCloudSeed2::PresetNames[]; diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h index 00984b08c..4be5edcd6 100644 --- a/src/effect_cloudseed2.h +++ b/src/effect_cloudseed2.h @@ -8,820 +8,36 @@ #define BUFFER_SIZE 128 #define SLOW_CLEAR_SIZE 192000 // may need to be adjusted for other Pis -#include "../CloudSeedCore/DSP/ReverbController.h" #include +#include -namespace Parameter = Cloudseed::Parameter; - -static const float UInit[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.0, - [Parameter::LowCut] = 0.0, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 1.0, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.0, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.5, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.4957000017166138, - [Parameter::EarlyDiffuseEnabled] = 0.0, - [Parameter::EarlyDiffuseCount] = 0.2960000038146973, - [Parameter::EarlyDiffuseDelay] = 0.146699994802475, - [Parameter::EarlyDiffuseModAmount] = 0.1559000015258789, - [Parameter::EarlyDiffuseFeedback] = 0.7066999673843384, - [Parameter::EarlyDiffuseModRate] = 0.1626999974250793, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.4599999785423279, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.2226999998092651, - [Parameter::LateLineSize] = 0.5, - [Parameter::LateLineModAmount] = 0.1560000032186508, - [Parameter::LateDiffuseDelay] = 0.510699987411499, - [Parameter::LateDiffuseModAmount] = 0.1600999981164932, - [Parameter::LateLineDecay] = 0.4959999918937683, - [Parameter::LateLineModRate] = 0.1652999967336655, - [Parameter::LateDiffuseFeedback] = 0.7119999527931213, - [Parameter::LateDiffuseModRate] = 0.1507000029087067, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.3199999928474426, - [Parameter::EqHighFreq] = 0.5151999592781067, - [Parameter::EqCutoff] = 0.8260999917984009, - [Parameter::EqLowGain] = 0.8495000004768372, - [Parameter::EqHighGain] = 0.8504999876022339, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.01009999960660934, - [Parameter::SeedDiffusion] = 0.05059999972581863, - [Parameter::SeedDelay] = 0.1002999991178513, - [Parameter::SeedPostDiffusion] = 0.1500999927520752, -}; - -static const float FXDivineInspiration[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.2346999943256378, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 0.0, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.7786999940872192, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.1599999964237213, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.7172999978065491, - [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, - [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4786999821662903, - [Parameter::LateLineSize] = 0.687999963760376, - [Parameter::LateLineModAmount] = 0.7547000050544739, - [Parameter::LateDiffuseDelay] = 0.6279999613761902, - [Parameter::LateDiffuseModAmount] = 0.4614000022411346, - [Parameter::LateLineDecay] = 0.8199999928474426, - [Parameter::LateLineModRate] = 0.6279999613761902, - [Parameter::LateDiffuseFeedback] = 0.6319999694824219, - [Parameter::LateDiffuseModRate] = 0.3267000019550323, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 1.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.5346999764442444, - [Parameter::EqCutoff] = 0.8172999620437622, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.543999969959259, - [Parameter::EqCrossSeed] = 0.1119999960064888, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1469999998807907, - [Parameter::SeedDelay] = 0.2309999912977219, - [Parameter::SeedPostDiffusion] = 0.2899999916553497, -}; - -static const float FXLawsOfPhysics[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 1.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.2800000011920929, - [Parameter::LowCut] = 0.1772999912500381, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 1.0, - [Parameter::EarlyOut] = 0.7999999523162842, - [Parameter::LateOut] = 0.6439999938011169, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 1.0, - [Parameter::TapDecay] = 0.5040000081062317, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 1.0, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 1.0, - [Parameter::EarlyDiffuseDelay] = 0.7706999778747559, - [Parameter::EarlyDiffuseModAmount] = 0.6158999800682068, - [Parameter::EarlyDiffuseFeedback] = 0.5026999711990356, - [Parameter::EarlyDiffuseModRate] = 0.3666999936103821, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.6039999723434448, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.3240000009536743, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.5759999752044678, - [Parameter::LateLineModRate] = 0.0372999981045723, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.4079999923706055, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.2680000066757202, - [Parameter::SeedTap] = 0.3489999771118164, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float FXSlowBraaam[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 1.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.1319999992847443, - [Parameter::LowCut] = 0.3599999845027924, - [Parameter::HighCut] = 0.1400000005960464, - [Parameter::DryOut] = 0.0, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.6839999556541443, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.5839999914169312, - [Parameter::TapDecay] = 0.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 1.0, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.7759999632835388, - [Parameter::EarlyDiffuseDelay] = 0.4986999928951263, - [Parameter::EarlyDiffuseModAmount] = 0.4838999807834625, - [Parameter::EarlyDiffuseFeedback] = 0.5467000007629395, - [Parameter::EarlyDiffuseModRate] = 0.3026999831199646, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.08399999886751175, - [Parameter::LateLineModAmount] = 0.1519999951124191, - [Parameter::LateDiffuseDelay] = 0.363999992609024, - [Parameter::LateDiffuseModAmount] = 0.4387999773025513, - [Parameter::LateLineDecay] = 0.5640000104904175, - [Parameter::LateLineModRate] = 0.2532999813556671, - [Parameter::LateDiffuseFeedback] = 0.7106999754905701, - [Parameter::LateDiffuseModRate] = 0.1826999932527542, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.1119999960064888, - [Parameter::EqHighFreq] = 0.5813999772071838, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.8240000009536743, - [Parameter::EqHighGain] = 0.8479999899864197, - [Parameter::EqCrossSeed] = 0.1759999990463257, - [Parameter::SeedTap] = 0.7879999876022339, - [Parameter::SeedDiffusion] = 0.3240000009536743, - [Parameter::SeedDelay] = 0.1730999946594238, - [Parameter::SeedPostDiffusion] = 0.3233000040054321, -}; - -static const float FXTheUpsideDown[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.2800000011920929, - [Parameter::LowCut] = 0.1772999912500381, - [Parameter::HighCut] = 0.3759999871253967, - [Parameter::DryOut] = 0.7080000042915344, - [Parameter::EarlyOut] = 0.9559999704360962, - [Parameter::LateOut] = 0.6279999613761902, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.1599999964237213, - [Parameter::TapDecay] = 0.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 1.0, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 1.0, - [Parameter::EarlyDiffuseDelay] = 0.9466999769210815, - [Parameter::EarlyDiffuseModAmount] = 0.5598999857902527, - [Parameter::EarlyDiffuseFeedback] = 0.510699987411499, - [Parameter::EarlyDiffuseModRate] = 0.4587000012397766, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.6039999723434448, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.3919999897480011, - [Parameter::LateLineModAmount] = 0.3319999873638153, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.715999960899353, - [Parameter::LateLineModRate] = 0.1412999927997589, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.4079999923706055, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.1319999992847443, - [Parameter::SeedTap] = 0.8539999723434448, - [Parameter::SeedDiffusion] = 0.1129999980330467, - [Parameter::SeedDelay] = 0.3800999820232391, - [Parameter::SeedPostDiffusion] = 0.2633000016212463, -}; - -static const float LBigSoundStage[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.2346999943256378, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 1.0, - [Parameter::EarlyOut] = 0.687999963760376, - [Parameter::LateOut] = 0.7559999823570251, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.1599999964237213, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.4172999858856201, - [Parameter::EarlyDiffuseDelay] = 0.6947000026702881, - [Parameter::EarlyDiffuseModAmount] = 0.3425999879837036, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.3506999909877777, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.6240000128746033, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 1.0, - [Parameter::LateLineSize] = 0.2479999959468842, - [Parameter::LateLineModAmount] = 0.0, - [Parameter::LateDiffuseDelay] = 0.1759999990463257, - [Parameter::LateDiffuseModAmount] = 0.1959999948740005, - [Parameter::LateLineDecay] = 0.4120000004768372, - [Parameter::LateLineModRate] = 0.0, - [Parameter::LateDiffuseFeedback] = 0.8840000033378601, - [Parameter::LateDiffuseModRate] = 0.2586999833583832, - [Parameter::EqLowShelfEnabled] = 1.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.2639999985694885, - [Parameter::EqHighFreq] = 0.5346999764442444, - [Parameter::EqCutoff] = 0.8172999620437622, - [Parameter::EqLowGain] = 0.9720000028610229, - [Parameter::EqHighGain] = 0.543999969959259, - [Parameter::EqCrossSeed] = 0.1119999960064888, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1469999998807907, - [Parameter::SeedDelay] = 0.2309999912977219, - [Parameter::SeedPostDiffusion] = 0.2899999916553497, -}; - -static const float LDiffusionCyclone[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.0746999979019165, - [Parameter::LowCut] = 0.1292999982833862, - [Parameter::HighCut] = 0.6119999885559082, - [Parameter::DryOut] = 0.9079999923706055, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.7786999940872192, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.1599999964237213, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.2132999897003174, - [Parameter::EarlyDiffuseDelay] = 0.2906999886035919, - [Parameter::EarlyDiffuseModAmount] = 0.1145999953150749, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2226999998092651, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4786999821662903, - [Parameter::LateLineSize] = 0.3199999928474426, - [Parameter::LateLineModAmount] = 0.2586999833583832, - [Parameter::LateDiffuseDelay] = 0.3759999871253967, - [Parameter::LateDiffuseModAmount] = 0.2893999814987183, - [Parameter::LateLineDecay] = 0.7519999742507935, - [Parameter::LateLineModRate] = 0.2239999920129776, - [Parameter::LateDiffuseFeedback] = 0.7080000042915344, - [Parameter::LateDiffuseModRate] = 0.2506999969482422, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 1.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.5346999764442444, - [Parameter::EqCutoff] = 0.8172999620437622, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.543999969959259, - [Parameter::EqCrossSeed] = 0.1119999960064888, - [Parameter::SeedTap] = 0.0, - [Parameter::SeedDiffusion] = 0.1219999939203262, - [Parameter::SeedDelay] = 0.3039999902248383, - [Parameter::SeedPostDiffusion] = 0.3409999907016754, -}; - -static const float LScreamIntoTheVoid[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 1.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.2346999943256378, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 0.4852999746799469, - [Parameter::DryOut] = 0.6998999714851379, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.7786999940872192, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.1599999964237213, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.7172999978065491, - [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, - [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.8319999575614929, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4186999797821045, - [Parameter::LateLineSize] = 0.3999999761581421, - [Parameter::LateLineModAmount] = 0.146699994802475, - [Parameter::LateDiffuseDelay] = 0.3519999980926514, - [Parameter::LateDiffuseModAmount] = 0.3653999865055084, - [Parameter::LateLineDecay] = 0.7199999690055847, - [Parameter::LateLineModRate] = 0.1959999948740005, - [Parameter::LateDiffuseFeedback] = 0.7119999527931213, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.5346999764442444, - [Parameter::EqCutoff] = 0.5012999773025513, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.543999969959259, - [Parameter::EqCrossSeed] = 0.1119999960064888, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.07299999892711639, - [Parameter::SeedDelay] = 0.1939999908208847, - [Parameter::SeedPostDiffusion] = 0.3039999902248383, -}; - -static const float M90sDigitalReverb[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.2800000011920929, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 0.7239999771118164, - [Parameter::DryOut] = 0.9720000028610229, - [Parameter::EarlyOut] = 0.4959999918937683, - [Parameter::LateOut] = 0.6173999905586243, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.2960000038146973, - [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, - [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, - [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.2680000066757202, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.3120000064373016, - [Parameter::LateLineModRate] = 0.0372999981045723, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 1.0, - [Parameter::EqLowFreq] = 0.4079999923706055, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float MAiryAmbience[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.07069999724626541, - [Parameter::LowCut] = 0.0, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 0.9785999655723572, - [Parameter::EarlyOut] = 0.5559999942779541, - [Parameter::LateOut] = 0.4280999898910522, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.2360000014305115, - [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, - [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.8319999575614929, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4186999797821045, - [Parameter::LateLineSize] = 0.1079999953508377, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.2506999969482422, - [Parameter::LateDiffuseModAmount] = 0.2480999976396561, - [Parameter::LateLineDecay] = 0.5879999995231628, - [Parameter::LateLineModRate] = 0.2292999923229218, - [Parameter::LateDiffuseFeedback] = 0.7119999527931213, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 1.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.1959999948740005, - [Parameter::EqHighFreq] = 0.7013999819755554, - [Parameter::EqCutoff] = 0.9759999513626099, - [Parameter::EqLowGain] = 0.687999963760376, - [Parameter::EqHighGain] = 0.2746999859809875, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float MDarkPlate[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 1.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.2346999943256378, - [Parameter::LowCut] = 0.6399999856948853, - [Parameter::HighCut] = 0.2933000028133392, - [Parameter::DryOut] = 0.8705999851226807, - [Parameter::EarlyOut] = 0.0, - [Parameter::LateOut] = 0.6613999605178833, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 0.0, - [Parameter::EarlyDiffuseCount] = 0.2960000038146973, - [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, - [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.4693999886512756, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.6345999836921692, - [Parameter::LateLineModRate] = 0.2292999923229218, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.9759999513626099, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float MGhostly[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.0, - [Parameter::LowCut] = 0.0, - [Parameter::HighCut] = 0.1920000016689301, - [Parameter::DryOut] = 1.0, - [Parameter::EarlyOut] = 0.7199999690055847, - [Parameter::LateOut] = 0.4799999892711639, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.03599999845027924, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.7080000042915344, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.1560000032186508, - [Parameter::EarlyDiffuseDelay] = 0.5986999869346619, - [Parameter::EarlyDiffuseModAmount] = 0.927899956703186, - [Parameter::EarlyDiffuseFeedback] = 0.6987000107765198, - [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 1.0, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.08399999886751175, - [Parameter::LateLineModAmount] = 0.335999995470047, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.5640000104904175, - [Parameter::LateLineModRate] = 0.2532999813556671, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 1.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.1119999960064888, - [Parameter::EqHighFreq] = 0.6413999795913696, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.8240000009536743, - [Parameter::EqHighGain] = 0.8319999575614929, - [Parameter::EqCrossSeed] = 0.1759999990463257, - [Parameter::SeedTap] = 0.7879999876022339, - [Parameter::SeedDiffusion] = 0.3240000009536743, - [Parameter::SeedDelay] = 0.1730999946594238, - [Parameter::SeedPostDiffusion] = 0.3233000040054321, -}; - -static const float MTappedLines[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 1.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.0, - [Parameter::LowCut] = 0.6092999577522278, - [Parameter::HighCut] = 0.7239999771118164, - [Parameter::DryOut] = 0.9720000028610229, - [Parameter::EarlyOut] = 1.0, - [Parameter::LateOut] = 0.5679999589920044, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.06399999558925629, - [Parameter::TapDecay] = 0.7719999551773071, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.8586999773979187, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.4839999973773956, - [Parameter::EarlyDiffuseDelay] = 0.2307000011205673, - [Parameter::EarlyDiffuseModAmount] = 0.6678999662399292, - [Parameter::EarlyDiffuseFeedback] = 0.7426999807357788, - [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.515999972820282, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.2680000066757202, - [Parameter::LateLineModAmount] = 0.171999990940094, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.715999960899353, - [Parameter::LateLineModRate] = 0.2572999894618988, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 1.0, - [Parameter::EqLowFreq] = 0.4079999923706055, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.6599999666213989, - [Parameter::SeedTap] = 0.4639999866485596, - [Parameter::SeedDiffusion] = 0.3240000009536743, - [Parameter::SeedDelay] = 0.09409999847412109, - [Parameter::SeedPostDiffusion] = 0.3233000040054321, -}; - -static const float SFastAttack[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.2800000011920929, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 0.7239999771118164, - [Parameter::DryOut] = 0.9720000028610229, - [Parameter::EarlyOut] = 0.6800000071525574, - [Parameter::LateOut] = 0.5399999618530273, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.06799999624490738, - [Parameter::TapDecay] = 0.9559999704360962, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.6520000100135803, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.2960000038146973, - [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, - [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, - [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.3079999983310699, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4879999756813049, - [Parameter::LateLineSize] = 0.4079999923706055, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.239999994635582, - [Parameter::LateDiffuseModAmount] = 0.1467999964952469, - [Parameter::LateLineDecay] = 0.4439999759197235, - [Parameter::LateLineModRate] = 0.0372999981045723, - [Parameter::LateDiffuseFeedback] = 0.8506999611854553, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 0.0, - [Parameter::EqLowpassEnabled] = 1.0, - [Parameter::EqLowFreq] = 0.4079999923706055, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.7439999580383301, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.2680000066757202, - [Parameter::SeedTap] = 0.3489999771118164, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float SSmallPlate[Parameter::COUNT] = { - [Parameter::Interpolation] = 0.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 1.0, - [Parameter::InputMix] = 0.2346999943256378, - [Parameter::LowCut] = 0.2933000028133392, - [Parameter::HighCut] = 0.687999963760376, - [Parameter::DryOut] = 0.8705999851226807, - [Parameter::EarlyOut] = 0.3680000007152557, - [Parameter::LateOut] = 0.5281000137329102, - [Parameter::TapEnabled] = 0.0, - [Parameter::TapCount] = 0.1959999948740005, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.9866999983787537, - [Parameter::EarlyDiffuseEnabled] = 1.0, - [Parameter::EarlyDiffuseCount] = 0.2960000038146973, - [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, - [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, - [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.8319999575614929, - [Parameter::LateDiffuseEnabled] = 0.0, - [Parameter::LateDiffuseCount] = 0.4186999797821045, - [Parameter::LateLineSize] = 0.543999969959259, - [Parameter::LateLineModAmount] = 0.2719999849796295, - [Parameter::LateDiffuseDelay] = 0.2506999969482422, - [Parameter::LateDiffuseModAmount] = 0.2480999976396561, - [Parameter::LateLineDecay] = 0.4959999918937683, - [Parameter::LateLineModRate] = 0.2292999923229218, - [Parameter::LateDiffuseFeedback] = 0.7119999527931213, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.7053999900817871, - [Parameter::EqCutoff] = 0.9759999513626099, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.8906999826431274, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.3339999914169312, - [Parameter::SeedDiffusion] = 0.1850000023841858, - [Parameter::SeedDelay] = 0.2180999964475632, - [Parameter::SeedPostDiffusion] = 0.3652999997138977, -}; - -static const float SSnappyAttack[Parameter::COUNT] = { - [Parameter::Interpolation] = 1.0, - [Parameter::LowCutEnabled] = 0.0, - [Parameter::HighCutEnabled] = 0.0, - [Parameter::InputMix] = 0.3026999831199646, - [Parameter::LowCut] = 0.0, - [Parameter::HighCut] = 1.0, - [Parameter::DryOut] = 1.0, - [Parameter::EarlyOut] = 0.371999979019165, - [Parameter::LateOut] = 0.6319999694824219, - [Parameter::TapEnabled] = 1.0, - [Parameter::TapCount] = 0.5239999890327454, - [Parameter::TapDecay] = 1.0, - [Parameter::TapPredelay] = 0.0, - [Parameter::TapLength] = 0.3226999938488007, - [Parameter::EarlyDiffuseEnabled] = 0.0, - [Parameter::EarlyDiffuseCount] = 0.2119999974966049, - [Parameter::EarlyDiffuseDelay] = 0.0, - [Parameter::EarlyDiffuseModAmount] = 0.2198999971151352, - [Parameter::EarlyDiffuseFeedback] = 0.7106999754905701, - [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, - [Parameter::LateMode] = 1.0, - [Parameter::LateLineCount] = 0.3279999792575836, - [Parameter::LateDiffuseEnabled] = 1.0, - [Parameter::LateDiffuseCount] = 0.03199999779462814, - [Parameter::LateLineSize] = 0.3014000058174133, - [Parameter::LateLineModAmount] = 0.1159999966621399, - [Parameter::LateDiffuseDelay] = 0.3479999899864197, - [Parameter::LateDiffuseModAmount] = 0.2547999918460846, - [Parameter::LateLineDecay] = 0.2425999939441681, - [Parameter::LateLineModRate] = 0.2292999923229218, - [Parameter::LateDiffuseFeedback] = 0.7306999564170837, - [Parameter::LateDiffuseModRate] = 0.1666999906301498, - [Parameter::EqLowShelfEnabled] = 0.0, - [Parameter::EqHighShelfEnabled] = 1.0, - [Parameter::EqLowpassEnabled] = 0.0, - [Parameter::EqLowFreq] = 0.3879999816417694, - [Parameter::EqHighFreq] = 0.5133999586105347, - [Parameter::EqCutoff] = 0.9759999513626099, - [Parameter::EqLowGain] = 0.5559999942779541, - [Parameter::EqHighGain] = 0.7680000066757202, - [Parameter::EqCrossSeed] = 0.0, - [Parameter::SeedTap] = 0.5879999995231628, - [Parameter::SeedDiffusion] = 0.2549999952316284, - [Parameter::SeedDelay] = 0.09809999912977219, - [Parameter::SeedPostDiffusion] = 0.189300000667572, -}; - -static const float *Presets[] = { - UInit, - FXDivineInspiration, - FXLawsOfPhysics, - FXSlowBraaam, - FXTheUpsideDown, - LBigSoundStage, - LDiffusionCyclone, - LScreamIntoTheVoid, - M90sDigitalReverb, - MAiryAmbience, - MDarkPlate, - MGhostly, - MTappedLines, - SFastAttack, - SSmallPlate, - SSnappyAttack, -}; - -static const char *CS2PresetNames[] = { - "Init", - "FXDivineInspiration", - "FXLawsOfPhysics", - "FXSlowBraaam", - "FXTheUpsideDown", - "LBigSoundStage", - "LDiffusionCyclone", - "LScreamIntoTheVoid", - "M90sDigitalReverb", - "MAiryAmbience", - "MDarkPlate", - "MGhostly", - "MTappedLines", - "SFastAttack", - "SSmallPlate", - "SSnappyAttack", -}; +#include "../CloudSeedCore/DSP/ReverbController.h" class AudioEffectCloudSeed2 { public: + static constexpr const char *PresetNames[] = { + "Init", + "FXDivineInspiration", + "FXLawsOfPhysics", + "FXSlowBraaam", + "FXTheUpsideDown", + "LBigSoundStage", + "LDiffusionCyclone", + "LScreamIntoTheVoid", + "M90sDigitalReverb", + "MAiryAmbience", + "MDarkPlate", + "MGhostly", + "MTappedLines", + "SFastAttack", + "SSmallPlate", + "SSnappyAttack", + }; + + static constexpr unsigned presets_num = sizeof PresetNames / sizeof *PresetNames; + static const float *Presets[]; + static std::string GetLateMode (int nValue, int nWidth) { return nValue ? "Post" : "Pre"; @@ -830,27 +46,24 @@ class AudioEffectCloudSeed2 static std::string getPresetName (int nValue, int nWidth) { assert (nValue >= 0 && (unsigned)nValue < presets_num); - return CS2PresetNames[nValue]; + return PresetNames[nValue]; } static const char *getPresetNameChar (int nValue) { assert (nValue >= 0 && (unsigned)nValue < presets_num); - return CS2PresetNames[nValue]; + return PresetNames[nValue]; } static unsigned getIDFromPresetName(const char *presetName) { for (unsigned i = 0; i < presets_num; ++i) - if (strcmp(CS2PresetNames[i], presetName) == 0) + if (strcmp(PresetNames[i], presetName) == 0) return i; return 0; } - static constexpr unsigned presets_num = sizeof CS2PresetNames / sizeof *CS2PresetNames; - - AudioEffectCloudSeed2(float samplerate): samplerate{samplerate}, ramp_dt{10.0f / samplerate}, @@ -910,7 +123,7 @@ class AudioEffectCloudSeed2 if (needParameterLoad) { unsigned needParam = needParameterLoad; - unsigned paramID = Parameter::COUNT - needParam; + unsigned paramID = Cloudseed::Parameter::COUNT - needParam; engine.SetParameter(paramID, Presets[preset][paramID]); needParameterLoad = needParam - 1; @@ -948,7 +161,7 @@ class AudioEffectCloudSeed2 targetVol = 0.0f; needBufferClear = true; - needParameterLoad = Parameter::COUNT; + needParameterLoad = Cloudseed::Parameter::COUNT; } void setNeedBufferClear() @@ -964,7 +177,9 @@ class AudioEffectCloudSeed2 bool isDisabled() { double *params = engine.GetAllParameters(); - return params[Parameter::DryOut] == 1.0f && params[Parameter::EarlyOut] == 0.0f && params[Parameter::LateOut] == 0.0f; + return params[Cloudseed::Parameter::DryOut] == 1.0f && + params[Cloudseed::Parameter::EarlyOut] == 0.0f && + params[Cloudseed::Parameter::LateOut] == 0.0f; } private: From 50c72df1b1e384204133eeb2275c10f71c51190c Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 21:11:47 +0100 Subject: [PATCH 101/136] effect_cloudseed2: convert to tabs --- src/effect_cloudseed2.h | 258 ++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h index 4be5edcd6..48bcf8142 100644 --- a/src/effect_cloudseed2.h +++ b/src/effect_cloudseed2.h @@ -58,139 +58,139 @@ class AudioEffectCloudSeed2 static unsigned getIDFromPresetName(const char *presetName) { for (unsigned i = 0; i < presets_num; ++i) - if (strcmp(PresetNames[i], presetName) == 0) - return i; + if (strcmp(PresetNames[i], presetName) == 0) + return i; return 0; } - AudioEffectCloudSeed2(float samplerate): - samplerate{samplerate}, - ramp_dt{10.0f / samplerate}, - engine{(int)samplerate}, - targetVol{}, - needBufferClear{}, - waitBufferClear{}, - needParameterLoad{}, - preset{}, - vol{} - { - } - - void setParameter(unsigned paramID, float param) - { - engine.SetParameter(paramID, param); - } - - float getParameter(unsigned paramID) - { - return engine.GetAllParameters()[paramID]; - } - - void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) - { - if (targetVol == 0.0f && vol > 0.0f) - { - engine.Process(inblockL, inblockR, inblockL, inblockR, len); - for (uint16_t i = 0; i < len; ++i) - { - vol = std::max(0.0f, vol - ramp_dt); - inblockL[i] *= vol; - inblockR[i] *= vol; - } - - return; - } - - if (needBufferClear) - { - engine.StartSlowClear(); - needBufferClear = false; - waitBufferClear = true; - } - - if (waitBufferClear) - { - if (engine.SlowClearDone(SLOW_CLEAR_SIZE)) - waitBufferClear = false; - - memset(inblockL, 0, len * sizeof *inblockL); - memset(inblockR, 0, len * sizeof *inblockR); - - return; - } - - if (needParameterLoad) - { - unsigned needParam = needParameterLoad; - unsigned paramID = Cloudseed::Parameter::COUNT - needParam; - engine.SetParameter(paramID, Presets[preset][paramID]); - needParameterLoad = needParam - 1; - - memset(inblockL, 0, len * sizeof *inblockL); - memset(inblockR, 0, len * sizeof *inblockR); - - if (!needParameterLoad) - targetVol = 1.0f; - - return; - } - - if (targetVol == 1.0f && vol < 1.0f) - { - engine.Process(inblockL, inblockR, inblockL, inblockR, len); - for (uint16_t i = 0; i < len; ++i) - { - vol = std::min(vol + ramp_dt, 1.0f); - inblockL[i] *= vol; - inblockR[i] *= vol; - } - - return; - } - - if (isDisabled()) return; - - engine.Process(inblockL, inblockR, inblockL, inblockR, len); - } - - void loadPreset(unsigned p) - { - assert(p < presets_num); - preset = p; - - targetVol = 0.0f; - needBufferClear = true; - needParameterLoad = Cloudseed::Parameter::COUNT; - } - - void setNeedBufferClear() - { - needBufferClear = true; - } - - void setRampedDown() - { - vol = 0.0f; - } - - bool isDisabled() - { - double *params = engine.GetAllParameters(); - return params[Cloudseed::Parameter::DryOut] == 1.0f && - params[Cloudseed::Parameter::EarlyOut] == 0.0f && - params[Cloudseed::Parameter::LateOut] == 0.0f; - } + AudioEffectCloudSeed2(float samplerate): + samplerate{samplerate}, + ramp_dt{10.0f / samplerate}, + engine{(int)samplerate}, + targetVol{}, + needBufferClear{}, + waitBufferClear{}, + needParameterLoad{}, + preset{}, + vol{} + { + } + + void setParameter(unsigned paramID, float param) + { + engine.SetParameter(paramID, param); + } + + float getParameter(unsigned paramID) + { + return engine.GetAllParameters()[paramID]; + } + + void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) + { + if (targetVol == 0.0f && vol > 0.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::max(0.0f, vol - ramp_dt); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (needBufferClear) + { + engine.StartSlowClear(); + needBufferClear = false; + waitBufferClear = true; + } + + if (waitBufferClear) + { + if (engine.SlowClearDone(SLOW_CLEAR_SIZE)) + waitBufferClear = false; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + return; + } + + if (needParameterLoad) + { + unsigned needParam = needParameterLoad; + unsigned paramID = Cloudseed::Parameter::COUNT - needParam; + engine.SetParameter(paramID, Presets[preset][paramID]); + needParameterLoad = needParam - 1; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + if (!needParameterLoad) + targetVol = 1.0f; + + return; + } + + if (targetVol == 1.0f && vol < 1.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::min(vol + ramp_dt, 1.0f); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (isDisabled()) return; + + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + } + + void loadPreset(unsigned p) + { + assert(p < presets_num); + preset = p; + + targetVol = 0.0f; + needBufferClear = true; + needParameterLoad = Cloudseed::Parameter::COUNT; + } + + void setNeedBufferClear() + { + needBufferClear = true; + } + + void setRampedDown() + { + vol = 0.0f; + } + + bool isDisabled() + { + double *params = engine.GetAllParameters(); + return params[Cloudseed::Parameter::DryOut] == 1.0f && + params[Cloudseed::Parameter::EarlyOut] == 0.0f && + params[Cloudseed::Parameter::LateOut] == 0.0f; + } private: - float samplerate; - float ramp_dt; - Cloudseed::ReverbController engine; - std::atomic targetVol; - std::atomic needBufferClear; - bool waitBufferClear; - std::atomic needParameterLoad; - std::atomic preset; - - std::atomic vol; + float samplerate; + float ramp_dt; + Cloudseed::ReverbController engine; + std::atomic targetVol; + std::atomic needBufferClear; + bool waitBufferClear; + std::atomic needParameterLoad; + std::atomic preset; + + std::atomic vol; }; From fd5ecad46686426afc1aea3bf477e1fd34945987 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 22:52:08 +0100 Subject: [PATCH 102/136] add AudioEffectCompressor --- src/effect.cpp | 34 +++++++++++++++- src/effect.h | 9 +++++ src/effect_chain.h | 5 +++ src/effect_compressor.h | 87 +++++++++++++++++++++++++++++++++++++++++ src/minidexed.cpp | 46 ++++++++++++++++++++++ src/uimenu.cpp | 14 +++++++ src/uimenu.h | 1 + 7 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/effect_compressor.h diff --git a/src/effect.cpp b/src/effect.cpp index 77cbaba51..d83e18f4c 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -1,8 +1,9 @@ #include #include "effect.h" -#include "effect_cloudseed2.h" #include "midi.h" +#include "effect_cloudseed2.h" +#include "effect_compressor.h" static std::string ToOnOff (int nValue, int nWidth) { @@ -74,6 +75,29 @@ static std::string ToEffectName (int nValue, int nWidth) return FX::s_effects[nValue].Name; } +static std::string TodB (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dB"; +} + +static std::string TodBFS (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dBFS"; +} + +static std::string ToMillisec (int nValue, int nWidth) +{ + return std::to_string (nValue) + " ms"; +} + +static std::string ToRatio (int nValue, int nWidth) +{ + if (nValue == AudioEffectCompressor::CompressorRatioInf) + return "INF:1"; + + return std::to_string (nValue) + ":1"; +} + FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = { {0, FX::effects_num - 1, 0, 1, "Slot1", ToEffectName, FX::FXSaveAsString}, @@ -144,6 +168,14 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, {0, 127, 12, 1, "CloudSeed2SeedDelay"}, {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, + {-20, 20, 0, 1, "CompressorPreGain", TodB}, + {-60, 0, -20, 1, "CompressorThresh", TodBFS}, + {1, AudioEffectCompressor::CompressorRatioInf, 5, 1, "CompressorRatio", ToRatio}, + {0, 1000, 5, 5, "CompressorAttack", ToMillisec}, + {0, 2000, 200, 5, "CompressorRelease", ToMillisec}, + {-20, 20, 0, 1, "CompressorMakeupGain", TodB}, + {0, 1, 0, 1, "CompressorHPFilterEnable", ToOnOff}, + {0, 1, 0, 1, "CompressorBypass", ToOnOff}, {0, 99, 0, 1, "ReturnLevel"}, }; diff --git a/src/effect.h b/src/effect.h index ec1a167e8..d1f83f06b 100644 --- a/src/effect.h +++ b/src/effect.h @@ -79,6 +79,14 @@ class FX FXParameterCloudSeed2SeedDiffusion, FXParameterCloudSeed2SeedDelay, FXParameterCloudSeed2SeedPostDiffusion, + FXParameterCompressorPreGain, + FXParameterCompressorThresh, + FXParameterCompressorRatio, + FXParameterCompressorAttack, + FXParameterCompressorRelease, + FXParameterCompressorMakeupGain, + FXParameterCompressorHPFilterEnable, + FXParameterCompressorBypass, FXParameterReturnLevel, FXParameterUnknown, }; @@ -111,6 +119,7 @@ class FX {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayHighCut}, {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, + {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, }; static constexpr uint8_t effects_num = sizeof s_effects / sizeof *s_effects; static constexpr uint8_t slots_num = 3; diff --git a/src/effect_chain.h b/src/effect_chain.h index 3fc5925e8..79e02c170 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -2,6 +2,7 @@ #include +#include "effect_compressor.h" #include "effect_cloudseed2.h" #include "effect_dreamdelay.h" #include "effect_platervbstereo.h" @@ -17,12 +18,14 @@ class AudioFXChain dream_delay{samplerate}, plate_reverb{samplerate}, cloudseed2{samplerate}, + compressor{samplerate}, funcs{ [this](float *inputL, float *inputR, uint16_t len) {}, [this](float *inputL, float *inputR, uint16_t len) { yk_chorus.process(inputL, inputR, len); }, [this](float *inputL, float *inputR, uint16_t len) { dream_delay.process(inputL, inputR, len); }, [this](float *inputL, float *inputR, uint16_t len) { plate_reverb.process(inputL, inputR, inputL, inputR, len); }, [this](float *inputL, float *inputR, uint16_t len) { cloudseed2.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { compressor.process(inputL, inputR, len); }, }, level{} { @@ -45,6 +48,7 @@ class AudioFXChain { dream_delay.resetState(); plate_reverb.reset(); + compressor.resetState(); cloudseed2.setRampedDown(); cloudseed2.setNeedBufferClear(); @@ -62,6 +66,7 @@ class AudioFXChain AudioEffectDreamDelay dream_delay; AudioEffectPlateReverb plate_reverb; AudioEffectCloudSeed2 cloudseed2; + AudioEffectCompressor compressor; private: std::atomic slots[FX::slots_num]; diff --git a/src/effect_compressor.h b/src/effect_compressor.h new file mode 100644 index 000000000..f1aac838c --- /dev/null +++ b/src/effect_compressor.h @@ -0,0 +1,87 @@ +/* + * Chip Audette's Compressor + * https://github.com/chipaudette/OpenAudio_ArduinoLibrary/blob/master/AudioEffectCompressor_F32.h + */ + +#include + +#include "compressor.h" + +class AudioEffectCompressor +{ +public: + static const unsigned CompressorRatioInf = 31; + + AudioEffectCompressor(float samplerate): + bypass{}, + samplerate{samplerate}, + compL{samplerate}, + compR{samplerate} + {} + + void setPreGain_dB(float gain) + { + compL.setPreGain_dB(gain); + compR.setPreGain_dB(gain); + } + + void setThresh_dBFS(float thresh) + { + compL.setThresh_dBFS(thresh); + compR.setThresh_dBFS(thresh); + } + + void setCompressionRatio(float ratio) + { + ratio = ratio == CompressorRatioInf ? INFINITY : ratio; + + compL.setCompressionRatio(ratio); + compR.setCompressionRatio(ratio); + } + + void setAttack_sec(float sec) + { + compL.setAttack_sec(sec, samplerate); + compR.setAttack_sec(sec, samplerate); + } + + void setRelease_sec(float sec) + { + compL.setRelease_sec(sec, samplerate); + compR.setRelease_sec(sec, samplerate); + } + + void setMakeupGain_dB(float gain) + { + compL.setMakeupGain_dB(gain); + compR.setMakeupGain_dB(gain); + } + + void enableHPFilter(bool hpfilter) + { + compL.enableHPFilter(hpfilter); + compR.enableHPFilter(hpfilter); + } + + void resetState() + { + compL.resetStates(); + compR.resetStates(); + } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + if (bypass) return; + + compL.doCompression (blockL, len); + compR.doCompression (blockR, len); + } + + std::atomic bypass; + +private: + const float samplerate; + + Compressor compL; + Compressor compR; +}; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b8e200a72..2c8685bd3 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1410,6 +1410,52 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne fx_chain[nFX]->cloudseed2.setParameter (Parameter - FX::FXParameterCloudSeed2Interpolation, mapfloat(nValue, p.Minimum, p.Maximum, 0.0f, 1.0f)); break; + case FX::FXParameterCompressorPreGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setPreGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorThresh: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setThresh_dBFS (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorRatio: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setCompressionRatio (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorAttack: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setAttack_sec ((nValue ?: 1) / 1000.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorRelease: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setRelease_sec ((nValue ?: 1) / 1000.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorMakeupGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setMakeupGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorHPFilterEnable: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.enableHPFilter (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorBypass: + fx_chain[nFX]->compressor.bypass = nValue; + break; + case FX::FXParameterReturnLevel: m_FXSpinLock.Acquire (); fx_chain[nFX]->set_level (nValue / 99.0f); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 5dd49693e..735b01a46 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -200,6 +200,7 @@ const CUIMenu::TMenuItem CUIMenu::s_FXListMenu[] = {"DreamDelay", MenuHandler, s_DreamDelayMenu}, {"PlateReverb", MenuHandler, s_PlateReverbMenu}, {"CloudSeed2", MenuHandler, s_CloudSeed2Menu}, + {"Compressor", MenuHandler, s_CompressorMenu}, {0}, }; @@ -336,6 +337,19 @@ const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LowPassMenu[] = {0}, }; +const CUIMenu::TMenuItem CUIMenu::s_CompressorMenu[] = +{ + {"Pre Gain", EditFXParameter2, 0, FX::FXParameterCompressorPreGain}, + {"Threshold", EditFXParameter2, 0, FX::FXParameterCompressorThresh}, + {"Ratio", EditFXParameter2, 0, FX::FXParameterCompressorRatio}, + {"Attack", EditFXParameter2, 0, FX::FXParameterCompressorAttack}, + {"Release", EditFXParameter2, 0, FX::FXParameterCompressorRelease}, + {"Makeup Gain", EditFXParameter2, 0, FX::FXParameterCompressorMakeupGain}, + {"HPFilter", EditFXParameter2, 0, FX::FXParameterCompressorHPFilterEnable}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterCompressorBypass}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = { {"Low Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLow}, diff --git a/src/uimenu.h b/src/uimenu.h index e1be5f2d1..6acfc8e5c 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -197,6 +197,7 @@ class CUIMenu static const TMenuItem s_CloudSeed2LowShelfMenu[]; static const TMenuItem s_CloudSeed2HighShelfMenu[]; static const TMenuItem s_CloudSeed2LowPassMenu[]; + static const TMenuItem s_CompressorMenu[]; static const TMenuItem s_MasterEQMenu[]; static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; From b94196cb52bced3313d3c3c5727b42da4c28fe9a Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 23:35:06 +0100 Subject: [PATCH 103/136] rename AudioEffect3BandEQ to AudioEffect3BandEQMono --- src/dexedadapter.h | 4 ++-- src/{effect_3bandeq.h => effect_3bandeqmono.h} | 4 ++-- src/minidexed.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/{effect_3bandeq.h => effect_3bandeqmono.h} (97%) diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 1214b4629..272cec7d7 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -25,7 +25,7 @@ #include #include -#include "effect_3bandeq.h" +#include "effect_3bandeqmono.h" #include "compressor.h" #define DEXED_OP_ENABLE (DEXED_OP_OSC_DETUNE + 1) @@ -108,7 +108,7 @@ class CDexedAdapter : public Dexed m_SpinLock.Release (); } - AudioEffect3BandEQ EQ; + AudioEffect3BandEQMono EQ; Compressor Compr; private: diff --git a/src/effect_3bandeq.h b/src/effect_3bandeqmono.h similarity index 97% rename from src/effect_3bandeq.h rename to src/effect_3bandeqmono.h index 1aa778f8c..84e1fedd6 100644 --- a/src/effect_3bandeq.h +++ b/src/effect_3bandeqmono.h @@ -10,10 +10,10 @@ #include "midi.h" -class AudioEffect3BandEQ +class AudioEffect3BandEQMono { public: - AudioEffect3BandEQ(unsigned samplerate): + AudioEffect3BandEQMono(unsigned samplerate): samplerate{samplerate}, fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, nLowMidFreq{24}, /* 315Hz */ diff --git a/src/minidexed.h b/src/minidexed.h index a55b70ea5..cc6447c95 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -52,7 +52,7 @@ #include "udpmididevice.h" #include "net/ftpdaemon.h" #include "compressor.h" -#include "effect_3bandeq.h" +#include "effect_3bandeqmono.h" #include "effect_chain.h" class CMiniDexed @@ -418,7 +418,7 @@ class CMiniDexed CSpinLock m_FXSpinLock; - AudioEffect3BandEQ m_MasterEQ[2]; + AudioEffect3BandEQMono m_MasterEQ[2]; CSpinLock m_EQSpinLock; Compressor m_MasterCompressor[2]; From f7ca0adc0d82ed4c0c9849b9d5a5e04feca697e1 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 12 Nov 2025 23:38:56 +0100 Subject: [PATCH 104/136] effect_3bandeqmono: convert to tabs --- src/effect_3bandeqmono.h | 216 +++++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/src/effect_3bandeqmono.h b/src/effect_3bandeqmono.h index 84e1fedd6..c339aa2d8 100644 --- a/src/effect_3bandeqmono.h +++ b/src/effect_3bandeqmono.h @@ -13,118 +13,118 @@ class AudioEffect3BandEQMono { public: - AudioEffect3BandEQMono(unsigned samplerate): - samplerate{samplerate}, - fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, - nLowMidFreq{24}, /* 315Hz */ - nMidHighFreq{44}, /* 3.2kHz */ - tmpLP{}, tmpHP{} - { - setLow_dB(fLow); - setMid_dB(fMid); - setHigh_dB(fHigh); - setGain_dB(fGain); - setLowMidFreq_n(nLowMidFreq); - setMidHighFreq_n(nMidHighFreq); - } - - void setLow_dB(float value) - { - fLow = value; - lowVol = std::pow(10.0f, fLow / 20.0f); - } - - void setMid_dB(float value) - { - fMid = value; - midVol = std::pow(10.0f, fMid / 20.0f); - } - - void setHigh_dB(float value) - { - fHigh = value; - highVol = std::pow(10.0f, fHigh / 20.0f); - } - - void setGain_dB(float value) - { - fGain = value; - outVol = std::pow(10.0f, fGain / 20.0f); - } - - float setLowMidFreq(float value) - { - fLowMidFreq = std::min(value, fMidHighFreq); - xLP = std::exp(-2.0f * M_PI * fLowMidFreq / samplerate); - a0LP = 1.0f - xLP; - b1LP = -xLP; - return fLowMidFreq; - } - - float setMidHighFreq(float value) - { - fMidHighFreq = std::max(value, fLowMidFreq); - xHP = std::exp(-2.0f * M_PI * fMidHighFreq / samplerate); - a0HP = 1.0f - xHP; - b1HP = -xHP; - return fMidHighFreq; - } - - unsigned setLowMidFreq_n(unsigned value) - { - nLowMidFreq = std::min(value, nMidHighFreq); - setLowMidFreq(MIDI_EQ_HZ[nLowMidFreq]); - return nLowMidFreq; - } - - unsigned setMidHighFreq_n(unsigned value) - { - nMidHighFreq = std::max(value, nLowMidFreq); - setMidHighFreq(MIDI_EQ_HZ[nMidHighFreq]); - return nMidHighFreq; - } - - float getLow_dB() const { return fLow; } - float getMid_dB() const { return fMid; } - float getHigh_dB() const { return fHigh; } - float getGain_dB() const { return fGain; } - float getLowMidFreq() const { return fLowMidFreq; } - float getMidHighFreq() const { return fMidHighFreq; } - unsigned getLowMidFreq_n() const { return nLowMidFreq; } - unsigned getMidHighFreq_n() const { return nMidHighFreq; } - - void resetState() { tmpLP = 0.0f; tmpHP = 0.0f; } - - void process(float32_t* block, uint16_t len) - { - float outLP, outHP; - - if (!fLow && !fMid && !fHigh && !fGain) return; - - for (uint16_t i=0; i < len; ++i) - { - float inValue = std::isnan(block[i]) ? 0.0f : block[i]; - - tmpLP = a0LP * inValue - b1LP * tmpLP; - outLP = tmpLP; - - tmpHP = a0HP * inValue - b1HP * tmpHP; - outHP = inValue - tmpHP; - - block[i] = (outLP*lowVol + (inValue - outLP - outHP)*midVol + outHP*highVol) * outVol; - } - } + AudioEffect3BandEQMono(unsigned samplerate): + samplerate{samplerate}, + fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, + nLowMidFreq{24}, /* 315Hz */ + nMidHighFreq{44}, /* 3.2kHz */ + tmpLP{}, tmpHP{} + { + setLow_dB(fLow); + setMid_dB(fMid); + setHigh_dB(fHigh); + setGain_dB(fGain); + setLowMidFreq_n(nLowMidFreq); + setMidHighFreq_n(nMidHighFreq); + } + + void setLow_dB(float value) + { + fLow = value; + lowVol = std::pow(10.0f, fLow / 20.0f); + } + + void setMid_dB(float value) + { + fMid = value; + midVol = std::pow(10.0f, fMid / 20.0f); + } + + void setHigh_dB(float value) + { + fHigh = value; + highVol = std::pow(10.0f, fHigh / 20.0f); + } + + void setGain_dB(float value) + { + fGain = value; + outVol = std::pow(10.0f, fGain / 20.0f); + } + + float setLowMidFreq(float value) + { + fLowMidFreq = std::min(value, fMidHighFreq); + xLP = std::exp(-2.0f * M_PI * fLowMidFreq / samplerate); + a0LP = 1.0f - xLP; + b1LP = -xLP; + return fLowMidFreq; + } + + float setMidHighFreq(float value) + { + fMidHighFreq = std::max(value, fLowMidFreq); + xHP = std::exp(-2.0f * M_PI * fMidHighFreq / samplerate); + a0HP = 1.0f - xHP; + b1HP = -xHP; + return fMidHighFreq; + } + + unsigned setLowMidFreq_n(unsigned value) + { + nLowMidFreq = std::min(value, nMidHighFreq); + setLowMidFreq(MIDI_EQ_HZ[nLowMidFreq]); + return nLowMidFreq; + } + + unsigned setMidHighFreq_n(unsigned value) + { + nMidHighFreq = std::max(value, nLowMidFreq); + setMidHighFreq(MIDI_EQ_HZ[nMidHighFreq]); + return nMidHighFreq; + } + + float getLow_dB() const { return fLow; } + float getMid_dB() const { return fMid; } + float getHigh_dB() const { return fHigh; } + float getGain_dB() const { return fGain; } + float getLowMidFreq() const { return fLowMidFreq; } + float getMidHighFreq() const { return fMidHighFreq; } + unsigned getLowMidFreq_n() const { return nLowMidFreq; } + unsigned getMidHighFreq_n() const { return nMidHighFreq; } + + void resetState() { tmpLP = 0.0f; tmpHP = 0.0f; } + + void process(float32_t* block, uint16_t len) + { + float outLP, outHP; + + if (!fLow && !fMid && !fHigh && !fGain) return; + + for (uint16_t i=0; i < len; ++i) + { + float inValue = std::isnan(block[i]) ? 0.0f : block[i]; + + tmpLP = a0LP * inValue - b1LP * tmpLP; + outLP = tmpLP; + + tmpHP = a0HP * inValue - b1HP * tmpHP; + outHP = inValue - tmpHP; + + block[i] = (outLP*lowVol + (inValue - outLP - outHP)*midVol + outHP*highVol) * outVol; + } + } private: - unsigned samplerate; + unsigned samplerate; - float fLow, fMid, fHigh, fGain, fLowMidFreq, fMidHighFreq; - unsigned nLowMidFreq, nMidHighFreq; + float fLow, fMid, fHigh, fGain, fLowMidFreq, fMidHighFreq; + unsigned nLowMidFreq, nMidHighFreq; - float lowVol, midVol, highVol, outVol; + float lowVol, midVol, highVol, outVol; - float xLP, a0LP, b1LP; - float xHP, a0HP, b1HP; + float xLP, a0LP, b1LP; + float xHP, a0HP, b1HP; - float tmpLP, tmpHP; + float tmpLP, tmpHP; }; From a4764c1cbda4c39347b1780ed478389c024e7b6e Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 00:06:47 +0100 Subject: [PATCH 105/136] effect_3bandeqmono: use float samplerate --- src/dexedadapter.h | 2 +- src/effect_3bandeqmono.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 272cec7d7..c92aea833 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -38,7 +38,7 @@ class CDexedAdapter : public Dexed public: CDexedAdapter (uint8_t maxnotes, unsigned samplerate): Dexed (maxnotes, samplerate), - EQ {samplerate}, + EQ {(float)samplerate}, Compr {(float)samplerate}, m_bCompressorEnable {} { diff --git a/src/effect_3bandeqmono.h b/src/effect_3bandeqmono.h index c339aa2d8..f198a3f66 100644 --- a/src/effect_3bandeqmono.h +++ b/src/effect_3bandeqmono.h @@ -13,7 +13,7 @@ class AudioEffect3BandEQMono { public: - AudioEffect3BandEQMono(unsigned samplerate): + AudioEffect3BandEQMono(float samplerate): samplerate{samplerate}, fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, nLowMidFreq{24}, /* 315Hz */ @@ -116,7 +116,7 @@ class AudioEffect3BandEQMono } private: - unsigned samplerate; + float samplerate; float fLow, fMid, fHigh, fGain, fLowMidFreq, fMidHighFreq; unsigned nLowMidFreq, nMidHighFreq; From b39ddac44a84035e6603360d6269e2f854c1e581 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 00:22:16 +0100 Subject: [PATCH 106/136] add AudioEffect3BandEQ --- src/effect.cpp | 7 ++++ src/effect.h | 8 ++++ src/effect_3bandeq.h | 95 ++++++++++++++++++++++++++++++++++++++++++++ src/effect_chain.h | 5 +++ src/minidexed.cpp | 40 +++++++++++++++++++ src/uimenu.cpp | 13 ++++++ src/uimenu.h | 1 + 7 files changed, 169 insertions(+) create mode 100644 src/effect_3bandeq.h diff --git a/src/effect.cpp b/src/effect.cpp index d83e18f4c..dca81a00d 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -176,6 +176,13 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {-20, 20, 0, 1, "CompressorMakeupGain", TodB}, {0, 1, 0, 1, "CompressorHPFilterEnable", ToOnOff}, {0, 1, 0, 1, "CompressorBypass", ToOnOff}, + {-24, 24, 0, 1, "EQLow", TodB}, + {-24, 24, 0, 1, "EQMid", TodB}, + {-24, 24, 0, 1, "EQHigh", TodB}, + {-24, 24, 0, 1, "EQGain", TodB}, + {0, 46, 24, 1, "EQLowMidFreq", ToHz}, + {28, 59, 44, 1, "EQMidHighFreq", ToHz}, + {0, 1, 0, 1, "EQBypass", ToOnOff}, {0, 99, 0, 1, "ReturnLevel"}, }; diff --git a/src/effect.h b/src/effect.h index d1f83f06b..b97ddb209 100644 --- a/src/effect.h +++ b/src/effect.h @@ -87,6 +87,13 @@ class FX FXParameterCompressorMakeupGain, FXParameterCompressorHPFilterEnable, FXParameterCompressorBypass, + FXParameterEQLow, + FXParameterEQMid, + FXParameterEQHigh, + FXParameterEQGain, + FXParameterEQLowMidFreq, + FXParameterEQMidHighFreq, + FXParameterEQBypass, FXParameterReturnLevel, FXParameterUnknown, }; @@ -120,6 +127,7 @@ class FX {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, + {"EQ", FXParameterEQLow, FXParameterEQBypass}, }; static constexpr uint8_t effects_num = sizeof s_effects / sizeof *s_effects; static constexpr uint8_t slots_num = 3; diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h new file mode 100644 index 000000000..db63375b7 --- /dev/null +++ b/src/effect_3bandeq.h @@ -0,0 +1,95 @@ +/* + * DISTHRO 3 Band EQ + * Ported from https://github.com/DISTRHO/Mini-Series/blob/master/plugins/3BandEQ + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include + +#include "effect_3bandeqmono.h" + +class AudioEffect3BandEQ +{ +public: + AudioEffect3BandEQ(float samplerate): + bypass{}, + eqL{samplerate}, + eqR{samplerate} + { + } + + void setLow_dB(float value) + { + eqL.setLow_dB(value); + eqR.setLow_dB(value); + } + + void setMid_dB(float value) + { + eqL.setMid_dB(value); + eqR.setMid_dB(value); + } + + void setHigh_dB(float value) + { + eqL.setHigh_dB(value); + eqR.setHigh_dB(value); + } + + void setGain_dB(float value) + { + eqL.setGain_dB(value); + eqR.setGain_dB(value); + } + + float setLowMidFreq(float value) + { + eqL.setLowMidFreq(value); + return eqR.setLowMidFreq(value); + } + + float setMidHighFreq(float value) + { + eqL.setMidHighFreq(value); + return eqR.setMidHighFreq(value); + } + + unsigned setLowMidFreq_n(unsigned value) + { + eqL.setLowMidFreq_n(value); + return eqR.setLowMidFreq_n(value); + } + + unsigned setMidHighFreq_n(unsigned value) + { + eqL.setMidHighFreq_n(value); + return eqR.setMidHighFreq_n(value); + } + + float getLow_dB() const { return eqR.getLow_dB(); } + float getMid_dB() const { return eqR.getMid_dB(); } + float getHigh_dB() const { return eqR.getHigh_dB(); } + float getGain_dB() const { return eqR.getGain_dB(); } + float getLowMidFreq() const { return eqR.getLowMidFreq(); } + float getMidHighFreq() const { return eqR.getMidHighFreq(); } + unsigned getLowMidFreq_n() const { return eqR.getLowMidFreq_n(); } + unsigned getMidHighFreq_n() const { return eqR.getMidHighFreq_n(); } + + void resetState() { eqL.resetState(); eqR.resetState(); } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + if (bypass) return; + + eqL.process(blockL, len); + eqR.process(blockR, len); + } + + std::atomic bypass; + +private: + AudioEffect3BandEQMono eqL; + AudioEffect3BandEQMono eqR; +}; diff --git a/src/effect_chain.h b/src/effect_chain.h index 79e02c170..14a2dedfa 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -2,6 +2,7 @@ #include +#include "effect_3bandeq.h" #include "effect_compressor.h" #include "effect_cloudseed2.h" #include "effect_dreamdelay.h" @@ -19,6 +20,7 @@ class AudioFXChain plate_reverb{samplerate}, cloudseed2{samplerate}, compressor{samplerate}, + eq{samplerate}, funcs{ [this](float *inputL, float *inputR, uint16_t len) {}, [this](float *inputL, float *inputR, uint16_t len) { yk_chorus.process(inputL, inputR, len); }, @@ -26,6 +28,7 @@ class AudioFXChain [this](float *inputL, float *inputR, uint16_t len) { plate_reverb.process(inputL, inputR, inputL, inputR, len); }, [this](float *inputL, float *inputR, uint16_t len) { cloudseed2.process(inputL, inputR, len); }, [this](float *inputL, float *inputR, uint16_t len) { compressor.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { eq.process(inputL, inputR, len); }, }, level{} { @@ -49,6 +52,7 @@ class AudioFXChain dream_delay.resetState(); plate_reverb.reset(); compressor.resetState(); + eq.resetState(); cloudseed2.setRampedDown(); cloudseed2.setNeedBufferClear(); @@ -67,6 +71,7 @@ class AudioFXChain AudioEffectPlateReverb plate_reverb; AudioEffectCloudSeed2 cloudseed2; AudioEffectCompressor compressor; + AudioEffect3BandEQ eq; private: std::atomic slots[FX::slots_num]; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2c8685bd3..87be1748c 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1456,6 +1456,46 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne fx_chain[nFX]->compressor.bypass = nValue; break; + case FX::FXParameterEQLow: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setLow_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQMid: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setMid_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQHigh: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setHigh_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQLowMidFreq: + m_FXSpinLock.Acquire (); + m_nFXParameter[nFX][Parameter] = fx_chain[nFX]->eq.setLowMidFreq_n (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQMidHighFreq: + m_FXSpinLock.Acquire (); + m_nFXParameter[nFX][Parameter] = fx_chain[nFX]->eq.setMidHighFreq_n (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQBypass: + fx_chain[nFX]->eq.bypass = nValue; + break; + case FX::FXParameterReturnLevel: m_FXSpinLock.Acquire (); fx_chain[nFX]->set_level (nValue / 99.0f); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 735b01a46..d5ae5a5f7 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -201,6 +201,7 @@ const CUIMenu::TMenuItem CUIMenu::s_FXListMenu[] = {"PlateReverb", MenuHandler, s_PlateReverbMenu}, {"CloudSeed2", MenuHandler, s_CloudSeed2Menu}, {"Compressor", MenuHandler, s_CompressorMenu}, + {"EQ", MenuHandler, s_FXEQMenu}, {0}, }; @@ -350,6 +351,18 @@ const CUIMenu::TMenuItem CUIMenu::s_CompressorMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_FXEQMenu[] = +{ + {"Low Level", EditFXParameter2, 0, FX::FXParameterEQLow}, + {"Mid Level", EditFXParameter2, 0, FX::FXParameterEQMid}, + {"High Level", EditFXParameter2, 0, FX::FXParameterEQHigh}, + {"Gain", EditFXParameter2, 0, FX::FXParameterEQGain}, + {"Low-Mid Freq", EditFXParameter2, 0, FX::FXParameterEQLowMidFreq}, + {"Mid-High Freq", EditFXParameter2, 0, FX::FXParameterEQMidHighFreq}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterEQBypass}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = { {"Low Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLow}, diff --git a/src/uimenu.h b/src/uimenu.h index 6acfc8e5c..a1ef1713e 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -198,6 +198,7 @@ class CUIMenu static const TMenuItem s_CloudSeed2HighShelfMenu[]; static const TMenuItem s_CloudSeed2LowPassMenu[]; static const TMenuItem s_CompressorMenu[]; + static const TMenuItem s_FXEQMenu[]; static const TMenuItem s_MasterEQMenu[]; static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; From 1d6e9a61dfdde064a02687562f695a11db19a648 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 02:46:15 +0100 Subject: [PATCH 107/136] effect_chain: scale only if necessary --- src/effect_chain.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/effect_chain.h b/src/effect_chain.h index 14a2dedfa..c6b347ffd 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -43,8 +43,11 @@ class AudioFXChain if (uint8_t id = slots[i]) funcs[id](inputL, inputR, len); - arm_scale_f32(inputL, level, inputL, len); - arm_scale_f32(inputR, level, inputR, len); + if (level != 1.0f) + { + arm_scale_f32(inputL, level, inputL, len); + arm_scale_f32(inputR, level, inputR, len); + } } void resetState() From a881f430ce1c001a6e00fc0d0cb76abfeb133094 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 02:11:06 +0100 Subject: [PATCH 108/136] use FXChain as master FX --- src/config.h | 10 +- src/mididevice.cpp | 4 +- src/minidexed.cpp | 231 +++++++---------------------------- src/minidexed.h | 29 +---- src/performanceconfig.cpp | 246 +++++++++----------------------------- src/performanceconfig.h | 54 +-------- src/uimenu.cpp | 69 ++++------- src/uimenu.h | 5 +- 8 files changed, 151 insertions(+), 497 deletions(-) diff --git a/src/config.h b/src/config.h index b56a54b05..03b5a98e1 100644 --- a/src/config.h +++ b/src/config.h @@ -43,7 +43,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = 1; static const unsigned AllToneGenerators = 1; static const unsigned DefToneGenerators = AllToneGenerators; + static const unsigned FXMixers = 0; static const unsigned FXChains = 0; + static const unsigned MasterFX = FXMixers; #else #if (RASPPI==4 || RASPPI==5) // Pi 4 and 5 quad core @@ -55,7 +57,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = TGsCore1 + TGsCore1Opt + 2*TGsCore23 + 2*TGsCore23Opt; static const unsigned DefToneGenerators = MinToneGenerators; - static const unsigned FXChains = 2; + static const unsigned FXMixers = 2; + static const unsigned FXChains = FXMixers + 1; + static const unsigned MasterFX = FXMixers; #else // Pi 2 or 3 quad core static const unsigned TGsCore1 = 2; // process 2 TGs on core 1 @@ -65,7 +69,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = MinToneGenerators; static const unsigned DefToneGenerators = AllToneGenerators; - static const unsigned FXChains = 2; + static const unsigned FXMixers = 2; + static const unsigned FXChains = FXMixers + 1; + static const unsigned MasterFX = FXMixers; #endif #endif diff --git a/src/mididevice.cpp b/src/mididevice.cpp index d2da26ef3..748d515b8 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -573,11 +573,11 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case MIDI_CC_EFFECT1_SEND: - m_pSynthesizer->SetFXSend (maplong (pMessage[2], 0, 127, 0, 99), nTG, 0); + m_pSynthesizer->SetFX1Send (maplong (pMessage[2], 0, 127, 0, 99), nTG); break; case MIDI_CC_EFFECT2_SEND: - m_pSynthesizer->SetFXSend (maplong (pMessage[2], 0, 127, 0, 99), nTG, 1); + m_pSynthesizer->SetFX2Send (maplong (pMessage[2], 0, 127, 0, 99), nTG); break; case MIDI_CC_DETUNE_LEVEL: diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 87be1748c..b7dbb5ddc 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -69,8 +69,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, fx_chain {}, tg_mixer {}, sendfx_mixer {}, - m_MasterEQ {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, - m_MasterCompressor {pConfig->GetSampleRate(), pConfig->GetSampleRate()}, m_pNet(nullptr), m_pNetDevice(nullptr), m_WLAN(nullptr), @@ -130,10 +128,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nAftertouchRange[i]=99; m_nAftertouchTarget[i]=0; - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) - { - m_nFXSend[i][nFX] = 25; - } + m_nFX1Send[i] = 25; + m_nFX2Send[i] = 0; m_bCompressorEnable[i] = 0; m_nCompressorPreGain[i] = 0; @@ -269,9 +265,13 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); // END setup tgmixer - for (unsigned nFX = 0; nFX < CConfig::FXChains; nFX++) + for (unsigned nFX = 0; nFX < CConfig::FXMixers; nFX++) { sendfx_mixer[nFX] = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); + } + + for (unsigned nFX = 0; nFX < CConfig::FXChains; nFX++) + { fx_chain[nFX] = new AudioFXChain(pConfig->GetSampleRate()); for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) @@ -281,25 +281,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetFXParameter (FX::TFXParameter(nParam), p.Default, nFX, bSaveOnly); } } - // END setup reverb - SetParameter (ParameterMasterEQLow, 0); - SetParameter (ParameterMasterEQMid, 0); - SetParameter (ParameterMasterEQHigh, 0); - SetParameter (ParameterMasterEQGain, 0); - SetParameter (ParameterMasterEQLowMidFreq, 24); - SetParameter (ParameterMasterEQMidHighFreq, 44); + // END setup reverb SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); - SetParameter (ParameterMasterCompressorEnable, 1); - SetParameter (ParameterMasterCompressorPreGain, 0); - SetParameter (ParameterMasterCompressorThresh, -3); - SetParameter (ParameterMasterCompressorRatio, 20); - SetParameter (ParameterMasterCompressorAttack, 5); - SetParameter (ParameterMasterCompressorRelease, 5); - SetParameter (ParameterMasterCompressorHPFilterEnable, 0); - SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); SetParameter (ParameterPerformanceBank, 0); @@ -368,10 +354,10 @@ bool CMiniDexed::Initialize (void) tg_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); tg_mixer->gain(i,1.0f); - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) { sendfx_mixer[nFX]->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); - sendfx_mixer[nFX]->gain(i,mapfloat(m_nFXSend[i][nFX],0,99,0.0f,1.0f)); + sendfx_mixer[nFX]->gain(i,mapfloat(nFX == 0 ? m_nFX1Send[i] : m_nFX2Send[i],0,99,0.0f,1.0f)); } } @@ -797,7 +783,7 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) tg_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) { sendfx_mixer[nFX]->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); } @@ -805,17 +791,33 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) m_UI.ParameterChanged (); } -void CMiniDexed::SetFXSend (unsigned nFXSend, unsigned nTG, unsigned nFX) +void CMiniDexed::SetFX1Send (unsigned nFX1Send, unsigned nTG) { - nFXSend=constrain((int)nFXSend,0,99); + nFX1Send=constrain((int)nFX1Send,0,99); assert (nTG < CConfig::AllToneGenerators); - assert (nFX < CConfig::FXChains); if (nTG >= m_nToneGenerators) return; // Not an active TG + if (0 >= CConfig::FXMixers) return; + + m_nFX1Send[nTG] = nFX1Send; + + sendfx_mixer[0]->gain(nTG,mapfloat(nFX1Send,0,99,0.0f,1.0f)); + + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetFX2Send (unsigned nFX2Send, unsigned nTG) +{ + nFX2Send=constrain((int)nFX2Send,0,99); + + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + if (1 >= CConfig::FXMixers) return; + + m_nFX2Send[nTG] = nFX2Send; + + sendfx_mixer[1]->gain(nTG,mapfloat(nFX2Send,0,99,0.0f,1.0f)); - m_nFXSend[nTG][nFX] = nFXSend; - sendfx_mixer[nFX]->gain(nTG,mapfloat(nFXSend,0,99,0.0f,1.0f)); - m_UI.ParameterChanged (); } @@ -1088,104 +1090,6 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) m_UI.ParameterChanged (); break; - case ParameterMasterCompressorEnable: - break; - - case ParameterMasterCompressorPreGain: - nValue=constrain(nValue,-20,20); - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].setPreGain_dB(nValue); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterCompressorThresh: - nValue=constrain(nValue,-60,0); - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].setThresh_dBFS(nValue); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterCompressorRatio: - nValue=constrain(nValue,1,(int)CompressorRatioInf); - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].setCompressionRatio(nValue == CompressorRatioInf ? INFINITY : nValue); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterCompressorAttack: - nValue=constrain(nValue,0,1000); - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].setAttack_sec((nValue ?: 1) / 1000.0f, m_pConfig->GetSampleRate()); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterCompressorRelease: - nValue=constrain(nValue,0,2000); - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].setRelease_sec((nValue ?: 1) / 1000.0f, m_pConfig->GetSampleRate()); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterCompressorHPFilterEnable: - m_MasterCompressorSpinLock.Acquire (); - for (int i=0; i<2; ++i) - m_MasterCompressor[i].enableHPFilter(nValue); - m_MasterCompressorSpinLock.Release (); - break; - - case ParameterMasterEQLow: - nValue = constrain(nValue, -24, 24); - m_EQSpinLock.Acquire(); - m_MasterEQ[0].setLow_dB(nValue); - m_MasterEQ[1].setLow_dB(nValue); - m_EQSpinLock.Release(); - break; - - case ParameterMasterEQMid: - nValue = constrain(nValue, -24, 24); - m_EQSpinLock.Acquire(); - m_MasterEQ[0].setMid_dB(nValue); - m_MasterEQ[1].setMid_dB(nValue); - m_EQSpinLock.Release(); - break; - - case ParameterMasterEQHigh: - nValue = constrain(nValue, -24, 24); - m_EQSpinLock.Acquire(); - m_MasterEQ[0].setHigh_dB(nValue); - m_MasterEQ[1].setHigh_dB(nValue); - m_EQSpinLock.Release(); - break; - - case ParameterMasterEQGain: - nValue = constrain(nValue, -24, 24); - m_EQSpinLock.Acquire(); - m_MasterEQ[0].setGain_dB(nValue); - m_MasterEQ[1].setGain_dB(nValue); - m_EQSpinLock.Release(); - break; - - case ParameterMasterEQLowMidFreq: - nValue = constrain(nValue, 0, 46); - m_EQSpinLock.Acquire(); - m_nParameter[ParameterMasterEQLowMidFreq] = m_MasterEQ[0].setLowMidFreq_n(nValue); - m_MasterEQ[1].setLowMidFreq_n(nValue); - m_EQSpinLock.Release(); - break; - - case ParameterMasterEQMidHighFreq: - nValue = constrain(nValue, 28, 59); - m_EQSpinLock.Acquire(); - m_nParameter[ParameterMasterEQMidHighFreq] = m_MasterEQ[0].setMidHighFreq_n(nValue); - m_MasterEQ[1].setMidHighFreq_n(nValue); - m_EQSpinLock.Release(); - break; - case ParameterMixerDryLevel: nValue = constrain(nValue, 0, 99); tg_mixer->gain(mapfloat(nValue,0,99,0.0f,1.0f)); @@ -1592,8 +1496,8 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT SetMIDIChannel ((uint8_t) nValue, i); break; - case TGParameterFX1Send: SetFXSend (nValue, i, 0); break; - case TGParameterFX2Send: SetFXSend (nValue, i, 1); break; + case TGParameterFX1Send: SetFX1Send (nValue, i); break; + case TGParameterFX2Send: SetFX2Send (nValue, i); break; case TGParameterCompressorEnable: SetCompressorEnable (nValue, i); break; case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, i); break; @@ -1633,8 +1537,8 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCutoff: return m_nCutoff[nTG]; case TGParameterResonance: return m_nResonance[nTG]; case TGParameterMIDIChannel: return m_nMIDIChannel[nTG]; - case TGParameterFX1Send: return m_nFXSend[nTG][0]; - case TGParameterFX2Send: return m_nFXSend[nTG][1]; + case TGParameterFX1Send: return m_nFX1Send[nTG]; + case TGParameterFX2Send: return m_nFX2Send[nTG]; case TGParameterPitchBendRange: return m_nPitchBendRange[nTG]; case TGParameterPitchBendStep: return m_nPitchBendStep[nTG]; case TGParameterPortamentoMode: return m_nPortamentoMode[nTG]; @@ -1915,7 +1819,7 @@ void CMiniDexed::ProcessSound (void) // BEGIN adding sendFX float32_t *FXSendBuffer[2]; - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) { if (fx_chain[nFX]->get_level() == 0.0f) continue; @@ -1934,20 +1838,11 @@ void CMiniDexed::ProcessSound (void) arm_add_f32(SampleBuffer[1], FXSendBuffer[1], SampleBuffer[1], nFrames); m_FXSpinLock.Release (); } - // END adding reverb - - m_EQSpinLock.Acquire(); - m_MasterEQ[0].process(SampleBuffer[0], nFrames); - m_MasterEQ[1].process(SampleBuffer[1], nFrames); - m_EQSpinLock.Release(); + // END adding sendFX - if (m_nParameter[ParameterMasterCompressorEnable]) - { - m_MasterCompressorSpinLock.Acquire (); - m_MasterCompressor[0].doCompression (SampleBuffer[0], nFrames); - m_MasterCompressor[1].doCompression (SampleBuffer[1], nFrames); - m_MasterCompressorSpinLock.Release (); - } + m_FXSpinLock.Acquire (); + fx_chain[CConfig::MasterFX]->process(SampleBuffer[0], SampleBuffer[1], nFrames); + m_FXSpinLock.Release (); // swap stereo channels if needed prior to writing back out if (m_bChannelsSwapped) @@ -2089,10 +1984,8 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetAftertouchRange (m_nAftertouchRange[nTG], nTG); m_PerformanceConfig.SetAftertouchTarget (m_nAftertouchTarget[nTG], nTG); - for (unsigned nFX = 0;nFX < CConfig::FXChains; ++nFX) - { - m_PerformanceConfig.SetFXSend (m_nFXSend[nTG][nFX], nTG, nFX); - } + m_PerformanceConfig.SetFX1Send (m_nFX1Send[nTG], nTG); + m_PerformanceConfig.SetFX2Send (m_nFX2Send[nTG], nTG); m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); m_PerformanceConfig.SetCompressorPreGain (m_nCompressorPreGain[nTG], nTG); @@ -2119,21 +2012,6 @@ bool CMiniDexed::DoSavePerformance (void) } } - m_PerformanceConfig.SetMasterEQLow (m_nParameter[ParameterMasterEQLow]); - m_PerformanceConfig.SetMasterEQMid (m_nParameter[ParameterMasterEQMid]); - m_PerformanceConfig.SetMasterEQHigh (m_nParameter[ParameterMasterEQHigh]); - m_PerformanceConfig.SetMasterEQGain (m_nParameter[ParameterMasterEQGain]); - m_PerformanceConfig.SetMasterEQLowMidFreq (m_nParameter[ParameterMasterEQLowMidFreq]); - m_PerformanceConfig.SetMasterEQMidHighFreq (m_nParameter[ParameterMasterEQMidHighFreq]); - - m_PerformanceConfig.SetMasterCompressorEnable (m_nParameter[ParameterMasterCompressorEnable]); - m_PerformanceConfig.SetMasterCompressorPreGain (m_nParameter[ParameterMasterCompressorPreGain]); - m_PerformanceConfig.SetMasterCompressorThresh (m_nParameter[ParameterMasterCompressorThresh]); - m_PerformanceConfig.SetMasterCompressorRatio (m_nParameter[ParameterMasterCompressorRatio]); - m_PerformanceConfig.SetMasterCompressorAttack (m_nParameter[ParameterMasterCompressorAttack]); - m_PerformanceConfig.SetMasterCompressorRelease (m_nParameter[ParameterMasterCompressorRelease]); - m_PerformanceConfig.SetMasterCompressorHPFilterEnable (m_nParameter[ParameterMasterCompressorHPFilterEnable]); - m_PerformanceConfig.SetMixerDryLevel (m_nParameter[ParameterMixerDryLevel]); if(m_bSaveAsDeault) @@ -2806,10 +2684,8 @@ void CMiniDexed::LoadPerformanceParameters(void) setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); setTGLink(m_PerformanceConfig.GetTGLink(nTG), nTG); - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) - { - SetFXSend (m_PerformanceConfig.GetFXSend (nTG, nFX), nTG, nFX); - } + SetFX1Send (m_PerformanceConfig.GetFX1Send (nTG), nTG); + SetFX2Send (m_PerformanceConfig.GetFX2Send (nTG), nTG); setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); @@ -2847,21 +2723,6 @@ void CMiniDexed::LoadPerformanceParameters(void) } } - SetParameter (ParameterMasterEQLow, m_PerformanceConfig.GetMasterEQLow ()); - SetParameter (ParameterMasterEQMid, m_PerformanceConfig.GetMasterEQMid ()); - SetParameter (ParameterMasterEQHigh, m_PerformanceConfig.GetMasterEQHigh ()); - SetParameter (ParameterMasterEQGain, m_PerformanceConfig.GetMasterEQGain ()); - SetParameter (ParameterMasterEQLowMidFreq, m_PerformanceConfig.GetMasterEQLowMidFreq ()); - SetParameter (ParameterMasterEQMidHighFreq, m_PerformanceConfig.GetMasterEQMidHighFreq ()); - - SetParameter (ParameterMasterCompressorEnable, m_PerformanceConfig.GetMasterCompressorEnable ()); - SetParameter (ParameterMasterCompressorPreGain, m_PerformanceConfig.GetMasterCompressorPreGain ()); - SetParameter (ParameterMasterCompressorThresh, m_PerformanceConfig.GetMasterCompressorThresh ()); - SetParameter (ParameterMasterCompressorRatio, m_PerformanceConfig.GetMasterCompressorRatio ()); - SetParameter (ParameterMasterCompressorAttack, m_PerformanceConfig.GetMasterCompressorAttack ()); - SetParameter (ParameterMasterCompressorRelease, m_PerformanceConfig.GetMasterCompressorRelease ()); - SetParameter (ParameterMasterCompressorHPFilterEnable, m_PerformanceConfig.GetMasterCompressorHPFilterEnable ()); - SetParameter (ParameterMixerDryLevel, m_PerformanceConfig.GetMixerDryLevel ()); m_UI.DisplayChanged (); diff --git a/src/minidexed.h b/src/minidexed.h index cc6447c95..7b3359ebe 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -51,8 +51,6 @@ #include "effect_mixer.hpp" #include "udpmididevice.h" #include "net/ftpdaemon.h" -#include "compressor.h" -#include "effect_3bandeqmono.h" #include "effect_chain.h" class CMiniDexed @@ -108,7 +106,8 @@ class CMiniDexed void setBreathController (uint8_t value, unsigned nTG); void setAftertouch (uint8_t value, unsigned nTG); - void SetFXSend (unsigned nFXSend, unsigned nTG, unsigned nFX); // 0 .. 99 + void SetFX1Send (unsigned nFXSend, unsigned nTG); // 0 .. 99 + void SetFX2Send (unsigned nFXSend, unsigned nTG); // 0 .. 99 void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) @@ -188,19 +187,6 @@ class CMiniDexed ParameterPerformanceSelectChannel, ParameterPerformanceBank, ParameterMasterVolume, - ParameterMasterCompressorEnable, - ParameterMasterCompressorPreGain, - ParameterMasterCompressorThresh, - ParameterMasterCompressorRatio, - ParameterMasterCompressorAttack, - ParameterMasterCompressorRelease, - ParameterMasterCompressorHPFilterEnable, - ParameterMasterEQLow, - ParameterMasterEQMid, - ParameterMasterEQHigh, - ParameterMasterEQGain, - ParameterMasterEQLowMidFreq, - ParameterMasterEQMidHighFreq, ParameterMixerDryLevel, ParameterUnknown }; @@ -364,7 +350,8 @@ class CMiniDexed unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - unsigned m_nFXSend[CConfig::AllToneGenerators][CConfig::FXChains]; + unsigned m_nFX1Send[CConfig::AllToneGenerators]; + unsigned m_nFX2Send[CConfig::AllToneGenerators]; bool m_bCompressorEnable[CConfig::AllToneGenerators]; int m_nCompressorPreGain[CConfig::AllToneGenerators]; @@ -414,16 +401,10 @@ class CMiniDexed AudioFXChain* fx_chain[CConfig::FXChains]; AudioStereoMixer* tg_mixer; - AudioStereoMixer* sendfx_mixer[CConfig::FXChains]; + AudioStereoMixer* sendfx_mixer[CConfig::FXMixers]; CSpinLock m_FXSpinLock; - AudioEffect3BandEQMono m_MasterEQ[2]; - CSpinLock m_EQSpinLock; - - Compressor m_MasterCompressor[2]; - CSpinLock m_MasterCompressorSpinLock; - CStatus m_Status; // Network diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 8ca946495..5c034441e 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -164,19 +164,19 @@ bool CPerformanceConfig::Load (void) m_nNoteShift[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); PropertyName.Format ("FX1Send%u", nTG+1); - m_nFXSend[nTG][0] = m_Properties.GetNumber (PropertyName, 25); + m_nFX1Send[nTG] = m_Properties.GetNumber (PropertyName, 25); PropertyName.Format ("FX2Send%u", nTG+1); - m_nFXSend[nTG][1] = m_Properties.GetNumber (PropertyName, 0); + m_nFX2Send[nTG] = m_Properties.GetNumber (PropertyName, 0); // compatibility ReverbSend[n] => FX1Send[n] PropertyName.Format ("ReverbSend%u", nTG+1); - if (m_Properties.IsSet (PropertyName) && CConfig::FXChains) + if (m_Properties.IsSet (PropertyName)) { - // the volume calculated by x^4, but FxSend uses x^2 + // the volume calculated by x^4, but FX1Send uses x^2 float32_t reverbSend = m_Properties.GetNumber (PropertyName, 50); reverbSend = pow(mapfloat(reverbSend, 0.0f, 99.0f, 0.0f, 1.0f), 2); - m_nFXSend[nTG][0] = mapfloat(reverbSend, 0.0f, 1.0f, 0, 99); + m_nFX1Send[nTG] = mapfloat(reverbSend, 0.0f, 1.0f, 0, 99); } PropertyName.Format ("PitchBendRange%u", nTG+1); @@ -275,7 +275,10 @@ bool CPerformanceConfig::Load (void) { const FX::FXParameterType &p = FX::s_FXParameter[nParam]; - PropertyName.Format ("FX%u%s", nFX+1, p.Name); + if (nFX == CConfig::MasterFX) + PropertyName.Format ("MasterFX%s", p.Name); + else + PropertyName.Format ("SendFX%u%s", nFX+1, p.Name); if (p.Flags & FX::FXSaveAsString) m_nFXParameter[nFX][nParam] = FX::getIDFromName(FX::TFXParameter(nParam), m_Properties.GetString (PropertyName, "")); @@ -284,33 +287,26 @@ bool CPerformanceConfig::Load (void) } } - m_nMasterEQLow = m_Properties.GetSignedNumber ("MasterEQLow", 0); - m_nMasterEQMid = m_Properties.GetSignedNumber ("MasterEQMid", 0); - m_nMasterEQHigh = m_Properties.GetSignedNumber ("MasterEQHigh", 0); - m_nMasterEQGain = m_Properties.GetSignedNumber ("MasterEQGain", 0); - m_nMasterEQLowMidFreq = m_Properties.GetNumber ("MasterEQLowMidFreq", 24); - m_nMasterEQMidHighFreq = m_Properties.GetNumber ("MasterEQMidHighFreq", 44); - - m_bMasterCompressorEnable = m_Properties.GetNumber ("MasterCompressorEnable", 1); - m_nMasterCompressorPreGain = m_Properties.GetSignedNumber ("MasterCompressorPreGain", 0); - m_nMasterCompressorThresh = m_Properties.GetSignedNumber ("MasterCompressorThresh", -3); - m_nMasterCompressorRatio = m_Properties.GetNumber ("MasterCompressorRatio", 20); - m_nMasterCompressorAttack = m_Properties.GetNumber ("MasterCompressorAttack", 5); - m_nMasterCompressorRelease = m_Properties.GetNumber ("MasterCompressorRelease", 5); - m_bMasterCompressorHPFilterEnable = m_Properties.GetNumber ("MasterCompressorHPFilterEnable", 0); + if (CConfig::FXChains) + { + m_nFXParameter[CConfig::MasterFX][FX::FXParameterReturnLevel] = FX::s_FXParameter[FX::FXParameterReturnLevel].Maximum; + } m_nMixerDryLevel = m_Properties.GetNumber ("MixerDryLevel", 99); // Compatibility - if (m_Properties.IsSet ("CompressorEnable")) + if (m_Properties.IsSet ("CompressorEnable") && CConfig::FXChains) { - m_bMasterCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1); - m_nMasterCompressorPreGain = 0; - m_nMasterCompressorThresh = -7; - m_nMasterCompressorRatio = 5; - m_nMasterCompressorAttack = 0; - m_nMasterCompressorRelease = 200; - m_bMasterCompressorHPFilterEnable = 1; + bool bHasCompressor = m_Properties.GetNumber ("CompressorEnable", 0); + + m_nFXParameter[CConfig::MasterFX][FX::FXParameterSlot0] = bHasCompressor ? FX::getIDFromName(FX::FXParameterSlot0, "Compressor") : 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorPreGain] = 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorThresh] = -7; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorRatio] = 5; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorAttack] = 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorRelease] = 200; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorHPFilterEnable] = 1; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorBypass] = 0; } if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) @@ -383,11 +379,11 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("NoteShift%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nNoteShift[nTG]); - for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) - { - PropertyName.Format ("FX%uSend%u", nFX+1, nTG+1); - m_Properties.SetNumber (PropertyName, m_nFXSend[nTG][nFX]); - } + PropertyName.Format ("FX1Send%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nFX1Send[nTG]); + + PropertyName.Format ("FX2Send%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nFX2Send[nTG]); PropertyName.Format ("PitchBendRange%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nPitchBendRange[nTG]); @@ -483,13 +479,19 @@ bool CPerformanceConfig::Save (void) { CString PropertyName; + CString FXName; + if (nFX == CConfig::MasterFX) + FXName = "MasterFX"; + else + FXName.Format ("SendFX%u", nFX+1); + for (unsigned nSlot = 0; nSlot < 3; ++nSlot) { unsigned nSlotParam = FX::FXParameterSlot0 + nSlot; unsigned nEffectID = m_nFXParameter[nFX][nSlotParam]; const FX::EffectType &effect = FX::s_effects[nEffectID]; - PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[nSlotParam].Name); + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[nSlotParam].Name); m_Properties.SetString (PropertyName, effect.Name); } @@ -504,7 +506,7 @@ bool CPerformanceConfig::Save (void) for (unsigned nParam = effect.MinID; nParam <= effect.MaxID; ++nParam) { const FX::FXParameterType &p = FX::s_FXParameter[nParam]; - PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[nParam].Name); + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[nParam].Name); if (p.Flags & FX::FXSaveAsString) m_Properties.SetString (PropertyName, FX::getNameFromID(FX::TFXParameter(nParam), m_nFXParameter[nFX][nParam])); @@ -513,25 +515,13 @@ bool CPerformanceConfig::Save (void) } } - PropertyName.Format ("FX%u%s", nFX+1, FX::s_FXParameter[FX::FXParameterReturnLevel].Name); - m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterReturnLevel]); + if (nFX != CConfig::MasterFX) + { + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[FX::FXParameterReturnLevel].Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterReturnLevel]); + } } - m_Properties.SetSignedNumber ("MasterEQLow", m_nMasterEQLow); - m_Properties.SetSignedNumber ("MasterEQMid", m_nMasterEQMid); - m_Properties.SetSignedNumber ("MasterEQHigh", m_nMasterEQHigh); - m_Properties.SetSignedNumber ("MasterEQGain", m_nMasterEQGain); - m_Properties.SetNumber ("MasterEQLowMidFreq", m_nMasterEQLowMidFreq); - m_Properties.SetNumber ("MasterEQMidHighFreq", m_nMasterEQMidHighFreq); - - m_Properties.SetNumber ("MasterCompressorEnable", m_bMasterCompressorEnable); - m_Properties.SetSignedNumber ("MasterCompressorPreGain", m_nMasterCompressorPreGain); - m_Properties.SetSignedNumber ("MasterCompressorThresh", m_nMasterCompressorThresh); - m_Properties.SetNumber ("MasterCompressorRatio", m_nMasterCompressorRatio); - m_Properties.SetNumber ("MasterCompressorAttack", m_nMasterCompressorAttack); - m_Properties.SetNumber ("MasterCompressorRelease", m_nMasterCompressorRelease); - m_Properties.SetNumber ("MasterCompressorHPFilterEnable", m_bMasterCompressorHPFilterEnable); - m_Properties.SetNumber ("MixerDryLevel", m_nMixerDryLevel); return m_Properties.Save (); @@ -603,11 +593,16 @@ int CPerformanceConfig::GetNoteShift (unsigned nTG) const return m_nNoteShift[nTG]; } -unsigned CPerformanceConfig::GetFXSend (unsigned nTG, unsigned nFX) const +unsigned CPerformanceConfig::GetFX1Send (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - assert (nFX < CConfig::FXChains); - return m_nFXSend[nTG][nFX]; + return m_nFX1Send[nTG]; +} + +unsigned CPerformanceConfig::GetFX2Send (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nFX2Send[nTG]; } void CPerformanceConfig::SetBankNumber (unsigned nValue, unsigned nTG) @@ -676,11 +671,16 @@ void CPerformanceConfig::SetNoteShift (int nValue, unsigned nTG) m_nNoteShift[nTG] = nValue; } -void CPerformanceConfig::SetFXSend (unsigned nValue, unsigned nTG, unsigned nFX) +void CPerformanceConfig::SetFX1Send (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - assert (nFX < CConfig::FXChains); - m_nFXSend[nTG][nFX] = nValue; + m_nFX1Send[nTG] = nValue; +} + +void CPerformanceConfig::SetFX2Send (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nFX2Send[nTG] = nValue; } int CPerformanceConfig::GetEQLow (unsigned nTG) const @@ -769,136 +769,6 @@ void CPerformanceConfig::SetFXParameter (FX::TFXParameter nParameter, int nValue m_nFXParameter[nFX][nParameter] = nValue; } -int CPerformanceConfig::GetMasterEQLow () const -{ - return m_nMasterEQLow; -} - -int CPerformanceConfig::GetMasterEQMid () const -{ - return m_nMasterEQMid; -} - -int CPerformanceConfig::GetMasterEQHigh () const -{ - return m_nMasterEQHigh; -} - -int CPerformanceConfig::GetMasterEQGain () const -{ - return m_nMasterEQGain; -} - -unsigned CPerformanceConfig::GetMasterEQLowMidFreq () const -{ - return m_nMasterEQLowMidFreq; -} - -unsigned CPerformanceConfig::GetMasterEQMidHighFreq () const -{ - return m_nMasterEQMidHighFreq; -} - -void CPerformanceConfig::SetMasterEQLow (int nValue) -{ - m_nMasterEQLow = nValue; -} - -void CPerformanceConfig::SetMasterEQMid (int nValue) -{ - m_nMasterEQMid = nValue; -} - -void CPerformanceConfig::SetMasterEQHigh (int nValue) -{ - m_nMasterEQHigh = nValue; -} - -void CPerformanceConfig::SetMasterEQGain (int nValue) -{ - m_nMasterEQGain = nValue; -} - -void CPerformanceConfig::SetMasterEQLowMidFreq (unsigned nValue) -{ - m_nMasterEQLowMidFreq = nValue; -} - -void CPerformanceConfig::SetMasterEQMidHighFreq (unsigned nValue) -{ - m_nMasterEQMidHighFreq = nValue; -} - -bool CPerformanceConfig::GetMasterCompressorEnable () const -{ - return m_bMasterCompressorEnable; -} - -int CPerformanceConfig::GetMasterCompressorPreGain () const -{ - return m_nMasterCompressorPreGain; -} - -int CPerformanceConfig::GetMasterCompressorThresh () const -{ - return m_nMasterCompressorThresh; -} - -unsigned CPerformanceConfig::GetMasterCompressorRatio () const -{ - return m_nMasterCompressorRatio; -} - -unsigned CPerformanceConfig::GetMasterCompressorAttack () const -{ - return m_nMasterCompressorAttack; -} - -unsigned CPerformanceConfig::GetMasterCompressorRelease () const -{ - return m_nMasterCompressorRelease; -} - -bool CPerformanceConfig::GetMasterCompressorHPFilterEnable () const -{ - return m_bMasterCompressorHPFilterEnable; -} - -void CPerformanceConfig::SetMasterCompressorEnable (bool nValue) -{ - m_bMasterCompressorEnable = nValue; -} - -void CPerformanceConfig::SetMasterCompressorPreGain (int nValue) -{ - m_nMasterCompressorPreGain= nValue; -} - -void CPerformanceConfig::SetMasterCompressorThresh (int nValue) -{ - m_nMasterCompressorThresh = nValue; -} - -void CPerformanceConfig::SetMasterCompressorRatio (unsigned nValue) -{ - m_nMasterCompressorRatio = nValue; -} - -void CPerformanceConfig::SetMasterCompressorAttack (unsigned nValue) -{ - m_nMasterCompressorAttack = nValue; -} - -void CPerformanceConfig::SetMasterCompressorRelease (unsigned nValue) -{ - m_nMasterCompressorRelease = nValue; -} - -void CPerformanceConfig::SetMasterCompressorHPFilterEnable (bool nValue) -{ - m_bMasterCompressorHPFilterEnable = nValue; -} - unsigned CPerformanceConfig::GetMixerDryLevel () const { return m_nMixerDryLevel; diff --git a/src/performanceconfig.h b/src/performanceconfig.h index afd140161..c935b34f7 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -55,7 +55,8 @@ class CPerformanceConfig // Performance configuration unsigned GetNoteLimitLow (unsigned nTG) const; // 0 .. 127 unsigned GetNoteLimitHigh (unsigned nTG) const; // 0 .. 127 int GetNoteShift (unsigned nTG) const; // -24 .. 24 - unsigned GetFXSend (unsigned nTG, unsigned nFX) const; // 0 .. 127 + unsigned GetFX1Send (unsigned nTG) const; // 0 .. 99 + unsigned GetFX2Send (unsigned nTG) const; // 0 .. 99 unsigned GetPitchBendRange (unsigned nTG) const; // 0 .. 12 unsigned GetPitchBendStep (unsigned nTG) const; // 0 .. 12 unsigned GetPortamentoMode (unsigned nTG) const; // 0 .. 1 @@ -92,7 +93,8 @@ class CPerformanceConfig // Performance configuration void SetNoteLimitLow (unsigned nValue, unsigned nTG); void SetNoteLimitHigh (unsigned nValue, unsigned nTG); void SetNoteShift (int nValue, unsigned nTG); - void SetFXSend (unsigned nValue, unsigned nTG, unsigned nFX); + void SetFX1Send (unsigned nValue, unsigned nTG); + void SetFX2Send (unsigned nValue, unsigned nTG); void SetPitchBendRange (unsigned nValue, unsigned nTG); void SetPitchBendStep (unsigned nValue, unsigned nTG); void SetPortamentoMode (unsigned nValue, unsigned nTG); @@ -138,36 +140,6 @@ class CPerformanceConfig // Performance configuration int GetFXParameter (FX::TFXParameter nParameter, unsigned nFX) const; void SetFXParameter (FX::TFXParameter nParameter, int nValue, unsigned nFX); - int GetMasterEQLow () const; - int GetMasterEQMid () const; - int GetMasterEQHigh () const; - int GetMasterEQGain () const; - unsigned GetMasterEQLowMidFreq () const; - unsigned GetMasterEQMidHighFreq () const; - - void SetMasterEQLow (int nValue); - void SetMasterEQMid (int nValue); - void SetMasterEQHigh (int nValue); - void SetMasterEQGain (int nValue); - void SetMasterEQLowMidFreq (unsigned nValue); - void SetMasterEQMidHighFreq (unsigned nValue); - - bool GetMasterCompressorEnable () const; - int GetMasterCompressorPreGain () const; - int GetMasterCompressorThresh () const; - unsigned GetMasterCompressorRatio () const; - unsigned GetMasterCompressorAttack () const; - unsigned GetMasterCompressorRelease () const; - bool GetMasterCompressorHPFilterEnable () const; - - void SetMasterCompressorEnable (bool nValue); - void SetMasterCompressorPreGain (int nValue); - void SetMasterCompressorThresh (int nValue); - void SetMasterCompressorRatio (unsigned nValue); - void SetMasterCompressorAttack (unsigned nValue); - void SetMasterCompressorRelease (unsigned nValue); - void SetMasterCompressorHPFilterEnable (bool nValue); - unsigned GetMixerDryLevel () const; void SetMixerDryLevel (unsigned nValue); @@ -216,7 +188,8 @@ class CPerformanceConfig // Performance configuration unsigned m_nNoteLimitLow[CConfig::AllToneGenerators]; unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - int m_nFXSend[CConfig::AllToneGenerators][CConfig::FXChains]; + int m_nFX1Send[CConfig::AllToneGenerators]; + int m_nFX2Send[CConfig::AllToneGenerators]; unsigned m_nPitchBendRange[CConfig::AllToneGenerators]; unsigned m_nPitchBendStep[CConfig::AllToneGenerators]; unsigned m_nPortamentoMode[CConfig::AllToneGenerators]; @@ -265,21 +238,6 @@ class CPerformanceConfig // Performance configuration int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; - int m_nMasterEQLow; - int m_nMasterEQMid; - int m_nMasterEQHigh; - int m_nMasterEQGain; - unsigned m_nMasterEQLowMidFreq; - unsigned m_nMasterEQMidHighFreq; - - bool m_bMasterCompressorEnable; - int m_nMasterCompressorPreGain; - int m_nMasterCompressorThresh; - unsigned m_nMasterCompressorRatio; - unsigned m_nMasterCompressorAttack; - unsigned m_nMasterCompressorRelease; - bool m_bMasterCompressorHPFilterEnable; - unsigned m_nMixerDryLevel; }; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index d5ae5a5f7..80bf87ffa 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -177,14 +177,13 @@ const CUIMenu::TMenuItem CUIMenu::s_MixerMenu[] = const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = { - {"SendFX1", MenuHandler, s_FXMenu, 0}, - {"SendFX2", MenuHandler, s_FXMenu, 1}, - {"EQ", MenuHandler, s_MasterEQMenu}, - {"Compressor", MenuHandler, s_MasterCompressorMenu}, + {"SendFX1", MenuHandler, s_SendFXMenu, 0}, + {"SendFX2", MenuHandler, s_SendFXMenu, 1}, + {"MasterFX", MenuHandler, s_MasterFXMenu, CConfig::MasterFX}, {0} }; -const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = +const CUIMenu::TMenuItem CUIMenu::s_SendFXMenu[] = { {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, @@ -193,6 +192,14 @@ const CUIMenu::TMenuItem CUIMenu::s_FXMenu[] = {0}, }; +const CUIMenu::TMenuItem CUIMenu::s_MasterFXMenu[] = +{ + {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {0}, +}; + const CUIMenu::TMenuItem CUIMenu::s_FXListMenu[] = { {"None"}, @@ -363,29 +370,6 @@ const CUIMenu::TMenuItem CUIMenu::s_FXEQMenu[] = {0} }; -const CUIMenu::TMenuItem CUIMenu::s_MasterEQMenu[] = -{ - {"Low Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLow}, - {"Mid Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQMid}, - {"High Level", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQHigh}, - {"Gain", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQGain}, - {"Low-Mid Freq", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQLowMidFreq}, - {"Mid-High Freq", EditGlobalParameter, 0, CMiniDexed::ParameterMasterEQMidHighFreq}, - {0} -}; - -const CUIMenu::TMenuItem CUIMenu::s_MasterCompressorMenu[] = -{ - {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorEnable}, - {"Pre Gain", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorPreGain}, - {"Threshold", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorThresh}, - {"Ratio", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorRatio}, - {"Attack", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorAttack}, - {"Release", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorRelease}, - {"HPFilter", EditGlobalParameter, 0, CMiniDexed::ParameterMasterCompressorHPFilterEnable}, - {0} -}; - #endif // inserting menu items before "OP1" affect OPShortcutHandler() @@ -461,19 +445,6 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank {0, 127, 8, ToVolume}, // ParameterMasterVolume - {0, 1, 1, ToOnOff}, // ParameterMasterCompressorEnable - {-20, 20, 1, TodB}, // ParameterMasterCompressorPreGain - {-60, 0, 1, TodBFS}, // ParameterMasterCompressorThresh - {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // ParameterMasterCompressorRatio - {0, 1000, 5, ToMillisec}, // ParameterMasterCompressorAttack - {0, 2000, 5, ToMillisec}, // ParameterMasterCompressorRelease - {0, 1, 1, ToOnOff}, // ParameterMasterCompressorHPFilterEnable - {-24, 24, 1, TodB}, // ParameterMasterEQLow - {-24, 24, 1, TodB}, // ParameterMasterEQMid - {-24, 24, 1, TodB}, // ParameterMasterEQHigh - {-24, 24, 1, TodB}, // ParameterMasterEQGain - {0, 46, 1, ToHz}, // ParameterMasterEQLowMidFreq - {28, 59, 1, ToHz}, // ParameterMasterEQMidHighFreq {0, 99, 1}, // ParameterMixerDryLevel }; @@ -1307,7 +1278,9 @@ void CUIMenu::EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) return; } - std::string FX = std::string("FX") + std::to_string (nFX+1); + std::string FX; + if (nFX == CConfig::MasterFX) FX = "MFX"; + else FX = std::string("FX") + std::to_string (nFX+1); std::string Value = GetFXValueString (Param, pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), @@ -1355,7 +1328,9 @@ void CUIMenu::EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event) return; } - std::string FX = std::string("FX") + std::to_string (nFX+1); + std::string FX; + if (nFX == CConfig::MasterFX) FX = "MFX"; + else FX = std::string("FX") + std::to_string (nFX+1); std::string Value = GetFXValueString (Param, pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), @@ -1841,8 +1816,12 @@ void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) { #ifdef ARM_ALLOW_MULTI_CORE if (m_pParentMenu == s_PlateReverbMenu || - m_pParentMenu == s_MasterEQMenu || - m_pParentMenu == s_MasterCompressorMenu || + m_pParentMenu == s_YKChorusMenu || + m_pParentMenu == s_DreamDelayMenu || + m_pParentMenu == s_FXEQMenu || + m_pParentMenu == s_CompressorMenu || + m_pParentMenu == s_EditCompressorMenu || + m_pParentMenu == s_EQMenu || m_pCurrentMenu == s_TGMenu) { bool bSaveCurrentSelection = m_pCurrentMenu == s_TGMenu; diff --git a/src/uimenu.h b/src/uimenu.h index a1ef1713e..aff38a188 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -180,7 +180,8 @@ class CUIMenu static const TMenuItem s_MenuRoot[]; static const TMenuItem s_MainMenu[]; static const TMenuItem s_TGMenu[]; - static const TMenuItem s_FXMenu[]; + static const TMenuItem s_SendFXMenu[]; + static const TMenuItem s_MasterFXMenu[]; static const TMenuItem s_FXListMenu[]; static const TMenuItem s_MixerMenu[]; static const TMenuItem s_EffectsMenu[]; @@ -199,8 +200,6 @@ class CUIMenu static const TMenuItem s_CloudSeed2LowPassMenu[]; static const TMenuItem s_CompressorMenu[]; static const TMenuItem s_FXEQMenu[]; - static const TMenuItem s_MasterEQMenu[]; - static const TMenuItem s_MasterCompressorMenu[]; static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; From bccaf3816457e5cc569f8ba388c6c8c1bf4711ba Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 04:42:44 +0100 Subject: [PATCH 109/136] effect_ykchorus: add bypass --- src/effect.cpp | 1 + src/effect.h | 3 ++- src/effect_ykchorus.h | 10 +++++++++- src/minidexed.cpp | 4 ++++ src/uimenu.cpp | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/effect.cpp b/src/effect.cpp index dca81a00d..fda8ee6ac 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -108,6 +108,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, {0, 100, 50, 1, "YKChorusLFORate1"}, {0, 100, 83, 1, "YKChorusLFORate2"}, + {0, 1, 0, 1, "YKChorusBypass", ToOnOff}, {0, 100, 0, 1, "DreamDelayMix", ToDryWet}, {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, diff --git a/src/effect.h b/src/effect.h index b97ddb209..25f5b08d8 100644 --- a/src/effect.h +++ b/src/effect.h @@ -19,6 +19,7 @@ class FX FXParameterYKChorusEnable2, FXParameterYKChorusLFORate1, FXParameterYKChorusLFORate2, + FXParameterYKChorusBypass, FXParameterDreamDelayMix, FXParameterDreamDelayMode, FXParameterDreamDelayTime, @@ -122,7 +123,7 @@ class FX static constexpr const EffectType s_effects[] = { {"None"}, - {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusLFORate2}, + {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusBypass}, {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayHighCut}, {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, diff --git a/src/effect_ykchorus.h b/src/effect_ykchorus.h index 05f567876..f400f6731 100644 --- a/src/effect_ykchorus.h +++ b/src/effect_ykchorus.h @@ -6,12 +6,16 @@ #pragma once +#include + #include "ykchorus/ChorusEngine.h" class AudioEffectYKChorus { public: - AudioEffectYKChorus(float samplerate) : engine {samplerate} + AudioEffectYKChorus(float samplerate): + bypass{}, + engine{samplerate} { setChorus1(true); setChorus2(true); @@ -52,6 +56,8 @@ class AudioEffectYKChorus void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) { + if (bypass) return; + if (wet == 0.0f) return; if (!engine.isChorus1Enabled && !engine.isChorus2Enabled) return; @@ -62,6 +68,8 @@ class AudioEffectYKChorus } } + std::atomic bypass; + private: ChorusEngine engine; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b7dbb5ddc..1f585733c 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1159,6 +1159,10 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; + case FX::FXParameterYKChorusBypass: + fx_chain[nFX]->yk_chorus.bypass = nValue; + break; + case FX::FXParameterDreamDelayMix: m_FXSpinLock.Acquire (); fx_chain[nFX]->dream_delay.setMix (nValue / 100.0f); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 80bf87ffa..2c1cd8b37 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -219,6 +219,7 @@ const CUIMenu::TMenuItem CUIMenu::s_YKChorusMenu[] = {"Enable II", EditFXParameter2, 0, FX::FXParameterYKChorusEnable2}, {"LFO Rate I", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate1}, {"LFO Rate II", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate2}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterYKChorusBypass}, {0} }; From 2ad782c36ba3cfbd6ccdc67f09a4e760aa03f611 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 04:53:17 +0100 Subject: [PATCH 110/136] effect_dreamdelay: add bypass --- src/effect.cpp | 1 + src/effect.h | 3 ++- src/effect_dreamdelay.cpp | 3 +++ src/effect_dreamdelay.h | 3 +++ src/minidexed.cpp | 4 ++++ src/uimenu.cpp | 1 + 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/effect.cpp b/src/effect.cpp index fda8ee6ac..d219adb8f 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -117,6 +117,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, {0, 100, 60, 1, "DreamDelayFeedback"}, {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, + {0, 1, 0, 1, "DreamDelayBypass", ToOnOff}, {0, 100, 0, 1, "PlateReverbMix", ToDryWet}, {0, 99, 50, 1, "PlateReverbSize"}, {0, 99, 25, 1, "PlateReverbHighDamp"}, diff --git a/src/effect.h b/src/effect.h index 25f5b08d8..0ce5034de 100644 --- a/src/effect.h +++ b/src/effect.h @@ -28,6 +28,7 @@ class FX FXParameterDreamDelayTempo, FXParameterDreamDelayFeedback, FXParameterDreamDelayHighCut, + FXParameterDreamDelayBypass, FXParameterPlateReverbMix, FXParameterPlateReverbSize, FXParameterPlateReverbHighDamp, @@ -124,7 +125,7 @@ class FX static constexpr const EffectType s_effects[] = { {"None"}, {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusBypass}, - {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayHighCut}, + {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayBypass}, {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, diff --git a/src/effect_dreamdelay.cpp b/src/effect_dreamdelay.cpp index 0d77acd71..6f2f2a553 100644 --- a/src/effect_dreamdelay.cpp +++ b/src/effect_dreamdelay.cpp @@ -5,6 +5,7 @@ constexpr float32_t MAX_DELAY_TIME = 2.0f; AudioEffectDreamDelay::AudioEffectDreamDelay(float32_t samplerate): +bypass{}, samplerate{samplerate}, mode{DUAL}, bufferSize{(size_t)(samplerate * MAX_DELAY_TIME)}, @@ -93,6 +94,8 @@ void AudioEffectDreamDelay::setMix(float32_t value) void AudioEffectDreamDelay::process(float32_t* blockL, float32_t* blockR, uint16_t len) { + if (bypass) return; + if (wet == 0.0f) return; switch(mode) diff --git a/src/effect_dreamdelay.h b/src/effect_dreamdelay.h index 2056b53dd..3eb9e22a1 100644 --- a/src/effect_dreamdelay.h +++ b/src/effect_dreamdelay.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include "common.h" @@ -36,6 +37,8 @@ class AudioEffectDreamDelay void resetState(); + std::atomic bypass; + private: float32_t samplerate; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 1f585733c..38dd74308 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1230,6 +1230,10 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; + case FX::FXParameterDreamDelayBypass: + fx_chain[nFX]->dream_delay.bypass = nValue; + break; + case FX::FXParameterPlateReverbMix: m_FXSpinLock.Acquire (); fx_chain[nFX]->plate_reverb.set_mix (nValue / 100.0f); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 2c1cd8b37..50c0d6488 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -233,6 +233,7 @@ const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = {"Tempo", EditFXParameter2, 0, FX::FXParameterDreamDelayTempo}, {"Feedback", EditFXParameter2, 0, FX::FXParameterDreamDelayFeedback}, {"HighCut", EditFXParameter2, 0, FX::FXParameterDreamDelayHighCut}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterDreamDelayBypass}, {0} }; From 95e34be0d13b964bd9ba33e6aa431ec85ac6116e Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 04:55:20 +0100 Subject: [PATCH 111/136] effect_platereverb: add bypass --- src/effect.cpp | 1 + src/effect.h | 3 ++- src/effect_platervbstereo.cpp | 5 ++++- src/effect_platervbstereo.h | 4 ++++ src/minidexed.cpp | 4 ++++ src/uimenu.cpp | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/effect.cpp b/src/effect.cpp index d219adb8f..fd1fce1a4 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -124,6 +124,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {0, 99, 25, 1, "PlateReverbLowDamp"}, {0, 99, 85, 1, "PlateReverbLowPass"}, {0, 99, 65, 1, "PlateReverbDiffusion"}, + {0, 1, 0, 1, "PlateReverbBypass", ToOnOff}, {0, AudioEffectCloudSeed2::presets_num - 1, 0, 1, "CloudSeed2Preset", AudioEffectCloudSeed2::getPresetName, FX::FXComposite | FX::FXSaveAsString}, {0, 1, 0, 1, "CloudSeed2Interpolation", ToOnOff}, {0, 1, 0, 1, "CloudSeed2LowCutEnabled", ToOnOff}, diff --git a/src/effect.h b/src/effect.h index 0ce5034de..aa3eff35b 100644 --- a/src/effect.h +++ b/src/effect.h @@ -35,6 +35,7 @@ class FX FXParameterPlateReverbLowDamp, FXParameterPlateReverbLowPass, FXParameterPlateReverbDiffusion, + FXParameterPlateReverbBypass, FXParameterCloudSeed2Preset, FXParameterCloudSeed2Interpolation, FXParameterCloudSeed2LowCutEnabled, @@ -126,7 +127,7 @@ class FX {"None"}, {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusBypass}, {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayBypass}, - {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbDiffusion}, + {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbBypass}, {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, {"EQ", FXParameterEQLow, FXParameterEQBypass}, diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index 8b0a6ce4a..012a2cc52 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -83,7 +83,8 @@ const int16_t AudioWaveformSine[257] = { -4808, -4011, -3212, -2410, -1608, -804, 0 }; -AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) +AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate): +bypass{} { set_mix(0.0f); @@ -227,6 +228,8 @@ void AudioEffectPlateReverb::process(const float32_t *inblockL, const float32_t int64_t y; uint32_t idx; + if (bypass) return; + if (wet == 0.0f) return; rv_time = rv_time_k; diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 0e7c51083..eb5286cf7 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -44,6 +44,7 @@ #ifndef _EFFECT_PLATERVBSTEREO_H #define _EFFECT_PLATERVBSTEREO_H +#include #include #include #include "common.h" @@ -118,6 +119,9 @@ class AudioEffectPlateReverb } void reset(); + + std::atomic bypass; + private: float32_t mix, dry, wet; float32_t input_attn; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 38dd74308..7734e0b2d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1270,6 +1270,10 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; + case FX::FXParameterPlateReverbBypass: + fx_chain[nFX]->plate_reverb.bypass = nValue; + break; + case FX::FXParameterCloudSeed2Preset: fx_chain[nFX]->cloudseed2.loadPreset (nValue); break; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 50c0d6488..f3c4c470e 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -245,6 +245,7 @@ const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp}, {"Low pass", EditFXParameter2, 0, FX::FXParameterPlateReverbLowPass}, {"Diffusion", EditFXParameter2, 0, FX::FXParameterPlateReverbDiffusion}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterPlateReverbBypass}, {0} }; From 357c16b5103ade7b99d635e5b5087ff412004147 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 04:55:48 +0100 Subject: [PATCH 112/136] effect_cloudseed2: add bypass --- src/effect.cpp | 1 + src/effect.h | 3 ++- src/effect_cloudseed2.h | 5 +++++ src/minidexed.cpp | 4 ++++ src/uimenu.cpp | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/effect.cpp b/src/effect.cpp index fd1fce1a4..32adb0d75 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -171,6 +171,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, {0, 127, 12, 1, "CloudSeed2SeedDelay"}, {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, + {0, 1, 0, 1, "CloudSeed2Bypass", ToOnOff}, {-20, 20, 0, 1, "CompressorPreGain", TodB}, {-60, 0, -20, 1, "CompressorThresh", TodBFS}, {1, AudioEffectCompressor::CompressorRatioInf, 5, 1, "CompressorRatio", ToRatio}, diff --git a/src/effect.h b/src/effect.h index aa3eff35b..508bfeff6 100644 --- a/src/effect.h +++ b/src/effect.h @@ -82,6 +82,7 @@ class FX FXParameterCloudSeed2SeedDiffusion, FXParameterCloudSeed2SeedDelay, FXParameterCloudSeed2SeedPostDiffusion, + FXParameterCloudSeed2Bypass, FXParameterCompressorPreGain, FXParameterCompressorThresh, FXParameterCompressorRatio, @@ -128,7 +129,7 @@ class FX {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusBypass}, {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayBypass}, {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbBypass}, - {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2SeedPostDiffusion}, + {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2Bypass}, {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, {"EQ", FXParameterEQLow, FXParameterEQBypass}, }; diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h index 48bcf8142..5deafec68 100644 --- a/src/effect_cloudseed2.h +++ b/src/effect_cloudseed2.h @@ -65,6 +65,7 @@ class AudioEffectCloudSeed2 } AudioEffectCloudSeed2(float samplerate): + bypass{}, samplerate{samplerate}, ramp_dt{10.0f / samplerate}, engine{(int)samplerate}, @@ -149,6 +150,8 @@ class AudioEffectCloudSeed2 return; } + if (bypass) return; + if (isDisabled()) return; engine.Process(inblockL, inblockR, inblockL, inblockR, len); @@ -182,6 +185,8 @@ class AudioEffectCloudSeed2 params[Cloudseed::Parameter::LateOut] == 0.0f; } + std::atomic bypass; + private: float samplerate; float ramp_dt; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 7734e0b2d..24b2fab54 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1326,6 +1326,10 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne fx_chain[nFX]->cloudseed2.setParameter (Parameter - FX::FXParameterCloudSeed2Interpolation, mapfloat(nValue, p.Minimum, p.Maximum, 0.0f, 1.0f)); break; + case FX::FXParameterCloudSeed2Bypass: + fx_chain[nFX]->cloudseed2.bypass = nValue; + break; + case FX::FXParameterCompressorPreGain: m_FXSpinLock.Acquire (); fx_chain[nFX]->compressor.setPreGain_dB (nValue); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index f3c4c470e..1531846e3 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -268,6 +268,7 @@ const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2Menu[] = {"Low Shelf", MenuHandler, s_CloudSeed2LowShelfMenu}, {"High Shelf", MenuHandler, s_CloudSeed2HighShelfMenu}, {"Low Pass", MenuHandler, s_CloudSeed2LowPassMenu}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterCloudSeed2Bypass}, {0} }; From 4e8f4676e85fc262781d8c172736321a42ef4649 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 05:41:23 +0100 Subject: [PATCH 113/136] Update CloudSeedCore --- CloudSeedCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CloudSeedCore b/CloudSeedCore index 57cec73a2..11eb12568 160000 --- a/CloudSeedCore +++ b/CloudSeedCore @@ -1 +1 @@ -Subproject commit 57cec73a2bcdef6f83e355ff55b6bcd696cc3148 +Subproject commit 11eb125687ccd73d89f01d16c255cc600dea68fe From 04b5745c1b5c40a2734ea33e0101545fcd467dcc Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Thu, 13 Nov 2025 16:40:45 +0100 Subject: [PATCH 114/136] add FXBypass option to bypass all FX chains --- src/effect.cpp | 1 + src/effect.h | 1 + src/effect_chain.h | 5 +++++ src/minidexed.cpp | 29 +++++++++++++++++++++++------ src/minidexed.h | 1 + src/performanceconfig.cpp | 15 +++++++++++++++ src/performanceconfig.h | 4 ++++ src/uimenu.cpp | 4 ++++ 8 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/effect.cpp b/src/effect.cpp index 32adb0d75..01ef96f91 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -188,6 +188,7 @@ FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = {28, 59, 44, 1, "EQMidHighFreq", ToHz}, {0, 1, 0, 1, "EQBypass", ToOnOff}, {0, 99, 0, 1, "ReturnLevel"}, + {0, 1, 0, 1, "Bypass", ToOnOff}, }; constexpr const FX::EffectType FX::s_effects[]; diff --git a/src/effect.h b/src/effect.h index 508bfeff6..362b6513d 100644 --- a/src/effect.h +++ b/src/effect.h @@ -99,6 +99,7 @@ class FX FXParameterEQMidHighFreq, FXParameterEQBypass, FXParameterReturnLevel, + FXParameterBypass, FXParameterUnknown, }; diff --git a/src/effect_chain.h b/src/effect_chain.h index c6b347ffd..90bd576fe 100644 --- a/src/effect_chain.h +++ b/src/effect_chain.h @@ -21,6 +21,7 @@ class AudioFXChain cloudseed2{samplerate}, compressor{samplerate}, eq{samplerate}, + bypass{}, funcs{ [this](float *inputL, float *inputR, uint16_t len) {}, [this](float *inputL, float *inputR, uint16_t len) { yk_chorus.process(inputL, inputR, len); }, @@ -39,6 +40,8 @@ class AudioFXChain void process (float *inputL, float *inputR, uint16_t len) { + if (bypass) return; + for (int i = 0; i < FX::slots_num; ++i) if (uint8_t id = slots[i]) funcs[id](inputL, inputR, len); @@ -76,6 +79,8 @@ class AudioFXChain AudioEffectCompressor compressor; AudioEffect3BandEQ eq; + std::atomic bypass; + private: std::atomic slots[FX::slots_num]; const process_t funcs[FX::effects_num]; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 24b2fab54..1a21db6c1 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -285,6 +285,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, // END setup reverb SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); + SetParameter (ParameterMixerDryLevel, 99); + SetParameter (ParameterFXBypass, 0); SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); @@ -1095,6 +1097,9 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) tg_mixer->gain(mapfloat(nValue,0,99,0.0f,1.0f)); break; + case ParameterFXBypass: + break; + default: assert (0); break; @@ -1422,6 +1427,10 @@ void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigne m_FXSpinLock.Release (); break; + case FX::FXParameterBypass: + fx_chain[nFX]->bypass = nValue; + break; + default: assert (0); break; @@ -1847,18 +1856,24 @@ void CMiniDexed::ProcessSound (void) sendfx_mixer[nFX]->doAddMix(i,m_OutputLevel[i]); } - m_FXSpinLock.Acquire (); - fx_chain[nFX]->process(FXSendBuffer[0], FXSendBuffer[1], nFrames); + if (!m_nParameter[ParameterFXBypass]) + { + m_FXSpinLock.Acquire (); + fx_chain[nFX]->process(FXSendBuffer[0], FXSendBuffer[1], nFrames); + m_FXSpinLock.Release (); + } arm_add_f32(SampleBuffer[0], FXSendBuffer[0], SampleBuffer[0], nFrames); arm_add_f32(SampleBuffer[1], FXSendBuffer[1], SampleBuffer[1], nFrames); - m_FXSpinLock.Release (); } // END adding sendFX - m_FXSpinLock.Acquire (); - fx_chain[CConfig::MasterFX]->process(SampleBuffer[0], SampleBuffer[1], nFrames); - m_FXSpinLock.Release (); + if (!m_nParameter[ParameterFXBypass]) + { + m_FXSpinLock.Acquire (); + fx_chain[CConfig::MasterFX]->process(SampleBuffer[0], SampleBuffer[1], nFrames); + m_FXSpinLock.Release (); + } // swap stereo channels if needed prior to writing back out if (m_bChannelsSwapped) @@ -2029,6 +2044,7 @@ bool CMiniDexed::DoSavePerformance (void) } m_PerformanceConfig.SetMixerDryLevel (m_nParameter[ParameterMixerDryLevel]); + m_PerformanceConfig.SetFXBypass (m_nParameter[ParameterFXBypass]); if(m_bSaveAsDeault) { @@ -2740,6 +2756,7 @@ void CMiniDexed::LoadPerformanceParameters(void) } SetParameter (ParameterMixerDryLevel, m_PerformanceConfig.GetMixerDryLevel ()); + SetParameter (ParameterFXBypass, m_PerformanceConfig.GetFXBypass ()); m_UI.DisplayChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index 7b3359ebe..25273e3b6 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -188,6 +188,7 @@ class CMiniDexed ParameterPerformanceBank, ParameterMasterVolume, ParameterMixerDryLevel, + ParameterFXBypass, ParameterUnknown }; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 5c034441e..9d5ddeac6 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -293,6 +293,7 @@ bool CPerformanceConfig::Load (void) } m_nMixerDryLevel = m_Properties.GetNumber ("MixerDryLevel", 99); + m_nFXBypass = m_Properties.GetNumber ("FXBypass", 0); // Compatibility if (m_Properties.IsSet ("CompressorEnable") && CConfig::FXChains) @@ -520,9 +521,13 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[FX::FXParameterReturnLevel].Name); m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterReturnLevel]); } + + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[FX::FXParameterBypass].Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterBypass]); } m_Properties.SetNumber ("MixerDryLevel", m_nMixerDryLevel); + m_Properties.SetNumber ("FXBypass", m_nFXBypass); return m_Properties.Save (); } @@ -779,6 +784,16 @@ void CPerformanceConfig::SetMixerDryLevel (unsigned nValue) m_nMixerDryLevel = nValue; } +unsigned CPerformanceConfig::GetFXBypass () const +{ + return m_nFXBypass; +} + +void CPerformanceConfig::SetFXBypass (unsigned nValue) +{ + m_nFXBypass = nValue; +} + // Pitch bender and portamento: void CPerformanceConfig::SetPitchBendRange (unsigned nValue, unsigned nTG) { diff --git a/src/performanceconfig.h b/src/performanceconfig.h index c935b34f7..549da1026 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -143,6 +143,9 @@ class CPerformanceConfig // Performance configuration unsigned GetMixerDryLevel () const; void SetMixerDryLevel (unsigned nValue); + unsigned GetFXBypass () const; + void SetFXBypass (unsigned nValue); + bool VoiceDataFilled(unsigned nTG); bool ListPerformances(); //std::string m_DirName; @@ -239,6 +242,7 @@ class CPerformanceConfig // Performance configuration int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; unsigned m_nMixerDryLevel; + unsigned m_nFXBypass; }; #endif diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 1531846e3..3b809873d 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -180,6 +180,7 @@ const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = {"SendFX1", MenuHandler, s_SendFXMenu, 0}, {"SendFX2", MenuHandler, s_SendFXMenu, 1}, {"MasterFX", MenuHandler, s_MasterFXMenu, CConfig::MasterFX}, + {"Bypass", EditGlobalParameter, 0, CMiniDexed::ParameterFXBypass}, {0} }; @@ -189,6 +190,7 @@ const CUIMenu::TMenuItem CUIMenu::s_SendFXMenu[] = {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Return Level", EditFXParameter2, 0, FX::FXParameterReturnLevel}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterBypass}, {0}, }; @@ -197,6 +199,7 @@ const CUIMenu::TMenuItem CUIMenu::s_MasterFXMenu[] = {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterBypass}, {0}, }; @@ -450,6 +453,7 @@ CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank {0, 127, 8, ToVolume}, // ParameterMasterVolume {0, 99, 1}, // ParameterMixerDryLevel + {0, 1, 1, ToOnOff}, // ParameterFXBypass }; // must match CMiniDexed::TTGParameter From 6b5cb10bb6509e20396ec7b3221fdc3196424e0b Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 23 Nov 2025 18:49:18 +0100 Subject: [PATCH 115/136] Bank 004 Mirage DreamDexed Performances (#24) * Bank 004 Mirage DreamDexed Performances * Copy performance files to sdcard --- .github/workflows/build.yml | 2 + performance/004_Mirage/000001_Ambient-DDx.ini | 408 +++++++++++++++++ performance/004_Mirage/000002_Pop Ballad.ini | 420 +++++++++++++++++ performance/004_Mirage/000003_MagicOrgan.ini | 414 +++++++++++++++++ performance/004_Mirage/000004_Security.ini | 429 ++++++++++++++++++ performance/004_Mirage/000005_SomniumDyna.ini | 412 +++++++++++++++++ performance/004_Mirage/000006_MagicPiano.ini | 389 ++++++++++++++++ .../004_Mirage/000007_Ascension 2TG.ini | 422 +++++++++++++++++ .../004_Mirage/000008_Bananen Mk II.ini | 373 +++++++++++++++ performance/004_Mirage/000009_78er DDxFX.ini | 373 +++++++++++++++ performance/DreamDexed Bank 004_Mirage.pdf | Bin 0 -> 27841 bytes 11 files changed, 3642 insertions(+) create mode 100644 performance/004_Mirage/000001_Ambient-DDx.ini create mode 100644 performance/004_Mirage/000002_Pop Ballad.ini create mode 100644 performance/004_Mirage/000003_MagicOrgan.ini create mode 100644 performance/004_Mirage/000004_Security.ini create mode 100644 performance/004_Mirage/000005_SomniumDyna.ini create mode 100644 performance/004_Mirage/000006_MagicPiano.ini create mode 100644 performance/004_Mirage/000007_Ascension 2TG.ini create mode 100644 performance/004_Mirage/000008_Bananen Mk II.ini create mode 100644 performance/004_Mirage/000009_78er DDxFX.ini create mode 100644 performance/DreamDexed Bank 004_Mirage.pdf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 924068f3e..a633e19b1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,6 +76,8 @@ jobs: # Performances git clone https://github.com/Banana71/Soundplantage --depth 1 cp -r ./Soundplantage/performance ./Soundplantage/*.pdf ./sdcard/ + cp -r ./performance/004_Mirage ./sdcard/performance/ + cp "./performance/DreamDexed Bank 004_Mirage.pdf" ./sdcard/performance/ # Hardware configuration cd hwconfig sh -ex ./customize.sh diff --git a/performance/004_Mirage/000001_Ambient-DDx.ini b/performance/004_Mirage/000001_Ambient-DDx.ini new file mode 100644 index 000000000..bbb80607e --- /dev/null +++ b/performance/004_Mirage/000001_Ambient-DDx.ini @@ -0,0 +1,408 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=40 +Pan1=0 +Detune1=-5 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=21 +EQMidHighFreq1=49 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=40 +Pan2=127 +Detune2=5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=21 +EQMidHighFreq2=49 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=40 +Pan3=0 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=21 +EQMidHighFreq3=49 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=40 +Pan4=127 +Detune4=3 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=21 +EQMidHighFreq4=49 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=40 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=21 +EQMidHighFreq5=49 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=1 +Volume6=40 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=21 +EQMidHighFreq6=49 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=40 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode7=0 +TGLink7=1 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=21 +EQMidHighFreq7=49 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=40 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode8=0 +TGLink8=1 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=21 +EQMidHighFreq8=49 +SendFX1Slot1=None +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1DreamDelayMix=54 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=107 +SendFX1DreamDelayTimeL=105 +SendFX1DreamDelayTimeR=107 +SendFX1DreamDelayTempo=30 +SendFX1DreamDelayFeedback=35 +SendFX1DreamDelayHighCut=50 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=123 +SendFX1CloudSeed2EarlyOut=122 +SendFX1CloudSeed2LateOut=108 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=12 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=4 +SendFX1CloudSeed2LateLineSize=87 +SendFX1CloudSeed2LateLineModAmount=95 +SendFX1CloudSeed2LateDiffuseDelay=79 +SendFX1CloudSeed2LateDiffuseModAmount=58 +SendFX1CloudSeed2LateLineDecay=86 +SendFX1CloudSeed2LateLineModRate=79 +SendFX1CloudSeed2LateDiffuseFeedback=80 +SendFX1CloudSeed2LateDiffuseModRate=41 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000002_Pop Ballad.ini b/performance/004_Mirage/000002_Pop Ballad.ini new file mode 100644 index 000000000..5f2410b23 --- /dev/null +++ b/performance/004_Mirage/000002_Pop Ballad.ini @@ -0,0 +1,420 @@ +BankNumber1=0 +VoiceNumber1=15 +MIDIChannel1=1 +Volume1=48 +Pan1=0 +Detune1=2 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=43 0B 0B 2A 63 58 00 00 27 06 1E 03 00 06 00 00 42 00 05 00 0E 45 0A 0D 2A 63 58 00 00 22 08 09 00 00 01 00 04 4E 00 01 00 0A 4E 49 33 37 63 3A 00 00 33 0C 0B 03 03 01 00 02 59 01 06 1B 06 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 03 63 00 01 00 08 42 0B 00 27 63 4F 00 00 26 0D 09 00 00 03 00 01 4C 00 01 01 00 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 02 63 00 01 00 03 63 63 63 63 32 32 32 32 08 07 01 23 00 00 00 01 00 00 18 6D 44 78 43 50 62 72 69 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-12 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=12 +EQMidHighFreq1=44 +BankNumber2=0 +VoiceNumber2=15 +MIDIChannel2=1 +Volume2=48 +Pan2=127 +Detune2=0 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=43 0B 0B 2A 63 58 00 00 27 06 1E 03 00 06 00 00 44 00 05 00 0E 45 0A 0D 2A 63 58 00 00 22 08 09 00 00 01 00 04 4E 00 01 00 0A 4E 49 33 37 63 3A 00 00 33 0C 0B 03 03 01 00 02 59 01 06 1C 06 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 03 63 00 01 00 08 42 0B 00 27 63 4F 00 00 26 0D 09 00 00 03 00 01 4C 00 01 01 00 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 02 63 00 01 00 03 63 63 63 63 32 32 32 32 08 07 01 23 00 00 00 01 00 00 18 6D 44 78 43 50 62 72 69 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=-12 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=12 +EQMidHighFreq2=44 +BankNumber3=0 +VoiceNumber3=4 +MIDIChannel3=1 +Volume3=48 +Pan3=0 +Detune3=-2 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 54 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 03 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 43 50 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=-12 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=12 +EQMidHighFreq3=44 +BankNumber4=0 +VoiceNumber4=4 +MIDIChannel4=1 +Volume4=48 +Pan4=127 +Detune4=1 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 54 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 03 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 43 50 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=-12 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=12 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=4 +MIDIChannel5=0 +Volume5=71 +Pan5=64 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 53 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 63 00 01 05 00 01 52 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 03 01 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 44 55 4F 53 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=-12 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=12 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=4 +MIDIChannel6=1 +Volume6=72 +Pan6=63 +Detune6=4 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=4F 2B 24 2D 63 45 00 00 15 00 2C 00 01 04 00 06 4F 00 05 00 08 5F 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 5F 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 22 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4E 00 07 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 05 00 23 00 00 00 01 03 00 18 3E 50 49 41 4E 4F 20 43 50 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=-12 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=12 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=100 +Pan7=64 +Detune7=-1 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=52 5F 12 30 58 63 00 00 18 00 0E 00 00 03 00 02 4F 00 03 00 07 5C 63 1F 37 63 63 00 00 18 0C 00 03 00 03 00 02 4A 00 01 00 07 52 35 17 35 63 5A 00 00 27 00 00 00 00 04 02 02 5A 00 01 00 07 52 5F 1F 2D 53 63 00 00 18 00 09 00 00 00 00 04 4C 00 03 00 07 63 63 19 37 63 63 00 00 27 00 00 00 00 03 00 07 43 00 01 00 07 52 32 14 38 63 5A 00 00 27 00 00 00 00 04 02 02 63 00 01 00 07 63 63 63 63 32 32 32 32 02 06 01 13 2F 00 00 01 00 03 18 31 39 38 32 20 20 20 20 20 20 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=1 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=100 +Pan8=64 +Detune8=0 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=52 5F 12 30 58 63 00 00 18 00 0E 00 00 03 00 02 4F 00 03 00 07 5C 63 1F 37 63 63 00 00 18 0C 00 03 00 03 00 02 4A 00 01 00 07 52 35 17 35 63 5A 00 00 27 00 00 00 00 04 02 02 5A 00 01 00 07 52 5F 1F 2D 53 63 00 00 18 00 09 00 00 00 00 04 4C 00 03 00 07 63 63 19 37 63 63 00 00 27 00 00 00 00 03 00 07 43 00 01 00 07 52 32 14 38 63 5A 00 00 27 00 00 00 00 04 02 02 63 00 01 00 07 63 63 63 63 32 32 32 32 02 06 01 13 2F 00 00 01 00 03 18 31 39 38 32 20 20 20 20 20 20 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=1 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=CloudSeed2 +SendFX1Slot3=None +SendFX1YKChorusMix=16 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=20 +SendFX1YKChorusLFORate2=35 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=LBigSoundStage +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=127 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=69 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=5 +SendFX1CloudSeed2EarlyDiffuseDelay=88 +SendFX1CloudSeed2EarlyDiffuseModAmount=43 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=44 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=7 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=31 +SendFX1CloudSeed2LateLineModAmount=0 +SendFX1CloudSeed2LateDiffuseDelay=22 +SendFX1CloudSeed2LateDiffuseModAmount=24 +SendFX1CloudSeed2LateLineDecay=20 +SendFX1CloudSeed2LateLineModRate=0 +SendFX1CloudSeed2LateDiffuseFeedback=112 +SendFX1CloudSeed2LateDiffuseModRate=32 +SendFX1CloudSeed2EqLowShelfEnabled=1 +SendFX1CloudSeed2EqHighShelfEnabled=1 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=33 +SendFX1CloudSeed2EqHighFreq=55 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=123 +SendFX1CloudSeed2EqHighGain=59 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=EQ +MasterFXSlot2=Compressor +MasterFXSlot3=None +MasterFXEQLow=-1 +MasterFXEQMid=3 +MasterFXEQHigh=0 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=25 +MasterFXEQMidHighFreq=46 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-14 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=50 +MasterFXCompressorRelease=250 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000003_MagicOrgan.ini b/performance/004_Mirage/000003_MagicOrgan.ini new file mode 100644 index 000000000..1aa716435 --- /dev/null +++ b/performance/004_Mirage/000003_MagicOrgan.ini @@ -0,0 +1,414 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=75 +Pan1=64 +Detune1=0 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=0 +FX2Send1=99 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=08 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 55 00 10 00 07 0D 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 57 00 0C 00 07 06 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 53 00 08 00 07 0D 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 62 00 10 00 07 12 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 0C 00 07 63 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 08 00 07 63 63 63 63 32 32 32 32 1F 00 00 23 00 06 00 01 00 01 18 42 69 6E 67 65 6C 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=1 +CompressorPreGain1=10 +CompressorThresh1=-44 +CompressorRatio1=5 +CompressorAttack1=65 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-6 +EQMid1=0 +EQHigh1=7 +EQGain1=0 +EQLowMidFreq1=24 +EQMidHighFreq1=47 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=100 +Pan2=0 +Detune2=-5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode2=0 +TGLink2=2 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=1 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=2 +EQMid2=0 +EQHigh2=5 +EQGain2=0 +EQLowMidFreq2=24 +EQMidHighFreq2=50 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=100 +Pan3=127 +Detune3=5 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode3=0 +TGLink3=2 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=1 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=2 +EQMid3=0 +EQHigh3=5 +EQGain3=0 +EQLowMidFreq3=24 +EQMidHighFreq3=50 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=0 +Volume4=48 +Pan4=63 +Detune4=0 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=99 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=1 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=24 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=48 +Pan5=64 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=99 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=48 +Pan6=63 +Detune6=0 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=1 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=48 +Pan7=64 +Detune7=0 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=1 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=48 +Pan8=63 +Detune8=0 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=1 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=None +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=31 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=38 +SendFX1YKChorusLFORate2=64 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=LBigSoundStage +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=125 +SendFX1CloudSeed2EarlyOut=100 +SendFX1CloudSeed2LateOut=104 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=121 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=5 +SendFX1CloudSeed2EarlyDiffuseDelay=88 +SendFX1CloudSeed2EarlyDiffuseModAmount=43 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=44 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=7 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=31 +SendFX1CloudSeed2LateLineModAmount=0 +SendFX1CloudSeed2LateDiffuseDelay=22 +SendFX1CloudSeed2LateDiffuseModAmount=16 +SendFX1CloudSeed2LateLineDecay=46 +SendFX1CloudSeed2LateLineModRate=0 +SendFX1CloudSeed2LateDiffuseFeedback=112 +SendFX1CloudSeed2LateDiffuseModRate=32 +SendFX1CloudSeed2EqLowShelfEnabled=1 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=33 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=123 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=DreamDelay +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2DreamDelayMix=48 +SendFX2DreamDelayMode=2 +SendFX2DreamDelayTime=28 +SendFX2DreamDelayTimeL=28 +SendFX2DreamDelayTimeR=19 +SendFX2DreamDelayTempo=120 +SendFX2DreamDelayFeedback=47 +SendFX2DreamDelayHighCut=50 +SendFX2DreamDelayBypass=0 +SendFX2ReturnLevel=99 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000004_Security.ini b/performance/004_Mirage/000004_Security.ini new file mode 100644 index 000000000..c568acb28 --- /dev/null +++ b/performance/004_Mirage/000004_Security.ini @@ -0,0 +1,429 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=90 +Pan1=0 +Detune1=-1 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=6 +CompressorThresh1=-16 +CompressorRatio1=2 +CompressorAttack1=35 +CompressorRelease1=165 +CompressorMakeupGain1=0 +EQLow1=-1 +EQMid1=1 +EQHigh1=6 +EQGain1=-1 +EQLowMidFreq1=22 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=90 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=6 +CompressorThresh2=-16 +CompressorRatio2=2 +CompressorAttack2=35 +CompressorRelease2=165 +CompressorMakeupGain2=0 +EQLow2=-1 +EQMid2=1 +EQHigh2=6 +EQGain2=-1 +EQLowMidFreq2=22 +EQMidHighFreq2=46 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=90 +Pan3=0 +Detune3=0 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=6 +CompressorThresh3=-16 +CompressorRatio3=2 +CompressorAttack3=35 +CompressorRelease3=165 +CompressorMakeupGain3=0 +EQLow3=-1 +EQMid3=1 +EQHigh3=6 +EQGain3=-1 +EQLowMidFreq3=22 +EQMidHighFreq3=46 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=90 +Pan4=127 +Detune4=-4 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=6 +CompressorThresh4=-16 +CompressorRatio4=2 +CompressorAttack4=35 +CompressorRelease4=165 +CompressorMakeupGain4=0 +EQLow4=-1 +EQMid4=1 +EQHigh4=6 +EQGain4=-1 +EQLowMidFreq4=22 +EQMidHighFreq4=46 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=99 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=1 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=15 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=10 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=46 +SendFX1YKChorusLFORate2=73 +SendFX1YKChorusBypass=0 +SendFX1DreamDelayMix=11 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=1 +SendFX1DreamDelayTimeL=1 +SendFX1DreamDelayTimeR=2 +SendFX1DreamDelayTempo=120 +SendFX1DreamDelayFeedback=1 +SendFX1DreamDelayHighCut=57 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=127 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=64 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=91 +SendFX1CloudSeed2TapDecay=0 +SendFX1CloudSeed2TapPredelay=12 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=6 +SendFX1CloudSeed2EarlyDiffuseDelay=67 +SendFX1CloudSeed2EarlyDiffuseModAmount=0 +SendFX1CloudSeed2EarlyDiffuseFeedback=35 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=8 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=0 +SendFX1CloudSeed2LateLineModAmount=64 +SendFX1CloudSeed2LateDiffuseDelay=80 +SendFX1CloudSeed2LateDiffuseModAmount=28 +SendFX1CloudSeed2LateLineDecay=8 +SendFX1CloudSeed2LateLineModRate=47 +SendFX1CloudSeed2LateDiffuseFeedback=99 +SendFX1CloudSeed2LateDiffuseModRate=44 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=Compressor +MasterFXEQLow=0 +MasterFXEQMid=0 +MasterFXEQHigh=4 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=22 +MasterFXEQMidHighFreq=51 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-15 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=45 +MasterFXCompressorRelease=230 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000005_SomniumDyna.ini b/performance/004_Mirage/000005_SomniumDyna.ini new file mode 100644 index 000000000..56317954a --- /dev/null +++ b/performance/004_Mirage/000005_SomniumDyna.ini @@ -0,0 +1,412 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=42 +Pan1=0 +Detune1=-5 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=21 +EQMidHighFreq1=49 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=42 +Pan2=127 +Detune2=5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=21 +EQMidHighFreq2=49 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=42 +Pan3=0 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=21 +EQMidHighFreq3=49 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=42 +Pan4=127 +Detune4=3 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=21 +EQMidHighFreq4=49 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=42 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=21 +EQMidHighFreq5=49 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=1 +Volume6=42 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=21 +EQMidHighFreq6=49 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=42 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode7=0 +TGLink7=1 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=21 +EQMidHighFreq7=49 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=42 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode8=0 +TGLink8=1 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=21 +EQMidHighFreq8=49 +SendFX1Slot1=YKChorus +SendFX1Slot2=None +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=24 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=42 +SendFX1YKChorusLFORate2=78 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=120 +SendFX1CloudSeed2EarlyOut=116 +SendFX1CloudSeed2LateOut=111 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=12 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=4 +SendFX1CloudSeed2LateLineSize=87 +SendFX1CloudSeed2LateLineModAmount=95 +SendFX1CloudSeed2LateDiffuseDelay=79 +SendFX1CloudSeed2LateDiffuseModAmount=58 +SendFX1CloudSeed2LateLineDecay=74 +SendFX1CloudSeed2LateLineModRate=79 +SendFX1CloudSeed2LateDiffuseFeedback=80 +SendFX1CloudSeed2LateDiffuseModRate=41 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=9 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=65 +SendFX1CloudSeed2EqLowGain=50 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=None +MasterFXEQLow=2 +MasterFXEQMid=0 +MasterFXEQHigh=5 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=19 +MasterFXEQMidHighFreq=49 +MasterFXEQBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000006_MagicPiano.ini b/performance/004_Mirage/000006_MagicPiano.ini new file mode 100644 index 000000000..63c86bbc6 --- /dev/null +++ b/performance/004_Mirage/000006_MagicPiano.ini @@ -0,0 +1,389 @@ +BankNumber1=0 +VoiceNumber1=18 +MIDIChannel1=1 +Volume1=105 +Pan1=0 +Detune1=-2 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=43 0B 0B 20 63 5A 00 00 02 00 3B 03 01 06 00 00 4E 00 05 00 0C 45 0A 0D 2C 63 5B 00 00 22 07 06 03 00 01 00 03 4C 00 01 00 09 5A 49 33 37 60 3A 00 00 33 0C 0B 03 03 01 00 02 56 01 06 06 06 43 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 61 00 01 00 08 42 0B 00 22 63 4F 00 00 20 00 09 00 00 03 00 02 4A 00 01 01 02 50 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 5E 00 01 00 04 63 63 63 63 32 32 32 32 08 07 00 23 00 00 00 01 00 00 18 6D 44 78 50 69 61 6E 6F 4C 52 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=1 +CompressorPreGain1=2 +CompressorThresh1=-19 +CompressorRatio1=2 +CompressorAttack1=40 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-2 +EQMid1=0 +EQHigh1=2 +EQGain1=0 +EQLowMidFreq1=22 +EQMidHighFreq1=47 +BankNumber2=0 +VoiceNumber2=18 +MIDIChannel2=1 +Volume2=105 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=43 0B 0B 20 63 5A 00 00 02 00 3B 03 01 06 00 00 4E 00 05 00 0E 45 0A 0D 2C 63 5B 00 00 22 07 06 03 00 01 00 03 4C 00 01 00 0B 5A 49 33 37 60 3A 00 00 33 0C 0B 03 03 01 00 02 56 01 06 06 06 43 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 61 00 01 00 08 42 0B 00 22 63 4F 00 00 20 00 09 00 00 03 00 02 4A 00 01 01 00 50 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 5E 00 01 00 03 63 63 63 63 32 32 32 32 08 07 00 23 00 00 00 01 00 00 18 6D 44 78 50 69 61 6E 6F 4C 52 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=1 +CompressorPreGain2=2 +CompressorThresh2=-19 +CompressorRatio2=2 +CompressorAttack2=40 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=-2 +EQMid2=0 +EQHigh2=2 +EQGain2=0 +EQLowMidFreq2=22 +EQMidHighFreq2=47 +BankNumber3=0 +VoiceNumber3=19 +MIDIChannel3=1 +Volume3=65 +Pan3=63 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=4F 2C 1F 2D 63 47 00 00 15 06 00 00 01 04 00 02 51 00 05 00 06 5F 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 04 4C 00 01 00 06 5F 0E 0D 30 63 5B 00 00 0F 24 1E 01 01 07 00 06 63 00 01 00 07 5F 2D 1E 2F 63 5E 00 00 05 00 45 00 01 02 03 06 4B 00 07 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 52 00 01 00 09 58 1C 15 31 63 5A 00 00 31 20 3F 01 01 04 00 05 63 00 01 00 07 00 00 00 00 32 32 32 32 02 04 00 02 47 08 30 00 00 01 18 52 6F 63 6B 20 41 50 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=1 +CompressorPreGain3=2 +CompressorThresh3=-19 +CompressorRatio3=2 +CompressorAttack3=40 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=-2 +EQMid3=-6 +EQHigh3=2 +EQGain3=0 +EQLowMidFreq3=26 +EQMidHighFreq3=41 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=102 +Pan4=0 +Detune4=1 +Cutoff4=90 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 09 2C 63 63 5D 00 28 0A 0F 03 00 03 00 01 47 00 05 00 07 54 63 11 25 63 63 5C 00 00 00 0E 00 01 03 00 00 47 00 03 00 07 4F 26 0F 1D 63 60 5A 00 2B 02 0F 03 00 04 00 02 4C 00 01 00 0E 4A 2A 15 2F 63 61 00 00 28 07 0A 03 00 05 00 03 5B 00 01 00 07 63 63 19 27 63 63 57 00 00 00 1B 00 01 01 00 01 51 00 01 01 01 42 42 10 2D 63 60 06 00 00 00 00 00 00 04 00 03 5B 00 01 00 09 63 63 63 63 32 32 32 32 01 06 00 23 00 00 00 01 00 01 18 44 72 61 68 74 69 67 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=1 +CompressorPreGain4=2 +CompressorThresh4=-19 +CompressorRatio4=2 +CompressorAttack4=40 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=-2 +EQMid4=0 +EQHigh4=2 +EQGain4=0 +EQLowMidFreq4=22 +EQMidHighFreq4=47 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=102 +Pan5=127 +Detune5=-2 +Cutoff5=90 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 09 2C 63 63 5D 00 28 0A 0F 03 00 03 00 01 47 00 05 00 07 54 63 11 25 63 63 5C 00 00 00 0E 00 01 03 00 00 47 00 03 00 07 4F 26 0F 1D 63 60 5A 00 2B 02 0F 03 00 04 00 02 4C 00 01 00 0E 4A 2A 15 2F 63 61 00 00 28 07 0A 03 00 05 00 03 5B 00 01 00 07 63 63 19 27 63 63 57 00 00 00 1B 00 01 01 00 01 51 00 01 01 01 42 42 10 2D 63 60 06 00 00 00 00 00 00 04 00 03 5B 00 01 00 09 63 63 63 63 32 32 32 32 01 06 00 23 00 00 00 01 00 01 18 44 72 61 68 74 69 67 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=2 +CompressorThresh5=-19 +CompressorRatio5=2 +CompressorAttack5=40 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=-2 +EQMid5=0 +EQHigh5=2 +EQGain5=0 +EQLowMidFreq5=22 +EQMidHighFreq5=47 +BankNumber6=0 +VoiceNumber6=4 +MIDIChannel6=1 +Volume6=14 +Pan6=64 +Detune6=0 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=0 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=08 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 55 00 10 00 07 0D 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 57 00 0C 00 07 06 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 53 00 08 00 07 0D 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 62 00 10 00 07 12 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 0C 00 07 63 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 08 00 07 63 63 63 63 32 32 32 32 1F 00 00 23 00 06 00 01 00 01 18 42 69 6E 67 65 6C 20 20 20 20 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=2 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=-3 +EQMid6=0 +EQHigh6=4 +EQGain6=0 +EQLowMidFreq6=26 +EQMidHighFreq6=51 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=18 +Pan7=0 +Detune7=6 +Cutoff7=70 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=54 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode7=0 +TGLink7=2 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=5 +EQMid7=-1 +EQHigh7=4 +EQGain7=0 +EQLowMidFreq7=18 +EQMidHighFreq7=47 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=18 +Pan8=125 +Detune8=-6 +Cutoff8=70 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=54 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode8=0 +TGLink8=2 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=5 +EQMid8=-1 +EQHigh8=4 +EQGain8=0 +EQLowMidFreq8=18 +EQMidHighFreq8=47 +SendFX1Slot1=YKChorus +SendFX1Slot2=PlateReverb +SendFX1Slot3=None +SendFX1YKChorusMix=20 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=0 +SendFX1YKChorusLFORate1=27 +SendFX1YKChorusLFORate2=83 +SendFX1YKChorusBypass=0 +SendFX1PlateReverbMix=9 +SendFX1PlateReverbSize=85 +SendFX1PlateReverbHighDamp=23 +SendFX1PlateReverbLowDamp=27 +SendFX1PlateReverbLowPass=78 +SendFX1PlateReverbDiffusion=68 +SendFX1PlateReverbBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=DreamDelay +SendFX2Slot3=None +SendFX2DreamDelayMix=50 +SendFX2DreamDelayMode=2 +SendFX2DreamDelayTime=19 +SendFX2DreamDelayTimeL=19 +SendFX2DreamDelayTimeR=28 +SendFX2DreamDelayTempo=120 +SendFX2DreamDelayFeedback=60 +SendFX2DreamDelayHighCut=55 +SendFX2DreamDelayBypass=0 +SendFX2ReturnLevel=99 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=Compressor +MasterFXEQLow=2 +MasterFXEQMid=0 +MasterFXEQHigh=3 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=22 +MasterFXEQMidHighFreq=48 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=0 +MasterFXCompressorThresh=-3 +MasterFXCompressorRatio=5 +MasterFXCompressorAttack=5 +MasterFXCompressorRelease=85 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000007_Ascension 2TG.ini b/performance/004_Mirage/000007_Ascension 2TG.ini new file mode 100644 index 000000000..4a7a4f918 --- /dev/null +++ b/performance/004_Mirage/000007_Ascension 2TG.ini @@ -0,0 +1,422 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=64 +Pan1=0 +Detune1=-8 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 41 73 63 65 6E 73 69 6F 6E 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=4 +EQGain1=1 +EQLowMidFreq1=24 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=64 +Pan2=127 +Detune2=8 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 41 73 63 65 6E 73 69 6F 6E 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=4 +EQGain2=1 +EQLowMidFreq2=24 +EQMidHighFreq2=44 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=0 +Volume3=56 +Pan3=0 +Detune3=-6 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode3=0 +TGLink3=0 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=24 +EQMidHighFreq3=44 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=0 +Volume4=56 +Pan4=127 +Detune4=10 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=24 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=4 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=2 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-13 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=50 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=32 +SendFX1YKChorusLFORate2=82 +SendFX1YKChorusBypass=0 +SendFX1DreamDelayMix=26 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=105 +SendFX1DreamDelayTimeL=105 +SendFX1DreamDelayTimeR=107 +SendFX1DreamDelayTempo=90 +SendFX1DreamDelayFeedback=16 +SendFX1DreamDelayHighCut=52 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=LScreamIntoTheVoid +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=1 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=61 +SendFX1CloudSeed2DryOut=117 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=111 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=10 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=3 +SendFX1CloudSeed2LateLineSize=50 +SendFX1CloudSeed2LateLineModAmount=18 +SendFX1CloudSeed2LateDiffuseDelay=44 +SendFX1CloudSeed2LateDiffuseModAmount=46 +SendFX1CloudSeed2LateLineDecay=66 +SendFX1CloudSeed2LateLineModRate=24 +SendFX1CloudSeed2LateDiffuseFeedback=90 +SendFX1CloudSeed2LateDiffuseModRate=21 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=1 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=100 +SendFX1CloudSeed2EqCutoff=63 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=88 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=9 +SendFX1CloudSeed2SeedDelay=24 +SendFX1CloudSeed2SeedPostDiffusion=38 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=Compressor +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXCompressorPreGain=0 +MasterFXCompressorThresh=-7 +MasterFXCompressorRatio=5 +MasterFXCompressorAttack=0 +MasterFXCompressorRelease=200 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=1 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000008_Bananen Mk II.ini b/performance/004_Mirage/000008_Bananen Mk II.ini new file mode 100644 index 000000000..9b9ccf42c --- /dev/null +++ b/performance/004_Mirage/000008_Bananen Mk II.ini @@ -0,0 +1,373 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=111 +Pan1=0 +Detune1=-1 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 01 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=6 +CompressorThresh1=-16 +CompressorRatio1=2 +CompressorAttack1=35 +CompressorRelease1=165 +CompressorMakeupGain1=0 +EQLow1=-2 +EQMid1=3 +EQHigh1=6 +EQGain1=0 +EQLowMidFreq1=22 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=111 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 01 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=6 +CompressorThresh2=-16 +CompressorRatio2=2 +CompressorAttack2=35 +CompressorRelease2=165 +CompressorMakeupGain2=0 +EQLow2=-2 +EQMid2=3 +EQHigh2=6 +EQGain2=0 +EQLowMidFreq2=22 +EQMidHighFreq2=46 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=63 +Pan3=0 +Detune3=4 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 00 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=6 +CompressorThresh3=-16 +CompressorRatio3=2 +CompressorAttack3=35 +CompressorRelease3=165 +CompressorMakeupGain3=0 +EQLow3=-2 +EQMid3=3 +EQHigh3=6 +EQGain3=0 +EQLowMidFreq3=22 +EQMidHighFreq3=46 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=63 +Pan4=127 +Detune4=-5 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 00 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=6 +CompressorThresh4=-16 +CompressorRatio4=2 +CompressorAttack4=35 +CompressorRelease4=165 +CompressorMakeupGain4=0 +EQLow4=-2 +EQMid4=3 +EQHigh4=6 +EQGain4=0 +EQLowMidFreq4=22 +EQMidHighFreq4=46 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=1 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=15 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=PlateReverb +SendFX1Slot3=None +SendFX1YKChorusMix=4 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=38 +SendFX1YKChorusLFORate2=58 +SendFX1YKChorusBypass=0 +SendFX1PlateReverbMix=9 +SendFX1PlateReverbSize=56 +SendFX1PlateReverbHighDamp=42 +SendFX1PlateReverbLowDamp=13 +SendFX1PlateReverbLowPass=76 +SendFX1PlateReverbDiffusion=65 +SendFX1PlateReverbBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=Compressor +MasterFXCompressorPreGain=3 +MasterFXCompressorThresh=-16 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=30 +MasterFXCompressorRelease=145 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000009_78er DDxFX.ini b/performance/004_Mirage/000009_78er DDxFX.ini new file mode 100644 index 000000000..2e4986eb9 --- /dev/null +++ b/performance/004_Mirage/000009_78er DDxFX.ini @@ -0,0 +1,373 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=127 +Pan1=64 +Detune1=0 +Cutoff1=65 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=36 +NoteShift1=24 +FX1Send1=30 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=55 63 54 4F 63 63 00 00 00 00 00 00 00 07 00 01 3B 01 02 07 07 63 31 2F 3D 63 5B 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 55 63 54 4F 63 63 00 00 00 00 00 00 00 07 00 01 45 01 02 0B 07 63 31 35 3D 63 5B 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 63 63 63 4F 63 63 00 00 00 00 00 00 00 07 00 01 44 01 02 3E 07 63 40 34 3D 63 5D 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 63 63 63 63 32 32 32 32 04 00 01 23 00 00 00 00 00 00 18 37 38 2D 4B 69 63 6B 20 20 20 00 +MonoMode1=0 +TGLink1=0 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=4 +EQMid1=0 +EQHigh1=0 +EQGain1=10 +EQLowMidFreq1=18 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=12 +MIDIChannel2=1 +Volume2=60 +Pan2=64 +Detune2=36 +Cutoff2=91 +Resonance2=9 +NoteLimitLow2=37 +NoteLimitHigh2=41 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 00 04 63 63 00 00 00 00 00 00 00 00 00 00 5E 01 03 4C 07 5D 63 18 17 63 63 50 00 00 00 00 00 00 00 00 00 61 01 03 1D 06 63 63 00 0A 63 63 00 00 00 00 00 00 00 00 00 00 57 01 03 27 07 54 3E 3F 3E 63 5B 00 00 00 00 00 00 00 00 00 03 5F 01 02 30 07 4E 5C 57 56 63 5F 00 00 00 00 00 00 00 00 00 00 59 01 02 1B 07 4D 48 40 3E 63 5C 00 00 00 00 00 00 00 00 00 02 63 01 02 1A 07 4B 00 4B 4B 32 32 32 32 01 07 01 00 00 00 00 00 04 07 18 37 38 2D 53 6E 61 72 65 20 20 00 +MonoMode2=0 +TGLink2=0 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=0 +CompressorPreGain2=2 +CompressorThresh2=-17 +CompressorRatio2=2 +CompressorAttack2=30 +CompressorRelease2=205 +CompressorMakeupGain2=0 +EQLow2=-3 +EQMid2=1 +EQHigh2=1 +EQGain2=12 +EQLowMidFreq2=27 +EQMidHighFreq2=51 +BankNumber3=0 +VoiceNumber3=13 +MIDIChannel3=1 +Volume3=30 +Pan3=11 +Detune3=-28 +Cutoff3=94 +Resonance3=19 +NoteLimitLow3=42 +NoteLimitHigh3=45 +NoteShift3=0 +FX1Send3=78 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=57 63 42 08 62 63 5E 00 00 00 00 00 00 00 00 00 55 01 03 2A 07 59 63 53 00 63 63 61 00 00 00 00 00 00 00 00 00 3F 01 03 1B 07 63 63 63 02 63 63 61 00 00 00 00 00 00 00 03 00 63 01 03 5D 05 4E 45 48 4B 63 57 00 00 00 00 00 00 00 00 00 04 58 01 03 32 05 63 5C 43 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 58 07 58 4E 57 63 63 63 00 00 00 00 00 00 00 00 00 04 55 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 14 00 10 01 05 03 18 37 38 2D 48 69 48 61 74 20 20 00 +MonoMode3=0 +TGLink3=0 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=10 +EQGain3=5 +EQLowMidFreq3=44 +EQMidHighFreq3=51 +BankNumber4=0 +VoiceNumber4=23 +MIDIChannel4=1 +Volume4=30 +Pan4=111 +Detune4=43 +Cutoff4=95 +Resonance4=19 +NoteLimitLow4=42 +NoteLimitHigh4=45 +NoteShift4=0 +FX1Send4=78 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=57 63 42 08 62 63 5E 00 00 00 00 00 00 00 00 00 55 01 03 2A 07 59 63 53 00 63 63 61 00 00 00 00 00 00 00 00 00 3F 01 03 1B 07 63 63 63 02 63 63 61 00 00 00 00 00 00 00 03 00 63 01 03 5D 05 4E 45 48 4B 63 57 00 00 00 00 00 00 00 00 00 04 58 01 03 32 05 63 5C 43 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 58 07 58 4E 57 63 63 63 00 00 00 00 00 00 00 00 00 04 55 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 14 00 10 01 05 03 18 37 38 2D 48 69 48 61 74 20 20 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=10 +EQGain4=5 +EQLowMidFreq4=44 +EQMidHighFreq4=51 +BankNumber5=0 +VoiceNumber5=13 +MIDIChannel5=1 +Volume5=45 +Pan5=47 +Detune5=41 +Cutoff5=88 +Resonance5=68 +NoteLimitLow5=46 +NoteLimitHigh5=47 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=57 63 0C 34 63 63 63 00 00 00 00 00 00 00 00 00 5E 01 03 2A 07 59 63 18 00 63 63 61 00 00 00 00 00 00 00 00 00 63 01 03 48 07 63 63 0B 00 63 63 00 00 00 00 00 00 00 00 00 00 5A 01 03 42 07 50 46 36 39 63 57 00 00 00 00 00 00 00 00 00 04 5D 01 03 45 07 5A 5B 3D 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 5E 07 4A 4F 4D 59 63 63 00 00 00 00 00 00 00 00 00 04 4E 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 07 00 00 01 05 00 18 37 38 2D 6F 48 69 48 61 74 20 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=10 +EQGain5=5 +EQLowMidFreq5=44 +EQMidHighFreq5=51 +BankNumber6=0 +VoiceNumber6=24 +MIDIChannel6=1 +Volume6=95 +Pan6=80 +Detune6=0 +Cutoff6=76 +Resonance6=0 +NoteLimitLow6=48 +NoteLimitHigh6=55 +NoteShift6=0 +FX1Send6=14 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 5C 63 63 63 00 00 00 00 00 00 00 00 00 04 3C 01 03 0F 07 63 63 55 63 63 5D 00 00 00 00 00 00 00 00 00 05 63 01 03 0F 07 63 63 63 63 32 32 32 32 00 00 01 23 00 00 00 01 00 00 18 37 38 2D 52 69 6D 20 20 20 20 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=16 +EQLowMidFreq6=32 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=31 +MIDIChannel7=1 +Volume7=45 +Pan7=0 +Detune7=-2 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=56 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 42 42 63 63 00 00 37 00 0A 00 03 00 00 05 3A 00 01 00 07 63 63 5E 5E 63 63 00 00 00 00 00 00 00 00 00 01 43 00 00 00 07 63 58 31 33 63 5F 00 00 34 00 28 00 00 03 00 03 63 00 00 00 07 63 63 63 63 63 63 00 00 00 00 00 00 00 07 00 00 33 00 05 0C 07 63 63 5B 5C 63 63 00 00 00 00 00 00 00 00 00 00 3B 00 02 27 07 63 63 46 47 63 63 00 00 34 00 28 00 00 03 00 03 5B 00 00 00 07 63 63 63 63 32 32 32 32 09 07 01 23 00 00 00 01 00 00 11 37 38 2D 43 6F 6E 67 61 20 20 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=10 +EQLowMidFreq7=44 +EQMidHighFreq7=59 +BankNumber8=0 +VoiceNumber8=31 +MIDIChannel8=1 +Volume8=45 +Pan8=127 +Detune8=2 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=56 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 42 42 63 63 00 00 37 00 0A 00 03 00 00 05 3A 00 01 00 07 63 63 5E 5E 63 63 00 00 00 00 00 00 00 00 00 01 43 00 00 00 07 63 58 31 33 63 5F 00 00 34 28 00 00 00 03 00 03 63 00 00 00 07 63 63 63 63 63 63 00 00 00 00 00 00 00 07 00 00 33 00 05 0C 07 63 63 5B 5C 63 63 00 00 00 00 00 00 00 00 00 00 3B 00 02 27 07 63 63 46 47 63 63 00 00 34 28 00 00 00 03 00 03 5B 00 00 00 07 63 63 63 63 32 32 32 32 09 07 01 23 00 00 00 01 00 00 11 37 38 2D 43 6F 6E 67 61 20 20 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=10 +EQLowMidFreq8=44 +EQMidHighFreq8=59 +SendFX1Slot1=PlateReverb +SendFX1Slot2=YKChorus +SendFX1Slot3=None +SendFX1PlateReverbMix=23 +SendFX1PlateReverbSize=29 +SendFX1PlateReverbHighDamp=10 +SendFX1PlateReverbLowDamp=4 +SendFX1PlateReverbLowPass=95 +SendFX1PlateReverbDiffusion=86 +SendFX1PlateReverbBypass=0 +SendFX1YKChorusMix=24 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=30 +SendFX1YKChorusLFORate2=40 +SendFX1YKChorusBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=Compressor +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-6 +MasterFXCompressorRatio=2 +MasterFXCompressorAttack=5 +MasterFXCompressorRelease=265 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=99 +FXBypass=0 diff --git a/performance/DreamDexed Bank 004_Mirage.pdf b/performance/DreamDexed Bank 004_Mirage.pdf new file mode 100644 index 0000000000000000000000000000000000000000..da6cc517eaac50b86bc041b4d11f300100f0b237 GIT binary patch literal 27841 zcmagF18`;0*Dn~G9ox2Tqhs4nZfx7OZ95&?b~^0Xwx;|4zBk`{HE(8a)v3L_&b@c7 zI;+n9Z88N>aXKb?4j8h*;=!)L*1%CNq3>`#`=uY*DE>97gF&T2k8pk-8(-OY7P&Vx*M_ngl}2 z?-ex9(ED}&@C-=(&b9F{dVSQVh#W!LDYLP$hvnSIqd$p;9g=4d@N;S$q5BNu;>AAS z{6mD}>=6MB_tFKFVK6w6nEEwHn~+l03}#I^LPo(3k1-l3d_yBq`US}FGcZJoC^1Zf zIQiLFH>@}nTCGiRXQK;MhYv%AnKu&{2z{c*cmKJd^SBDAW4uiRk8WETIpi?=vL##RoVND>LCk&qkotg?G7smu=6Gm|!8mEEG zfRH0{MiG`vWe!A~{1}|#W^5S3$sg~LXR#-Bod7>dAbObEfX=|W^>@e-H@^tZVw#}E z3v&d)HCw0RwsyodEehfmGmlwu-?TuBoH-MTc??jceVBWI-uLs?$er-Sgh#+wso`+{YhSLS9;i zZ;h`z9gsPV{KLaz0)DObcYgx9?b|;1Ej;h$9=L)8YNFHvJu(m8G_S`F`KO)_tAj8{ z&9G5s-Yp*u0AHGQ{bMFI4bbGr?P2HQqD%|+nP0<3mPN;;&6oeL)ZG+Ptc3o84-boREFZ0}(`GLUcAsa|}ZljJL|rdUsVj zIK-G%gY3CQR@U~-w3s>Y(BV2Ojf2ma772V~qTm=VJ=vc7uTRj>S) zd44JGO8Sa@CtVP)o-29aG36wW9}Hk4e;BrlBsS(LG))xtJsSrekM^=Donq-b>t3@f zlX~Ly_(r6{hw8Ee)be)fwvR}I9bp$@Bghcj%+E+U3zBbpV%Z?a3Wo!}IN|H2QaT8& z&+687V#k{pNdfU3s`^qn{-X|-;tKUF&j|+R)Fs6*XH~b}2(-<|Vs^0X)fb-*(ZDqK zVWs-uIKlVIWQu>z-;4Vr*_4?mR_4AJa#L-z=L-B-8r>x@kCIZOw|O<}=a^gDdw{A6 z3|IZz_RKhb+OJW$XY!o++^SGN-To@p^R#E!Ido#CwJZ-|@ZIoxGuQxOy)w0(t3=(l zmduLm59^Gj^wz0DKi9{R z#7vLKKR%#3yCTVk> z9qmHP1wd;96P(S#WCb3r0{3%xjNWI>rlcjh#f9gXT<@He>zr9(I;M9Vzv@IJ_tN%B zqlW!w*~7Pf7I$o^p6786nmr9low{2zN%x^~cR=$rnp{u?i5a!o%3X`DI;b4rNec+K z&AWQ;*xBS6omRik#GIjJUF@UsXmc@BxD`|93+5-$@j(&zE9e-BRunc@ ze}aBowh4((t*he!YTb57h)VBlcIQPZ1#6mGmvv0%&tYS09T=_QMFe!jAyx%LPOk=B0h5Q^ULc1|A@mlc9586xr-v|2)9$(u0LArLWIDeLi&FC#R&s>&if>R#$bW17b~M?6D< zu|s9*&$L1G4`Ze_(kZ{L$Bp8$AQy!zfX>%s`SvY{3NX>(<)pGTQrWT3Al-H(h{_;9 zkHDN-5mc(lP@AO>b;>4N#b;h@!vB)QZok^!4+kj4@8Q8}FBF@^V~p&xuOwT zb=CKHg_o>}CmB4$PK7O?1oNo#gs9!Dh3Ks2#2a@%Jn{{=er~#PDc}G-CtOV`8u+D7 z{0=J-{^cp$-dN)Kx!Km3qr_e-c0ySgt)K;WV$;zk|C#yL38ekK(z_>ReSQr0jXTw2 zIr-Cs>aaF@EI<-+RlK^1K{*g_5eMg4reh9^NX;>o*=(%wA@bvWeqh zM{?v#uHRMEbpLqw}D`=X9?p3{;KD(wXWVT8Oa#Hi5k%Z&nPRIA$vUd+0TgOSr77V zONnv_{8B=I!p_z_dmC6jfA#=TMAdK8uyGNAV6NmCNwb{8ZdfRBSNhJ(+|=mgIR0Hm zaI1Q&>X_4>z&Y;e+Ph04OM=iC8^6b33Am`G#s7N#mZ5UKK%gHZ-HB%y`N=E4O(>s; z>0!&uY9d14g1t%FTkvn3g(seorV&P-&wguo!|14x+3O?j*0Y2DI1Ov86IN)V7TM- z$h0&7#UiyWk}TV^UW;Wq1;LA6dst79vZd=y^vd23wHus~ABX7zxuF*Z9GdGkXY)x* zo`NK7hW_|K!yaQVZdCUW?ugS7dvX9InB5`XS@&1;m;VtURlA~Xpacx;gnmmQFt7iP za2R9$_?ew_h2LI@irr&DcUvh7K zysR>t!{U{y!{#J@_+W{qTqaAOr=p{x5ucZolajF~^X#dF%U(5{ZNPfsq7_4VgB$Nn z1!23)#IM}A4CcMuBWNqsqmr}0)<)R7p}vTo1fm2-Ae>s)nhO64!c_4y(sYl6(XO42 zoW$f6ie!>o7ls7BI=;^1=ggOZ;?D3$drnN!cxO;d4m%; zdF%6d7(xQ=hxxLp#uV&xb3d+SOgi2Ti7^gejdgHxxLBF@ZAw`{Nmzm~ZiLkg%|d7eo8 zy=I^njuynhuJ)p5F{>WKh~@HblBkgxuDr6dF{Gr{nqs05-`G&C)=*@NqN(t#x3$v& zlb&3iy91-b<8SDdbrevNo(T7&2baqX(o0q4TU(gNx^M2_VZ7olL2u(Af1e-l)t8x* z-$GzZ_8OSZ9-Q?qsW25P0tgKzrdCuE-a<>ujaB!AN7oJGQ3N4iE}EVdqt8sgBhN*G zD#5dRH__bUFPfd*G!_o5Q@U)frzpX;k3+FWB2T7N205v6ZuI(>OKw@pT|%+JUlQkV zwb<3|;C!PVIC0WdL?eqxq-gOlhgiZ;IG^M>S*;^2o5HwwRt#f2y!z-W$<_i2tc%VJ zwbWAjoohELPXo6(O$#!^G0G&kRWcefd7s@6M~)i4EZUw5PhUwE7xHJ?@*U!TJXe50 zOY;kem%~mf+uEhVS_r-~K1-{?S)$Jcy_;r0IIXfu4{`Jw&#kU0jpsAv=^Xcj-ZdtH z*XLWh3h|e=uD|=#R~YufWnrf^^9E?wHdj;}8X~lF**1N?v)I=jLPsEF#5g)9BP_&< z@+2=1Uz}iey+dcj1GCfA1FrxCpn_vg#Yg;`2@d`kuW%O8j!2T@&OqH_d4Os4G3k2S z_{TKN`UsXh;(209bZ^*K_Cgo z%CuK_M7!K4rb@_y&9C8MO_vflrzO*~vfI%tD?z#>TYu^X+4^GJkV5|q@9UZl@+WW}n_-&Ve~hsIjZixEL1`2gAK6M&up%V>9DCMum>Zw0N?m6v>^ zt3cEcVC36N)MHci|4N|H`jdddnmy*!rAKiGf}n~=#ck9iA{J7!q{dyrId6SWzR}f6 zB7CzM8}fndu)hv(^x9#v=cI*eZ^E*m71R7M6bt?V7G*(5>_BQYRpSfKpr!R$=+g&0 zj1Z4oZ?kTtlp>*2c{joY1WEA{A0e7gOM_@rLgwo52s%OIhv|uhdg7l)3GjRUYG|6x z-9_jv<9*C;SM1PU|DLb7zt>=rvJ)plEr=ye$Z#yBr;0$5k#-F1-ma6Wk3|2onF4~N zv}*x#Arr8IN+~TwrGS81Tv_Sdge&o@rup6#80>2vv26j6g-uI*2|aW0c}y_^CnF=z@E#hUrhKe+azc?)r9q~Yr3yf zIVn2oLrSlzW+f5K3^`=U;s?eno0^f`4WK?SV-Uj?$5ZD=ncivCwo< zB_|;=xp1W_^-!@PDPzrHe%RTl>4!@8^r;JJN~$a}m*lENcSxVEr#KgEC`;bA^~nMo zpPNY#f8m9l{_vpBFMde(erWRepgZgEolV;#n5jPPDSVbPj49X7hJHZXuSiM79DzZZ#9W%N zUyk{q3{>My2}-|^lp?DvbX%ul&pYhtZkJ6`(tg$k-Z5K&*dEDJ(n&dPtPNzFZKvg? zTrQGYO=l+|Ob0uzc>^v!i}Lh0oL{}W?|R;&1|_}{wP}AkA0D8}>R_>2th}``=qGak z-Y&K?Vj*2O3HF1jXw;{)O}1aF1b8c|b+u|bWQ^yabo<*l`F!)Okg-aY~SS+8BpE))zdO+%5w~?3KAyke3nMXbz$8~3cw3`Yj#ZAuzy*}Kt>q*_itt5A_} zealw4Xwl4w@*Ks*U`x@dJfq>SX}K+Z&s3+%tMt`rEjs?~IGwCt{rlDW@ctd$B}#`z zc8!PgfmOegGdb@?Ki7ItUvKC6={gMiWT;j<^r--U%DwcWPq`#v%n^d=Plq;8^(I#? zMvG@rxtwlXbhsb03hln@lyqt8U^AGeS)&0NS zl1cgp?%ltUzJzGdu80Ut`t|)4}|dU={{Ma(7^<1`!71AdFm? zI1loP5z}6(tQ>98AX(CI%0z@Av&!%m814yRCKO&<*VC zdg9`+Px4;-RRiYS?MrS`)lg?jmwj>_vUrxT%51-PrnNyez9C9 z;NBhJd%s)&LA}GC41j-&PmoR60)yl3-Zo&h@(_|_3{W#iZeX`ZFF0o=qAo|bOix+c z4@}O-%@@P!Vn6!Tl(K)GBHs@#5Gs5q-j4INQe2Iy&)18AKqV9E`Nzu`^sPqXgX_*Y z33q)D>1R8KoaCZ5iEnqRe8h{#>hndI+6=||#6?m9M>1LQ5rOk(TZ zbho*HGXJ<$B|tAbV{22Pmov*tZ@s|gcpDq!mHzN}0*|4~N%j0U1Ml~h>g9C-F8-Sx zqR)bV=OQcDG`ZCUZW$=@4?NL&XvJQ+=Jmenc|jO>JTEcDQ!y?IdMsUEE_d4!Im#?v zu_ADW?|ery3(!@l#ay*gtB$3P2^4!o_hiKWdx+jk?-R^6r@P0e3K}%n!xyzUI>cJw$vyjR(f+FlA59 z$}kbnz6v$IrPBh;Nftim?$WU1hkAL$-;a#>VfFZx;`VYUhC%qkaKHs*;)k3;JJY*S zn4rbXkE}uB)SZ}N@cS>L4hT%aoX6DSlM{^l7j7{(;;0!7t9mUqtQ~RQZxZ|%vp(j$ z{6dj)GUCME)vQG`;j1$3A$dR%Jn$706e4Q&RC$eQTC5nBT^7$KCn;e$r0bama_pT- zU_tCmTueL(t5`~KTo8HyNoOthrr5Q%c7qgH^mc<^u$%Op$AQZ9?(^V??FMPE_UvbY zCG_P^LK(2p^cqYTfl2h77lCCu^|Rn@ox2kBP#p%fuy;DUhJxlgH$AX=#*90r_UVc{ z14wC&x5OAw^yzotSzb%vJeb-;;|2#v$J5BZ9L$b2^t&b)Domkey7qw%zb^yfWmRy~ zbZ(#=Vpzactr(xXI|fTb#AacL?f$ zy&ByVJAb4(7{}xgMRN9>C*}-beG3@Mp&RMqx@yRE2>4;l&qdDpvzhf=rGhK=RjFfD z%EuDt5#JtKq^{dF7Na!BE90_v;&9-{)TLgc1jt=;vU5;B$<4Ye&-EVc-4?pJS&qQE zWy`_J>rZrwdG?n&B<_$FkUaWisBB73a5=&&d*H1MnbhIQby)V3hR?`SEZQ4p%bqM= z(9-D3Q; zKJL6-avdKt+FecbTfWxAmFk4>&h36O3@^2E7afluVR^pe--jIXRBlwAx!5sS4iF=< zAQhuNQwEZAFoEfWT2uKfe*!|+e$y%dfY(7l(V?_=j@V4>;VAq96rqWoWpeZZhj<#dq#;QKbXaPBI~^0!T^Bk?0-AfdfrpKxo24I`ilG)gf~$+5D<7-+ ze6qFLu)G|KuK?Q7JE0&Rkz7Ze*Y|s`lsx_?Sse!LnK5QxCiWDb0?3k6{t8?dYHCkuU7`ZTW5xlwvL{6fMV0H>r zp8kC>wr26FOjv1P`}BZRdW~kNKa#gb-A{|U6AUSC9giXg%G+u))OA9`Y#etCHgAjA z;9@Ty-My5`D~oI|3Kd>VvDqfE*$MICu!o!!p5~5;{R_Jsb7IggU!wCMGslUBgc*3+ zmC_Qibd*w3T`y*jK=2s)9#pxi;;~UEKyD*$DYLFuUFPb#UUqhu4{a~jvpZw@?-ysk z?OOOt>&k6?QzwKjxxp_ph0P|h5XyuAdmi0M@-CJ?&ORVOb7App5$FTlIH4MrUmLDW zRgrlX1Fby>e5|L2Z&0$UToBIgCUxBjKW9x<{*Z2)H^ni3l;fwy65>4i zx9ivQJ{97-GSYJ3Gv_-W9pK=0cB}TjKowU?Z!66c;Y0n=t0Lj zXgi-bULSlCY;-fMp`^xm&{t(A(u`P<*Ck=3xTV1CIqYpaT@G|p$TREicZhrcI3Hwn ztjNx?awUb)aw;rGBbS>CuW|2U->@04@eLa!$CRqtN!Q>-E{+h?hp9i%WTh7$`5;1> z){mvN#qOsV-WN#l2pu`Czt>D~E2VjM$}v2=N=trE(I$eK+42*Xi@u%~s`?!Fa+YKl`NFz6(QT?t0ZTEfIRru-ND1)%T#*&SRP;IMC%uw+`QEZPki+J=FA>?L~9Ad48Ky(i`!eA@FGpec~S4%BJCl`Az3>% z>^ZkaUDxdlEJN@8u?R!&ba$b5p$)wyfa!zi@|I)M;ta+j*g6H+^jm5-Wlx@eaEK`X z3U3hLlu>$Jl8XZE)OB9%#kPGWJJ7H4j0 zt4bO)Vw+l(6k&GCJ`{x$=qAw>B?Y!e?4re78(YM1#T1eF!sglaL5HmKzG50Za^k4> z2K)%UzxZJX%0$qF+DULJz|bniar^xPzSrxrhNBqO2&XnRNupQd*Zx@?{U`9 zsx2#Jc!0eC*eN$nWkLz2L4NK$X6Qu5t#sw}Qm$&<$o^g_M?VOM&a18uCKXl>H#T?u z#G0zLH*FZP;^JdOuJ(Z~rT%g&?cGm1f1Wb$tS^*l+w&@;XyRQX#~@~)gvL*O+g6|b zmY$68ry2cxN4nBGD27<)J4%Q!eRu($R3Rtun zUi(u^uNebJh`G_kVIC)tDJ=4xZJTHW4~JT58;y3Ldtx9-zZ8#=dOhk9&ak&27hfe*$s`(SAG#iF1mv>q-w2d>ZMS_h);v~?{h%7}0qiob)(g|CH0IO;h`8IU zTv)ze8}DIylrWHawOw7bEKLR@X!GE+csboS_5ble7J?hlRndIb%$l1r4UVr)_B9SyIZu>H z_2GT)_PTvsq`mJRrR{J%C7#=lMpkk2TlG3RcxgxN-wO2n=yZ_JjF;R&TwQq9ap#{R z`gCkj+jnVKMuC!Yu?XIj>4F~jz8ix0{&p3~!f}uKy?+E3_&dku5FXw)j6EnsOX-sg zsS_-c0a(^fEUkXJKCg!NO8xd5KfWiBl(<0d%Sl%?Bicvi+CBUEn3vQM7b}3d|!@U8taQ=j)}v}9Ly9! z=l0QZ0Y+j`9_5bgDXjPLd9mL0@p&Z2;Ho}C-w>N4iukM$sEW}lB^*FjNSq`}&LG7l zV6Y090kJKtt9V_6o#d+3f$?!|hgdIQ-zz+B{wrI0wI- z#7oRewwxt#7wr4JByxoqSJTaJsV9T&UpX@UR`v{j(0=gWl;1T9RN2To^Tif+%Uu;e zms2h3mhl%dTo}$4A57n99-eV(?XZI4YZH#2+Dt0{Ijgz<#Lw=9MDbveG6*a17c&zt!<8+gRBh zf8cMaAzO_HwbGWrb)Si8dmMsWw)zdUHCNsmLmK1d`Jf&VvdLq`6Oeq5-C|2#@!^~d zhDfsJ6%SDREl6&Z8{5WJh{9`?MPVx3x`8ekTd!gpMXK5^WNR&%YG1dplE^Xu`!}}Z z(BBO53q$)>zx%rBbCrLKGpo9Z+GdTVcq-ab#HYOZZ?GpZf9`c`(flgfS_R`Njum7j zYzZ4UfA3Ux7Awhq(y1tRS88BoK-HQ@Nj?gG8!Y$|Z01=~w@7zl(uin=l3Ic&d|mkH zc^U}WnhbK#s9>7I$iO>0O-Hjtd~yMMF9A6%T#x$oBcz9Tji3OOEF=kLas=qa8#sp` zY!NR3M5$R|4*3H9p)OH42P2aB5mMb*qOji=_u?uk6BY-y4_2Ty5{(n#0b z+|4TC&m&y}K6&%y9txV9~|JR4#ike*MdBPD_@&V|w? zSKIb}7IY|egbUjQa8E>ef)WNEZt`xZmd@aBpqJ&eOB!xo!Bn6wgdw0l;LFx;B71}| z9q!u$OoFI1wPTXy=C+Ij`R{@Ku~2NHkn|0Z3Goi{l+BU!B`iyEe_TX6VMfM(W1U42 zTS>w=JMU&HDi%DkbuWpQ@12C(2RwZt&4hS?C>Af^P+dfd4=zSVuGDC&V=B}v#EMgi zPKXJxV(1beRFy< z)fA2#C+#AY9U%IsCFBcd*faYf{KD7?iMfSzN)nY zicY-kn2jf|P8_p#PJ+yg^UfE}1^fFFYB|gnh9&`|%NO%G%)CT#L!B{wj8YU@nhmVXC%I~##wH0Zs+sZiu>=te!rB56ww5>b+% zO7nCT2E~z@I3YG4#8K{pwTPF?sa%ry%V_q;D9%Hq)=m}pI#TO&RT3zvTk#cip_!eQ z(PuA7k|aC2eGe?0vQMb2teDU6U$yNsW=y`_Yel~_!V(pFbgS_U-YyK*mKNVsrVdZM z77*_eR5tys()d3@k=W_UhR4+(x5lrKN7@iQB-ik7Q=zoYIhuaEQ<0W704@4$9(8l# znATr%ZU^l=S}i>m`u@>Lt8!?G6|-DD*+AaTnxW+>jcRXmuGFJ$m}hJik$pnGL}QFn zcny-J-hinu*N?^IiQK&;HviRLoe zdsd3Jw(gP;*Ql;G^~5RK8ZEvwFfLG>Rw~C&QT86@qs6GfZjq+AZ)|_!#%u}v&fk$M z%_^T@8zMdH18mMX#K90tUKx*0s}i(^CIR-w7FKrKO5e z;C`bs+2-I^+gO&QQZc1}>m4a_49S2Pl@R+br|qWP7iK$p7dN(@ZZF4c5G66o4WX3@ zR{gF}WTVg(4H%gi#&Y^GnT}CQd=;~`7RT&CESnZ$15ab$gTO@_y*hirQXStm{_JhW zCV~cBPB_h|>@x#_b#8+=HBbhbwpey`7@iTepJpHcIofoaQS;PPpBFJJ+j1S`43Ss+bZ?KJSB&5M5IuACE*O8lcY?&r z0k%Q}l>_>U3+LVRnYFcZ<0qhdMaA8H&bsOe6Dik{3zM_qa`r-Xo0ODzyr0Cv>&KUH z`Fb-1H+zdk!1`?pp>|Dx>euH348|Vs-O+!XzRbb4W-!j_!W7P8;{3 za#fA}TJdm^8MK?ygrB!Z1WDwKgn-ZJJ_bw(Sqyp?&T&|J`F@ylyJzU^+?li0&@+sNtY02Cp7l@;nUq^~e+6R}m7ku*bhLu!= zxI&bN^YHwfhL6Y1#OrGK9KQ>~wNICgD_7U;sx#@`<7daHW9PB!RqLf@Zr&&Br1ARE zI{HSd;qO-4KQ(P89%rqAhv@MDCM_%4EWWIcyiJqa=54SfKb?DHJGwi)Aa&F_D7_9t z`>+7S!3@R^st>93bC@6jILI*h$<+|WoPr)LdHtUe6lhABx+PT88%jNzL9Wn*cG}hv zWoUWobQO;}nn{b6XR1c|Hd{;*_Y}}iE61f((YM9kuez){K=#vPESY#7t+w;Fu<6b6>O8cum4iuE zxo}XVaAw&WShl8WWO50{kqzbs8F;PLjE1Sw_mzz*nOe5k)I*`mB$UkjXtZg>YT~D+)0>oa8@#lrI67$?sE#yF{X*qbtl1MHkdO`VJ# zE$y8Fe{tJ?Svf;nQwCw7e;*oIOCwW9LuX5XowA{w6P+-?#suacxZB)`ko7O|*IHN@ z;I2)_%E?4X$HKu*$i%|PO31{>!m7(4%YIqe*w^08Cm~-;ODxDlXgLjNMg_4A!(qa1B?-(Y*k^SjGPD0PBF`K1P#`#r4w$;0dW18~>>Q0^)*|Aza!&j^S9jf&v; zbo})PuqO18M5pnAG9?k^7x`*&%W=W@Uet^Hjf)`ufx?M-E6*fC^2PM_m*{ZK71(C` zlQ*~+?ibC4a~t>C^K#4-X85&=414fIVOQD1bzC&EcN9&eTT`<0f%xf9{pABHcQpy| ze<)if#{d3j|L+oIPjH^XdMNPWbOW zCH&XMN-zv6098B7e}^mx|Fy&a)*nnv|NS%mSA#J9JGAkCI->F4a7He6R>uDg&gkXg zjVku!-pzk>HI;+K9B?{L3Y;Au9PAHFI-P(CMv5B%2Q?laObRoejwNUkVowE@a6(Kw z08{1ePl+PfpHzP0Nnd^ZtM-TP=5;MbbyO8i@x7NWAIcBjo}Jm}=l64tq|@5U=dj7-v3hQ~ zNVU00mkGbbCNbWwG@2rjl&Oih{Oao9my;pe5Q$7!!&pOCjR(ykW6VD7<#N2JxcGPflx<%suGXC0@0N6HQJu{twiMVBR>n z#W0+-;peaZQ1ZIS!VHOk?JY)VE$J$EHP`iF2tFvGqsi&GbW%0;4N33?{{`;|+ndQb z?&x`WzbF0!Qd3;=IZgUw+wkJsYO#! zZ7CcN|IO&m`s2a6t1k>>dVKL24&of!;(*O?8p|He{C6DY=yx3C1Gh1Um8dQOar`n} zHHtSYnf3Dw3e3{;RgI3Mr9B2P0>Zqk^@d);>F@J6Gqw$I$md^$B3ppTs`zI_hmc%h z%k1RZTpkJyMSiD|2TN1sx*TSY1vV6!I(n*HM&C`13X3V#B8eEyRc;=xgXIG-EviXT&ci`WFz^NoFiu8D~a*FYXsDIiDc-V=M-?`)K6(D z!$a|ygE(oY40I(wzZ7Jve;8-D!#-NoMoNWu+%U^Z4JUgt_7lgF7o`w=7+p+5``%(s zWvB%lPNRGXF+HKt$rqT?C#iu|zj&_&IhNSdppQzYuC$@66UEKhu|_|~)v>{i6JJ7* zpvP!L!rz7cHk`xE2RBo=9divm0W;Oewsa^bS7Wa!bPpUohD8|9#FV*{&nINgO^mi2 z8EsB3UdykSV~@Dh#H(o|Xo?3{1y+vfC3n^pi-tGcQEP2)d2CH*L&CYpL&EXC$Ksgj zVoyEHQ^19#RH68Jjb*-2LPRuTuJK`X-Ue2-|9v*uLs#G)MLu{(rx?j(<_%Y>{*oM5 z24=doq4fttMypCoWb~Id`iodpZ_Ad66+A{!yObt)BInBI61jZ!!IQz1k}4ue&}~JU zY#wTpe3mw{F|+j08&d18e!`Ah$*B2dKh--IqfkS>y}|&09&zZ;QPM^rnub(MG%HB>ZS>9$ znYXslV?c}M@IW@5 zIEbtG3&&1U_C!bb4iqH{fk&S*I~#%T8wQ12^g}d&!G1Xu-C{4Ao!poU1uUwGIgG}j z)AWh_SQ`_!sn^iqA&M|}Qu#uP07)~N4`eAFDtX85}5iTuOz=}u19eM4cL|hyq%(WqS zzC7wb$F5rlFZswMZrfB2YPt|WIzSk#Or!*oHOQW`u_FBYq%4P$I0>$+IO!oV0vS`D zhw^7w{UKE}-=iQxmLQNk&r_ycR-BMbr`}yTCS5pD1+E=sFRSxwcH|&=;MNHmBzBp% zg6`&H``U?G*0L1`mu z$u(x7Rtzn~r0)asJE0A71{iJIFeMTGtEgL{2hl19^Oeg7e%Ro>4$CHvgYl< z&aOB!+vM=|{c)~;+zWD-R~Kv7bKTG5*KPi+cI4sF=FP(@!nO&tI_WmfV?eof0617Z zbUT#D zV#dalB9s&XGlSkFlmS1po<9g-%U<3nR15ED!x-ml*Oh>Jh<1o^L}_GC1nMysR8x=i z9eVVpL2w@C&1b=;MQes|(E3qpedxo$B1XVC*m-pJ4$n7`P9Xm?MAtEf*zYQ@f@Nh) zWG`-5S~QLaq=;3(jSdTrro`^qK-k+e&tmaZ%x5=pDZ0_1a@dwkjzS&XSxeR|FPGCA zgpmqJ3>XTm4+qEzs0XU=6o?nkUjn3_3Wx?|4%J@~)e5ff5z03w5K-x-5@-s(Zwbg9 z#GVMq-0~PdxCU4O5=sG#9_SeK#xRieshbFBkP-@#zDv+>%?a@mtE8BMOoL?scU*xX02n*>h+tW$;C`*+7JGz6sdDNq>K;h zJ>QUh-sax)`egF6M;6GSh{5cmAcM9ej(>pLp5V;EH|+*DvS;pTBuv7c^e=?7nDn=Y zaA(Qq0p(`NCjnhLW#g#&&C1l9yCqElfv&H0B-krb^oYpN#~zj{H$GB%??8Hd41fGK zIZbmlE3x>Iegrjo$Y+0_H7nq?XxqEqY&aTvD66$<-EVbGJ$U1@sqScRBld~=D)YM7 zo6Grl+F92d>9igm>5Voc)*uz5L{+u?W7EWQdx|Sy3JT$PKwQrq%Of-9 z&Sk%+F~Qd)L&d1gs`(R&DWh3!C8=;8iPhFrsDOa8-Pht~YTQ()No+P1{BgXDcWy6$ z58vWmFbZ-2zx+-x1JaRiuE?CvECKbG6ZP?IRN9{>q0hpD3LA-b%seYnu_`A6_WZe) z-FEZy#Oco~_;JL%PWwHAn|bA<*54~vbA4{|-R!;2k{kiR@gU@wbB|q}j|n^Yn+f%3 z7pt6Qs6P_Le?NGFN-_Q28L%BE&0v5f*9L0};FK>BmY^O|+QaR3EfY4UeqgZjH$&v zSpV%4+mHT-a9HWru07_o8Q&-wPm(*{oek@G|Iis(PDTTj=XN68y~=uNSA@~Dx~$)< z)iIT~sl|sSxSF5PSGc!%&murolsB-0nDbh`t(vC&G)4U`YJuWpbB7sF^LdojqI$u6WwmFGmC9j5H{l#kCB?OTlg z8J@c)m3qK@4>5oerktdLwN&5L!94a`)I9K%-*=(k-q*R0*pSX*tEQ)GkG;pW_hSM_ z_dB@FfT;R9ULaw1{5v>-r&nV<`=jaO!1%+;BkY6IqR+R$2lVf&QxHYi&8MtUkQyC#7WN|VJ~@(s$K%j0(m2t4+IA-U)nzdL=prJ zMG)2B^=DIu%rjIU<>y3jeZGNpGpC{4Br|tR2BVx(vVJl^nH_6NVixJ-?h%X7X~3!Kt6V!;ZUP0PrfecF2L1{6 z&SPpL`8sA3uA&j_SPDN-v_lJK0CMcH0**#~&DU zPXp=-pUGv=GhaOHo}{H4+xZ|EMhZCMR)XSIW?7*hEfMBaP&io@#)<=>v4VY6Ry^92 z)v}0OsP>UcmPH~}my(i8L1KuNs{FZ(zf@6GL<`1(pCss;)2MR4o#I~|;&S{G3JYKG z)kxzyL8c=RIWV2hxVTa}Q{FEE!`^LH>0RPh{ys3T``w*^GznuCtiX)iI@#m~Jcdoo zP2)*}vVO`v)#J;U&KaA-r}XR86q{}|=V*ynnRcKfSBfHu4R;mfQfj|Bl5830I%H{w zGsHPrqR~iHqZewNftXBJ?tNIE%HjnZP8`ScKSs<0zMr~igD$gHnpVf0GVba>9-Iiq z@!r#S25s6;w?{*FmMHxQ^U``#^z$^SuM?Cr0TKPAru<-f2bme;7EYnkmcfcPGs;3N z?gdb#AZbBu8~J2HPS|T~mX_7SiN8oK<{L#)A7b~tc&Y~oUTIisGr$KG zkkZ=Tcz%Q}V?ml+}E_>X>Og;tl1s-R$i`s18HNFg&-(uRT zwXSzsJofn*Usi4FZ-)hXpOwy85N4cAUa$4IZs+bu=;>dj#5uhd8xN~eopp6OeJB5~ z&dvg=t)+YP6iO*t!QEYw5G)ia4#lllakm75OX0S7p>T^+toWrsDN-DQyE_zjch`UD zy}jR+@4f$9FKbQCIeYflo;`C;PS$UR^FSt%(1W$?W%FysU%6R>NO0c9F1o+rXC@VE z+IXm|3wDmDwFnfpumVYp<7is2fYHiMSs1J7BoRv92>lI?d?0~OJ4{aFmt1+zEL95~T+DA4*1hSgyS@ciZ^rqx z&&YKNjXjDzHAZyZ`+CW6#_Kk^N(T9ZT!Hrew=Egc6o+w>Hbo0`!C?G@d#*F=`~qja z)XnbQ^>+1@;~|E{R$H!NZzz;XT8-wr?-y9B!c>h7vd%8dm|c#!a>#aP(k2QQQRf5J zN!K%)x$?r7feBoRN~v3zINAwa5`04(x>+c|a58%m)mwgHN1~bPs5fFf=_> zVlgU9i`s@6BtzxW(mSk%tu3S%jIS93UNSYSzvdFRf60_V8LYz|2;{MHVCxj=PrZ+J z*jlgoNzueXYHsH8)aPi|HvpzPW97|6K3cmU#4eq6#`H=btd+rvJZv z?7Yr`1IfRA@wlL1&lH{JvW!z43gpC{HyoMfTP+8_rHIl47o@+?FL_xLmS$U~@v${M zl09!ls7-?TQI5yj9Bpe8luFnA;o;nJL-&unwNU9kFeV5(xlCZcE4E`B;)T(*|6E50 z`Lw+GpSyXp@=EukB4PNEq&v%p< z#^r^^?*uwRNmc@#`NyZ~E9Ps+dn@KS`D^9^>7nDBfiq_%p7YG=SAyS~ylMsQE?e+w z_i0xiOgZaKf8{D#x2Q5kopwtnr-05)IrQQtL*3hOnWt{)ubw1Bt(7Pc7?l_$7zIHV zFp6vrvCxV%dSkq=pf+5h$?-+87?<2DN38G901spx&e?lpMIG* zkk6TkF|4H~YN$}Ax!hig&2lSlqiCNe-~~~Vr^$_Bwh9A6`2qUNHWZ!=o8IjMOYpk_)vG*0 z=^Ft*@i?C36%~c0g^V~j%Syy&QIo#(Ygs01vsj)|QMnh~)jSr8RkJJ2N3FpNgt@ja zR9~s<3HlE;B;rl4_b1>{uJ5bAHK2WNEEH0gNl%JpJN%5X`T(O95{Sy{r}>^)?|B6J zTsWcEA<0Vc3QFGg#i3&Pww3*Ko$W+k8~FK$#3ul|B~)-QlGFSbBeRcN!bdnwFz zWk%?DA0Gid4X|xeH0_c>@1Ch|Pw08k9a`xh(pqE60E%HqaOu5KDtUUip%!JwXUbqT zgeu3F8&c9=kwJf6)+pk|gfPNM-Gkd?@5qYhJkU)o;kq3=-G(Mq8G9^2=i?WviD$0u z21iAu`EZPs3U%RUy@uB|P5D+`ocy|{wFetfL%Y?m+pBHHXTKS?xrbdQrS#}_Sjq7m z3cdHYa|K%nT7U~jOo;N$L0lzhH$CbZugOdvTtLx-BC$-DQroOKUvP22Q@e--m(kl2 ztPSst(Naf^HR=93{>b3GcvHgXxDEEpw@u39B!!gsMdJkBenT-%-2D5xE`q`XmKNF& z=8Tl6gl@q{QPO=K+-WTMliajPm@^7%z5cxlYwcINy&VhpJ_77NiB_)GH%)BDb6|2M zM_mI$SHrES(7I3IyZYCiU41h(H-XDii_n7H zuwms+LNIl>La#dMl3iTeQOqG542MAp?inCf*4T`7CduAFkIF~<#&hiDxj@)-(d&=isWsSi7^n3smN)H%v8S`e2*je?S(?WiA+EuZ zYw85O3=#SE29Nijs!ZscvIy8=rX-XWe6ASt`L7s$E75KEZ2)Bh$g~##Ij`L^k7&?< zOECWGVscS{4n7+vKXn@cZ>GN1ftm(l9-Pb*ojrKBw3@c&dJ+;EwQCe-z4E=fuBKJY z{t|SKp{*#w;2FuJ14&tPPi~Ms3tHW1SGroh@7cCUs&p(lY>1Kv#wdt4+@Eh6n+3Tx zbv_z7|5UhmF<+-)2TdSYgN?+8RftRDZYq~&3#i53r^I_%sQm7JPc|o0YklI8?#r5^ zc81%*T%*GK0*(xuDo*!WTCBk_bkjwXGah0H*v$0>os~ls7>|IW&T_V2;sdehv#RaU zm}kD_@Sd0Mhde8p*hYdpjStT8ckeB8SVNc3PhEx1Hb+iV1!b2(_a%B7DwqU=<)+C{ z0_RHwQ-&NL)CPVP9PNoM&JRJ?c=nZ(w;mO(o9B7Ry+CrBX_Sr!b2xkN?|m9V$-!}G zL;;~~f$CqP`QxgXqI4i%2z+irX-2_a#dTnMAwCMWp&i?#N2eWRg!wUU*v;GMfZc}+xkd+7C z5q+r4*#(!beY2?WRty`bZQVVVr4{G{9FMc4wu&iD?Tk#EIbJDRY)c3dS@(=@*xlB* zJR8wBjVG>h)xXN)9;NI&7i`smsxiKY>lW}Ok7jSjy@h~nhXi%*Ww3YU60FI-(Z)*3 z7~3IOQ+SioD$M#=sgi>)6ZIP*(eZI`TngJUMae3AE9n<9k6X^7ASy)qXYY}4dYRJt zFLiYnbJWo}GChh-CT?y8^RvHd8GLK~)EO9+YiIGoqsBlPC!Z(-^Uav%gYvySf=6BF z?}hv(GQ*cWP=A4vFEWM21uGJGQtGx*whJAfb&NQX%sE{wAc87siFZv7xo+M}_ZH4D zM%2l;?xeeNGt4$3B3uXG-&D%JIGwymBR7q*^OnvAf8$hj>(LAl=;fCA)caDGDER>R?2O!;yC zdd8ckh%n0 z-d)l%emE_!ylBpNffrlBfVQ%>CStVuN_<#W8u#l#vNGaqKFEg3(SAx4hi*hI?d77J zOLoFTxvsC7HavcX?O%2CW3Bo($_f+S633gArK6SW>O_ofhTpH%eM#LQJQ2a*|H-V~QNym>vb|JWao-wFHStZa& zlP8gCk!r&E4feni$<6v@d-(tto=2bM0x)xd9E8mp4w;P}A6b%R18NCqKVoU-0;A}( z)!xVlRDlV+83@bN97wlQm5j&FDY10NLchGw$f^i&Rqdd?d6;?Z3D9MuHGSJZgee~N z)SoM}G2wnetcFpevo|Z@JC<99Z_Jjvw#U9FC7K$8!3((CLd0%__WJW z$fXZZpwR<&<}KHQ@S@9S*kF}|ZSYG#J-1AtbWkk&6{nYx*7y0z(5K&v5Jl?~q2Tio zVkhZoKBN9?rIUz_ge;*%;n2G03=?MM8jDWr#|Gh){%ot}PEKk)Tz>Q&A5@8)wIfl@ z8#2w(TiO%Qa51FA-7{Z3cA7WiYKEu1kCo$!PVNl|e--}`+Y6q?NDPNJBw??@=LtC1 zR!%G4pB=5MpPbw5j656L%IM~))v67);@oRHR3d*pEMj*S?9CHE#0Mpak+s4Bu5ZI| z-KWaZAKYiU?Ju4cz1~Rt@OmOF+)L7_!g)JvG)BHWx{y7_5@sWpz=JC-{BjmWaF1os z{vq!8XUe+U1^I)Rt**`RvAV(YeQaK3b;{KDb%(q=x`PoM(eFa$zS@@RR@Y~{b9^cO zG*;AE)Z#eV0HGiX{SDJrmnVlOnJmSM<0G5ycKw5blo2bO2W1>qvL`3PV->0%SN*3R z5(~x-yO?=U{4H|6mj!&H^IJlDVPyqNkei-T2aCh(9vgu3Ldc(EiKX?C@^YpjOAnJ z#&*>X4>XUidg}%bKlA%h-)DQWGWYC>*1rBSp=M@$lpjD1;%sNeFN6zFq++PP9(f-x z$+A=Tb&uJPP{jU|=cGx;+BFCLM1cG+{2OL8RIut+pxsKn+{U;z*B_(MBP-z zBbe{OT8^Ufl)yo6dUal-mZc%<*hu&1&!p9^QUkmIz%6{WKx@`mm$z(b2_!osV&U6S zhT&5JT`z*bQoQ%P=R|#Vj4C-3^b7>cq0qyRZ*5m!)$AS)@fLE;3W*OO){m|uM&c*> z;;`&o%e&@jTnk$5WdM=R@_{It~2vY#x`QscVeiE>O z3g2!!G=pw9*NAYGe2>;%YrQvXJEd+r(dv?663Wx?@P5qgYdSsjDe^+ZScfVt5~Powq9<)0x69g>GE6=i43e$gm!k6V(B$%Zd$i@a zj4nNus%ceix8@ZMu1runK_Q>yJwIG!2OKo5U8)Dk&&-7|3`NCPbnKGVag48&+Fw`XCIf)CkK6+F;LZbi_UeqNumb89#f~p|#CW6m(7N%*tdjzgn zd*LXc3u%>56g&zpwy*1r3KY8!!&}%TU@f$ekh;()c3@Yj1HRFPRX^JV-v<3_+EGmb z7*+om*w=?Wk1eZWQ+{{m)y)j97A?kdaXD$Z-D`5bdQMmu8VSAn>@oQYpc_qp7wlI} zhp=Q+)!l=>3ZuYAU>=gZRVoYGh`Iti!^uq@F zGpk>WlaivG7|FXy>eC3vjA$&!;v3domMgNW*!1&W>AkAf*Dc9=7>c3ark|s4sXwV2 zqiv!=VkjMtv(}>ZYjLs)y;#~rT*T3g9Lde zK|j}M8nN8Drk%yamGL=DAy^^amc4Gu*>4NG= z*i)NE-%N$1-o`m;;FB>V3ET2P!P8~@)o0QI#{Tru;4w0vrIs!|%8D((QniZB&_=$R_rUr6Q81wn)*>W@`s{3ux_bP8hWlc>-#^_?Iz)hllk zK3gm8swCCbzfdMJ@cvLcztj=xmMSDSdq|^zpsed}fW)i}%swr=xcyitdt13W=zH2x z!s}z;fhG}Tnn%5rLrHHa-+D^ZV1D~lKw6?b@s)q{Jd9Wr`?TMu_+HoM+^HG;jO8K> zOuR@ft+zPaT(#>^H=jX?pFlDCe`ZQ^OH~0=_I3 zgYVAzO!Np3E`SSWrsu|Xn-O10u{e{wm~xr*I%el_oN!BGK1^V_5_^SRr+B@AEzLIV zN-1WnJl-KKKOx&rb+NtxT?k)L1aw3e@zZ`!q0q<6;7x5Y7NG07?E(0Da9N{eY1ZvD#FAvvP3nIzpR=rbo#clej4 zMuP|6{KYYzoA!D3?C3nBvB(#ziHqe3i__`8B5LcRSePOL9Fp+ELgRSjsb{DGwjDj0 z!Um&HFzzpy3(LJtcb`DP1u`1&MQW^sq} z#|-5=Appz}a@gF(LE4HN9tYw6C6O3#$Pl3S1Yj%6=H^zD&$wE7;;tj}VE<8bmuF-r zf)qd=Uw-D>+$9aq+F5s>ko+=q&2B){etdBsCTA9Z(}9WWf;$kHXlvX2QH6)$C4WF1 zKmYKEOpDlvUrWtYTIIrsqM}QvP0PMw&wTcZN@-dyNRKBBK><)s3g>wtF~H$yV(N0T z6o~$ftyqA5m?XhKuiQ-aHxIkasx6=PzPaFju(Aj9@$tM{o&XoO6swe$f!G4cY?~8=DRa19jjQO( zljqqcX3$DP-;L5IjsdKp!NWWn>={zUUKP8H???wGv%W1vtMKTOTiZ|&znjx;pBP^W zY*Ex%D82~X@O0E+p&K2RCfgu;Qejj%ULFzL|F}1+sK}Z%@|A94fH%PI%llz|p3#se zNkt^N_E2pSW?Jb@303ozP}__i+>tb?(AdRvPCU~w^okc=C!j_GHEmKYrp%n;-O5L-C_*JO^_R zK^~Q!)bd;sPOBGH2cyJ3b7bC=Jk0sfuZUo-e9Zl(BeHboL|OX4K{}AiIAEx&Y4AvZ zI;+%|D3*yXz$Oz!ddd0R3f4&%s7_lWV}%ebzJLCZwpH6Mw>4HeGwbMa$K$JO?f}EU z-t=E(mA$CoJOsW?KE<>#yZcATwf12XVGF3|3ejzMwy!e$Wq)$F(LR)agB%ifdJ1~i5adZeC+*uNM z^3pjEG~;y7Ch;tEF?hc&?W~Gtp&ZjulPg9<$I%0jIrfmU{7Kv6qWmvKvJlM*J$F)K zx)|-?PDA~}mWS`vrflpC{b!f=lgmh!Gs3HA>f&Mtl67XmZq27z12MG>*qVAotuE@B z1;!lwsx$b5SnyM1nbm`7ll@@3NKl`19I)~G9aRlh+6cj zE3z!)T>oZ^&kjQ4>@%}rY;?S44Ut!>342?t#Z?|9k(<2r3|o_&{3}(~mE><6CF>L$ zk3|S&;uRJ^{OdkM^oyxyVaLXJ??FI((FWt%qx1`{b)Etq4!NX zTKA63C)3;9>+a##dM6;r<;N4s*|FM)@87`FdS&<@%Nq9WzZPU7PIn5p3O(}NHa{2W zmAS%}opz&l%yf7B_hMr?6}}U#jl*rQ!N(_^-xHyhFwXUp9fL=kqj<;C^ineql`?Z3 zOUsKg>l0CT4t&mc;PxVVUm9|?X!D=?j>X^{_a>`vB>TB}r4%H|>^peaozoF1Y+1Q- zR|j7ccBLkda*imNW?G|b#mWwGKZr@<@C#u~FDGC%e2?&Bbf{Xg!yHmW?eOS@v&VOF zdaS@7I9y}8*RIexWqHITfD@g%)q50II9G;Npe1DwzxRHeU_w>LEM-7@)b^?1^-9=t zqd}1U>5&}BeqxHmF4(+V<;!3x1k@8q!kP*$Pp6y;{t+47HBd-@bpGW~JL zoJEL<*Zmb!$lL4(-|6F@&^=9WUO!c7ythJ6TO&C_OZQ}pSWNK4nZwTc(k;r<1YEWM zMsEDv6avHz2K`ud`Ny)#pr4B^Bln8<6X^I4%kUrONaDXSM@aPH-?$Mk4;YCX0l{~; z5r_sN0Q~==jUfDx{|+1dU?=`gQ}FzYrr?19|2NzyN-<&*_&9L)oKOV%D6iR+c_QZV zQ|!>@G-|f*)Q_J^(8n-v&(|aWpYWJ|xpD8vzdJ0IROtNV>oc6|B;Qa|FPsv{sRVJ8 zeN7u*yn4lvghh+<>t{L4*U-YA=wo^+nC89tvBOk8QMn4DNz`NTxU=+Ddxw_@@r zD;TgV=n!vh;g~+O2tUIZ+eb4jp`#wAudiPt+0i|v%Hi2rQgy%6?tmOAFEwoprJMF| zN2dZ~gNRALbwKA);XEu#)U&k17dzYceI3VjZHm+_nXvAK)?VomfH&|)X>$mnVRU8ScaaU+A~qsfhY#}a4NyF&uB@}h`)xpf!l|7|Gn z{>NYb^!fh_#Pol1{r}1@@%@!w`pF61u|-HG=?6E&jbxU7%75}icN`Nh5Xm6jF-^ZS zNLW90e#9YprJuTY@*jC1^?%0Q$?nSd%Mt76^*I9p8 z{mD)W3H^><(SUvj5CJN1n5nwCvmOAsB@RHt+}&CKuTbJ&n5!SXu3~Iy4p1?M-?5HA z3IV8@JHcGwrshsGpx+mlS2Q=XHojvh@2Vrf1L8u$XZ(C%etrlqw*U<PI_2Bnn#1Qgod$+6F?nFQ6gbDWI0YWKPa!ikdps&#k)#5Vg0Kn zSb#sPf~?8^LtX9)m$x=^(xbU+w%XmL1k455QqW%t|I57j!y-Sb|K~tZu!h)* z;rSx~kw-8P2o?hZxsh>q;qIF6?uc|PJ}G3l(?#m>NgxC0ciCO~ALqyjKBOM^o!%em z_$2T05dnz(ynl(A-T|=yb%3Ut++AR?a&~rb5(EH{T?;jHurr1_BTdX@3bO~WB2DoZ zYk>ZV-%1!GAz7Fu(npYe^1F**{kTv>LVW;DCvy!e7kd+AZz(&NLw_$klwTC$j#b4p6F{;klzpt2IkjhK*}?;n=qxohE_1@0^X7D1K_hncyU zn*SMpCx;*dH_~FraAz5wJB#!E5$@vd^0>1Y(xP`>dS^K>A2P2WMIr4ZiQEZ_MN*I( z$juA7doTdThY0GVXuo z2LeI3kq-ZNJ#H`rInw_jU{T3^x33uP=3LPjh4!0n}hHLY0GBz-aC|;SNca zlcdq35kkHgkr050Nr(d_rIGCigMknU34Td#KCpxsh#v$J!TR4-?j{sTn5l%7xv8y_ zi#-j1mxosX43Pp$@<{TEA)QG=j8{@zT7nlj4Ty=0iA&r$y_2&s-1&zqaU=T&xnmil Jl(IC|{{Yjx);j Date: Sun, 23 Nov 2025 19:07:56 +0100 Subject: [PATCH 116/136] build: copy the DreamDexed Bank 004_Mirage.pdf to the root of the sdcard --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a633e19b1..ef4e33790 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,7 +77,7 @@ jobs: git clone https://github.com/Banana71/Soundplantage --depth 1 cp -r ./Soundplantage/performance ./Soundplantage/*.pdf ./sdcard/ cp -r ./performance/004_Mirage ./sdcard/performance/ - cp "./performance/DreamDexed Bank 004_Mirage.pdf" ./sdcard/performance/ + cp ./performance/*.pdf ./sdcard/ # Hardware configuration cd hwconfig sh -ex ./customize.sh From 418a1c0b30a851d5500a8f6da50f67564c306bba Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 2 Dec 2025 19:29:37 +0100 Subject: [PATCH 117/136] uimenu: showdirect --- src/uimenu.cpp | 34 ++++++++++++++++++---------------- src/uimenu.h | 1 + 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 3b809873d..179618d32 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -616,8 +616,8 @@ const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = const CUIMenu::TMenuItem CUIMenu::s_StatusMenu[] = { - {"CPU Temp", ShowCPUTemp, 0, 0}, - {"CPU Speed", ShowCPUSpeed, 0, 0}, + {"CPU Temp", ShowCPUTemp, 0, 0, .ShowDirect=true}, + {"CPU Speed", ShowCPUSpeed, 0, 0, .ShowDirect=true}, {0} }; @@ -638,14 +638,10 @@ void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) char info[17]; snprintf(info, sizeof(info), "%d/%d C", pStatus->nCPUTemp.load(), pStatus->nCPUMaxTemp); - const char *pMenuName = - pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] - [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - - pUIMenu->m_pUI->DisplayWrite (pMenuName, - pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, info, - false, false); + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); static TKernelTimerHandle timer = 0; if (timer) CTimer::Get ()->CancelKernelTimer(timer); @@ -669,14 +665,10 @@ void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) char info[17]; snprintf(info, sizeof(info), "%d/%d MHz", pStatus->nCPUClockRate.load() / 1000000, pStatus->nCPUMaxClockRate / 1000000); - const char *pMenuName = - pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] - [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - - pUIMenu->m_pUI->DisplayWrite (pMenuName, - pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, info, - false, false); + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); static TKernelTimerHandle timer = 0; if (timer) CTimer::Get ()->CancelKernelTimer(timer); @@ -803,6 +795,10 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) case MenuEventSelect: // push menu assert (pUIMenu->m_nCurrentMenuDepth < MaxMenuDepth); + + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].ShowDirect) + break; + pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pParentMenu; pUIMenu->m_MenuStackMenu[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pCurrentMenu; pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth] @@ -906,6 +902,12 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) if (pUIMenu->m_pCurrentMenu) // if this is another menu? { + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].ShowDirect) + { + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Handler(pUIMenu, MenuEventUpdate); + return; + } + bool bIsMainMenu = pUIMenu->m_pCurrentMenu == s_MainMenu; bool bIsTGMenu = pUIMenu->m_pCurrentMenu == s_TGMenu; diff --git a/src/uimenu.h b/src/uimenu.h index aff38a188..9192a87dc 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -74,6 +74,7 @@ class CUIMenu TMenuHandler* StepDown; TMenuHandler* StepUp; unsigned Parameter2; + bool ShowDirect; }; typedef std::string TToString (int nValue, int nWidth); From f99a6e790cfb145fd0b5dbcf76e8f8872f4214ef Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 2 Dec 2025 20:10:11 +0100 Subject: [PATCH 118/136] status menu: add Network IP --- src/uimenu.cpp | 31 +++++++++++++++++++++++++++++++ src/uimenu.h | 4 +++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 179618d32..541eaca7f 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -618,6 +618,7 @@ const CUIMenu::TMenuItem CUIMenu::s_StatusMenu[] = { {"CPU Temp", ShowCPUTemp, 0, 0, .ShowDirect=true}, {"CPU Speed", ShowCPUSpeed, 0, 0, .ShowDirect=true}, + {"Net IP", ShowIPAddr, 0, 0, .ShowDirect=true}, {0} }; @@ -675,6 +676,36 @@ void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); } +void CUIMenu::ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CString IPString("-"); + const CIPAddress& IPAddr = pUIMenu->m_pConfig->GetNetworkIPAddress(); + + if (IPAddr.IsSet()) + { + IPAddr.Format(&IPString); + } + + pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + (const char*)IPString, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); + + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); +} + CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), m_pMiniDexed (pMiniDexed), diff --git a/src/uimenu.h b/src/uimenu.h index 9192a87dc..da20b7d7d 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -105,7 +105,9 @@ class CUIMenu static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event); static void ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event); - + static void ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event); + + static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); static std::string GetTGValueString (unsigned nTGParameter, int nValue, int nWidth); static std::string GetFXValueString (unsigned nFXParameter, int nValue, int nWidth); From 1a376d348b6772b738276eb6f3e7ae8d1978cd15 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 29 Nov 2025 11:19:34 +0100 Subject: [PATCH 119/136] Remove network ready display and timer start Removed UI display write and timer start for network readiness. --- src/minidexed.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 1a21db6c1..0dc8e0856 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -2968,14 +2968,6 @@ unsigned CMiniDexed::getModController (unsigned controller, unsigned parameter, } -static void UpdateScreen(TKernelTimerHandle hTimer, void *pParam, void *pContext) -{ - CUserInterface *pUI = static_cast (pContext); - assert (pUI); - - pUI->DisplayChanged (); -} - void CMiniDexed::UpdateNetwork() { if (!m_pNet) { @@ -3018,9 +3010,6 @@ void CMiniDexed::UpdateNetwork() LOGNOTE("FTP daemon not started (NetworkFTPEnabled=0)"); } - m_UI.DisplayWrite (IPString, "", "Network ready", 0, 1); - CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), UpdateScreen, 0, &m_UI); - m_pmDNSPublisher = new CmDNSPublisher (m_pNet); assert (m_pmDNSPublisher); From 9f7f9a18cd28615fd6ad149fa02610038e169734 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 07:09:20 +0100 Subject: [PATCH 120/136] Status: read the actual IP address from the network subsystem not just from the config --- src/minidexed.cpp | 8 ++++++++ src/minidexed.h | 1 + src/uimenu.cpp | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 0dc8e0856..97ed98b8c 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -3193,4 +3193,12 @@ bool CMiniDexed::InitNetwork() } } +const CIPAddress& CMiniDexed::GetNetworkIPAddress() +{ + if (m_pNet) + return *m_pNet->GetConfig()->GetIPAddress(); + else + return m_pConfig->GetNetworkIPAddress(); +} + CStatus *CStatus::s_pThis = 0; diff --git a/src/minidexed.h b/src/minidexed.h index 25273e3b6..5a7002e65 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -287,6 +287,7 @@ class CMiniDexed bool InitNetwork(); void UpdateNetwork(); + const CIPAddress& GetNetworkIPAddress(); private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 541eaca7f..8961b1c99 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -689,7 +689,7 @@ void CUIMenu::ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event) } CString IPString("-"); - const CIPAddress& IPAddr = pUIMenu->m_pConfig->GetNetworkIPAddress(); + const CIPAddress& IPAddr = pUIMenu->m_pMiniDexed->GetNetworkIPAddress(); if (IPAddr.IsSet()) { From 661550db7d5337b8f936cf030fd4aeebae9efff4 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 06:57:48 +0100 Subject: [PATCH 121/136] SetVoiceParameter: reverse the nOP only once --- src/minidexed.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 97ed98b8c..0fa6f1d6b 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1625,6 +1625,11 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne assert (m_pTG[nTG]); assert (nOP <= 6); + if (nOP < 6) + { + nOP = 5 - nOP; // OPs are in reverse order + } + unsigned nTGLink = m_nTGLink[nTG]; for (unsigned i = 0; i < m_nToneGenerators; i++) @@ -1634,8 +1639,6 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne if (nOP < 6) { - nOP = 5 - nOP; // OPs are in reverse order - if (uchOffset == DEXED_OP_ENABLE) { if (uchValue) From 41e7750de9f75b3a119b4843645989e135343340 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 19:14:44 +0100 Subject: [PATCH 122/136] Status: add version --- src/Makefile | 5 +++++ src/uimenu.cpp | 19 +++++++++++++++++++ src/uimenu.h | 1 + 3 files changed, 25 insertions(+) diff --git a/src/Makefile b/src/Makefile index 4cae38b5a..734351c15 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,5 +18,10 @@ EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) OPTIMIZE = -O3 +DATE := $(shell git log -1 --format=%cd --date=format:"%Y%m%d") +COMMIT := $(shell git rev-parse --short HEAD) +VERSION := $(DATE)-$(COMMIT) +DEFINE += -DVERSION=\"$(VERSION)\" + include ./Synth_Dexed.mk include ./Rules.mk diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 8961b1c99..4d48d4830 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -619,6 +619,7 @@ const CUIMenu::TMenuItem CUIMenu::s_StatusMenu[] = {"CPU Temp", ShowCPUTemp, 0, 0, .ShowDirect=true}, {"CPU Speed", ShowCPUSpeed, 0, 0, .ShowDirect=true}, {"Net IP", ShowIPAddr, 0, 0, .ShowDirect=true}, + {"Version", ShowVersion, 0, 0, .ShowDirect=true}, {0} }; @@ -706,6 +707,24 @@ void CUIMenu::ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event) timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); } +void CUIMenu::ShowVersion (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + VERSION, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); +} + CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), m_pMiniDexed (pMiniDexed), diff --git a/src/uimenu.h b/src/uimenu.h index da20b7d7d..7b3b9bc84 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -106,6 +106,7 @@ class CUIMenu static void ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event); static void ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event); static void ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowVersion (CUIMenu *pUIMenu, TMenuEvent Event); static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); From eb8afd2582badc00765eea323372c5c0d2d33669 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 19:31:20 +0100 Subject: [PATCH 123/136] gh build: remove startup version message --- .github/workflows/build.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef4e33790..57f5385dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,10 +28,6 @@ jobs: - name: Create sdcard directory run: mkdir -p ./sdcard/ - - name: Put git hash in startup message - run: | - sed -i "s/Loading.../$(date +%Y%m%d)-$(git rev-parse --short HEAD)/g" src/userinterface.cpp - # Install 64-bit toolchain (aarch64) - name: Install 64-bit toolchain run: | @@ -115,10 +111,6 @@ jobs: - name: Create sdcard directory run: mkdir -p ./sdcard/ - - name: Put git hash in startup message - run: | - sed -i "s/Loading.../${{ env.GIT_INFO }}/g" src/userinterface.cpp - # Install 32-bit toolchain (arm-none-eabi) - name: Install 32-bit toolchain run: | From 6e817f43d529ee49fe870a48312e5baa5ad64610 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 19:35:36 +0100 Subject: [PATCH 124/136] gh build: use commiter date instead of the actual date This is the same what used in the Makefile --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57f5385dd..0d2587907 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: - name: Compute Git Info for Artifact Name id: gitinfo - run: echo "::set-output name=git_info::$(date +%Y-%m-%d)-$(git rev-parse --short HEAD)" + run: echo "::set-output name=git_info::$(git log -1 --format=%cd --date=format:%Y%m%d)-$(git rev-parse --short HEAD)" - name: Get specific commits of git submodules run: sh -ex ./submod.sh @@ -103,7 +103,7 @@ jobs: - uses: actions/checkout@v2 - name: Compute Git Info for Artifact Name - run: echo "GIT_INFO=$(date +%Y-%m-%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + run: echo "GIT_INFO=$(git log -1 --format=%cd --date=format:%Y%m%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV - name: Get specific commits of git submodules run: sh -ex ./submod.sh From b2d2fc88fa0110afb486ae9c022a6c5bc6632d65 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 20:17:45 +0100 Subject: [PATCH 125/136] gh build: use checkout@v6 and pull the PR head instead of the merge commit --- .github/workflows/build.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d2587907..0d20e4e52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,9 @@ jobs: artifact-path: ${{ steps.upload64.outputs.artifact-path }} git_info: ${{ steps.gitinfo.outputs.git_info }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Compute Git Info for Artifact Name id: gitinfo @@ -100,7 +102,9 @@ jobs: outputs: artifact-path: ${{ steps.upload32.outputs.artifact-path }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Compute Git Info for Artifact Name run: echo "GIT_INFO=$(git log -1 --format=%cd --date=format:%Y%m%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV From bc4603fb54cfc05e014a6271212858eff39d9a47 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 20:37:38 +0100 Subject: [PATCH 126/136] Makefile: use shorter date in version --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 734351c15..89b9c8407 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) OPTIMIZE = -O3 -DATE := $(shell git log -1 --format=%cd --date=format:"%Y%m%d") +DATE := $(shell git log -1 --format=%cd --date=format:%y%m%d) COMMIT := $(shell git rev-parse --short HEAD) VERSION := $(DATE)-$(COMMIT) DEFINE += -DVERSION=\"$(VERSION)\" From 9bad05d6b78b1426289cc7b624af6dc57392a210 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 20:37:57 +0100 Subject: [PATCH 127/136] gh build: use shorter date in version --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d20e4e52..7b41ef478 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - name: Compute Git Info for Artifact Name id: gitinfo - run: echo "::set-output name=git_info::$(git log -1 --format=%cd --date=format:%Y%m%d)-$(git rev-parse --short HEAD)" + run: echo "::set-output name=git_info::$(git log -1 --format=%cd --date=format:%y%m%d)-$(git rev-parse --short HEAD)" - name: Get specific commits of git submodules run: sh -ex ./submod.sh @@ -107,7 +107,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Compute Git Info for Artifact Name - run: echo "GIT_INFO=$(git log -1 --format=%cd --date=format:%Y%m%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + run: echo "GIT_INFO=$(git log -1 --format=%cd --date=format:%y%m%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV - name: Get specific commits of git submodules run: sh -ex ./submod.sh From f410dc7b960832e57fd105f83444a2a19efd2204 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Mon, 8 Sep 2025 20:13:11 +0200 Subject: [PATCH 128/136] Add WaitForEvent for Core 1 also to reduce power consumpiton This reduces the power consumption when used in fast=true mode --- src/minidexed.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 0fa6f1d6b..6120b7aa5 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -543,6 +543,7 @@ void CMiniDexed::Run (unsigned nCore) while (m_CoreStatus[nCore] != CoreStatusExit) { ProcessSound (); + WaitForEvent (); } } else // core 2 and 3 From ce91912926ae3781c7c76e5b9a4d94f5984b8a06 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 26 Nov 2024 00:32:58 +0100 Subject: [PATCH 129/136] add MIDI Button actions --- src/config.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++ src/config.h | 28 +++++++++++++++++++ src/minidexed.ini | 13 ++++++++- src/uibuttons.cpp | 21 +++++++++++---- src/uibuttons.h | 12 +++++++++ 5 files changed, 137 insertions(+), 6 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index ec5b36100..24ba2f074 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -179,18 +179,32 @@ void CConfig::Load (void) m_nMIDIButtonCh = m_Properties.GetNumber ("MIDIButtonCh", 0); m_nMIDIButtonNotes = m_Properties.GetNumber ("MIDIButtonNotes", 0); + m_nMIDIButtonPrev = m_Properties.GetNumber ("MIDIButtonPrev", 0); m_nMIDIButtonNext = m_Properties.GetNumber ("MIDIButtonNext", 0); m_nMIDIButtonBack = m_Properties.GetNumber ("MIDIButtonBack", 0); m_nMIDIButtonSelect = m_Properties.GetNumber ("MIDIButtonSelect", 0); m_nMIDIButtonHome = m_Properties.GetNumber ("MIDIButtonHome", 0); + m_MIDIButtonActionPrev = m_Properties.GetString ("MIDIButtonActionPrev", ""); + m_MIDIButtonActionNext = m_Properties.GetString ("MIDIButtonActionNext", ""); + m_MIDIButtonActionBack = m_Properties.GetString ("MIDIButtonActionBack", ""); + m_MIDIButtonActionSelect = m_Properties.GetString ("MIDIButtonActionSelect", ""); + m_MIDIButtonActionHome = m_Properties.GetString ("MIDIButtonActionHome", ""); + m_nMIDIButtonPgmUp = m_Properties.GetNumber ("MIDIButtonPgmUp", 0); m_nMIDIButtonPgmDown = m_Properties.GetNumber ("MIDIButtonPgmDown", 0); m_nMIDIButtonBankUp = m_Properties.GetNumber ("MIDIButtonBankUp", 0); m_nMIDIButtonBankDown = m_Properties.GetNumber ("MIDIButtonBankDown", 0); m_nMIDIButtonTGUp = m_Properties.GetNumber ("MIDIButtonTGUp", 0); m_nMIDIButtonTGDown = m_Properties.GetNumber ("MIDIButtonTGDown", 0); + + m_MIDIButtonActionPgmUp = m_Properties.GetString ("MIDIButtonActionPgmUp", ""); + m_MIDIButtonActionPgmDown = m_Properties.GetString ("MIDIButtonActionPgmDown", ""); + m_MIDIButtonActionBankUp = m_Properties.GetString ("MIDIButtonActionBankUp", ""); + m_MIDIButtonActionBankDown = m_Properties.GetString ("MIDIButtonActionBankDown", ""); + m_MIDIButtonActionTGUp = m_Properties.GetString ("MIDIButtonActionTGUp", ""); + m_MIDIButtonActionTGDown = m_Properties.GetString ("MIDIButtonActionTGDown", ""); m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); @@ -677,6 +691,31 @@ unsigned CConfig::GetMIDIButtonHome (void) const return m_nMIDIButtonHome; } +const char *CConfig::GetMIDIButtonActionPrev (void) const +{ + return m_MIDIButtonActionPrev.c_str(); +} + +const char *CConfig::GetMIDIButtonActionNext (void) const +{ + return m_MIDIButtonActionNext.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBack (void) const +{ + return m_MIDIButtonActionBack.c_str(); +} + +const char *CConfig::GetMIDIButtonActionSelect (void) const +{ + return m_MIDIButtonActionSelect.c_str(); +} + +const char *CConfig::GetMIDIButtonActionHome (void) const +{ + return m_MIDIButtonActionHome.c_str(); +} + unsigned CConfig::GetMIDIButtonPgmUp (void) const { return m_nMIDIButtonPgmUp; @@ -707,6 +746,36 @@ unsigned CConfig::GetMIDIButtonTGDown (void) const return m_nMIDIButtonTGDown; } +const char *CConfig::GetMIDIButtonActionPgmUp (void) const +{ + return m_MIDIButtonActionPgmUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionPgmDown (void) const +{ + return m_MIDIButtonActionPgmDown.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBankUp (void) const +{ + return m_MIDIButtonActionBankUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBankDown (void) const +{ + return m_MIDIButtonActionBankDown.c_str(); +} + +const char *CConfig::GetMIDIButtonActionTGUp (void) const +{ + return m_MIDIButtonActionTGUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionTGDown (void) const +{ + return m_MIDIButtonActionTGDown.c_str(); +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index 03b5a98e1..015740ebf 100644 --- a/src/config.h +++ b/src/config.h @@ -220,12 +220,20 @@ class CConfig // Configuration for MiniDexed // MIDI Button Navigation unsigned GetMIDIButtonCh (void) const; unsigned GetMIDIButtonNotes (void) const; + unsigned GetMIDIButtonPrev (void) const; unsigned GetMIDIButtonNext (void) const; unsigned GetMIDIButtonBack (void) const; unsigned GetMIDIButtonSelect (void) const; unsigned GetMIDIButtonHome (void) const; + // Action type for Midi buttons: "click", "doubleclick", "longpress", "" + const char *GetMIDIButtonActionPrev (void) const; + const char *GetMIDIButtonActionNext (void) const; + const char *GetMIDIButtonActionBack (void) const; + const char *GetMIDIButtonActionSelect (void) const; + const char *GetMIDIButtonActionHome (void) const; + // MIDI Button Program and TG Selection unsigned GetMIDIButtonPgmUp (void) const; unsigned GetMIDIButtonPgmDown (void) const; @@ -234,6 +242,14 @@ class CConfig // Configuration for MiniDexed unsigned GetMIDIButtonTGUp (void) const; unsigned GetMIDIButtonTGDown (void) const; + // Action type for buttons: "click", "doubleclick", "longpress", "" + const char *GetMIDIButtonActionPgmUp (void) const; + const char *GetMIDIButtonActionPgmDown (void) const; + const char *GetMIDIButtonActionBankUp (void) const; + const char *GetMIDIButtonActionBankDown (void) const; + const char *GetMIDIButtonActionTGUp (void) const; + const char *GetMIDIButtonActionTGDown (void) const; + // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions bool GetEncoderEnabled (void) const; @@ -355,6 +371,18 @@ class CConfig // Configuration for MiniDexed std::string m_ButtonActionTGUp; std::string m_ButtonActionTGDown; + std::string m_MIDIButtonActionPrev; + std::string m_MIDIButtonActionNext; + std::string m_MIDIButtonActionBack; + std::string m_MIDIButtonActionSelect; + std::string m_MIDIButtonActionHome; + std::string m_MIDIButtonActionPgmUp; + std::string m_MIDIButtonActionPgmDown; + std::string m_MIDIButtonActionBankUp; + std::string m_MIDIButtonActionBankDown; + std::string m_MIDIButtonActionTGUp; + std::string m_MIDIButtonActionTGDown; + unsigned m_nDoubleClickTimeout; unsigned m_nLongPressTimeout; diff --git a/src/minidexed.ini b/src/minidexed.ini index fd5c99e65..26d60101e 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -122,7 +122,7 @@ LongPressTimeout=400 # MIDI Button Navigation # Specify MIDI CC to act as a button (0 = ununsed, so don't use CC 0) -# NB: Off < 64 < ON +# NB: Off < 64 < ON for click / doubleclick / longpress actions # CC channel: 0=OFF; 1-16 MIDI Ch; >16 Omni # If MIDIButtonNotes>0 then treat MIDIButton numbers as MIDI # Note numbers, triggered with NoteOn/NoteOff, not CC numbers. @@ -130,20 +130,31 @@ MIDIButtonCh=17 MIDIButtonNotes=0 # Arrow left MIDIButtonPrev=46 +MIDIButtonActionPrev=click # Arrow right MIDIButtonNext=47 +MIDIButtonActionNext=click # Arrow up MIDIButtonBack=48 +MIDIButtonActionBack=click # Arrow down MIDIButtonSelect=49 +MIDIButtonActionSelect=click # Home button MIDIButtonHome=50 +MIDIButtonActionHome=click MIDIButtonPgmUp=51 +MIDIButtonActionPgmUp=click MIDIButtonPgmDown=52 +MIDIButtonActionPgmDown=click MIDIButtonBankUp=53 +MIDIButtonActionBankUp=click MIDIButtonBankDown=54 +MIDIButtonActionBankDown=click MIDIButtonTGUp=55 +MIDIButtonActionTGUp=click MIDIButtonTGDown=56 +MIDIButtonActionTGDown=click # KY-040 Rotary Encoder EncoderEnabled=1 diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index de831cae5..07d1128e6 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -300,17 +300,28 @@ boolean CUIButtons::Initialize (void) m_TGDownAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionTGDown ()); m_notesMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNotes ()); m_prevMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPrev ()); + m_prevMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPrev ()); m_nextMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNext ()); + m_nextMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionNext ()); m_backMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBack ()); + m_backMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBack ()); m_selectMidi = ccToMidiPin( m_pConfig->GetMIDIButtonSelect ()); + m_selectMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionSelect ()); m_homeMidi = ccToMidiPin( m_pConfig->GetMIDIButtonHome ()); + m_homeMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionHome ()); m_pgmUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmUp ()); + m_pgmUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPgmUp ()); m_pgmDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmDown ()); + m_pgmDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPgmDown ()); m_BankUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankUp ()); + m_BankUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBankUp ()); m_BankDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankDown ()); + m_BankDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBankDown ()); m_TGUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGUp ()); + m_TGUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionTGUp ()); m_TGDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGDown ()); - + m_TGDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionTGDown ()); + // First sanity check and convert the timeouts: // Internally values are in tenths of a millisecond, but config values // are in milliseconds @@ -329,7 +340,7 @@ boolean CUIButtons::Initialize (void) // Each normal button can be assigned up to 3 actions: click, doubleclick and // longpress. We may not initialise all of the buttons. - // MIDI buttons only support a single click. + // MIDI Buttons can be assigned to click, doubleclick, longpress unsigned pins[MAX_BUTTONS] = { m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, m_pgmUpPin, m_pgmDownPin, m_BankUpPin, m_BankDownPin, m_TGUpPin, m_TGDownPin, m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi, m_pgmUpMidi, m_pgmDownMidi, m_BankUpMidi, m_BankDownMidi, m_TGUpMidi, m_TGDownMidi @@ -338,9 +349,9 @@ boolean CUIButtons::Initialize (void) // Normal buttons m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction, m_pgmUpAction, m_pgmDownAction, m_BankUpAction, m_BankDownAction, m_TGUpAction, m_TGDownAction, - // MIDI Buttons only support a single click (at present) - CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, - CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick + // MIDI buttons + m_prevMidiAction, m_nextMidiAction, m_backMidiAction, m_selectMidiAction, m_homeMidiAction, + m_pgmUpMidiAction, m_pgmDownMidiAction, m_BankUpMidiAction, m_BankDownMidiAction, m_TGUpMidiAction, m_TGDownMidiAction, }; CUIButton::BtnEvent events[MAX_BUTTONS] = { // Normal buttons diff --git a/src/uibuttons.h b/src/uibuttons.h index 278244307..bbe1fa9cf 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -165,18 +165,30 @@ class CUIButtons // MIDI button configuration unsigned m_notesMidi; + unsigned m_prevMidi; + CUIButton::BtnTrigger m_prevMidiAction; unsigned m_nextMidi; + CUIButton::BtnTrigger m_nextMidiAction; unsigned m_backMidi; + CUIButton::BtnTrigger m_backMidiAction; unsigned m_selectMidi; + CUIButton::BtnTrigger m_selectMidiAction; unsigned m_homeMidi; + CUIButton::BtnTrigger m_homeMidiAction; unsigned m_pgmUpMidi; + CUIButton::BtnTrigger m_pgmUpMidiAction; unsigned m_pgmDownMidi; + CUIButton::BtnTrigger m_pgmDownMidiAction; unsigned m_BankUpMidi; + CUIButton::BtnTrigger m_BankUpMidiAction; unsigned m_BankDownMidi; + CUIButton::BtnTrigger m_BankDownMidiAction; unsigned m_TGUpMidi; + CUIButton::BtnTrigger m_TGUpMidiAction; unsigned m_TGDownMidi; + CUIButton::BtnTrigger m_TGDownMidiAction; BtnEventHandler *m_eventHandler; void *m_eventParam; From 97804700bdcb0b7ffa12155c6764208df9d7a684 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 04:20:22 +0100 Subject: [PATCH 130/136] CMIDIPin: convert the MIDI value to LOW/HIGH in CUIButton simplify the CMIDIPin in order to easier to handle dec/inc values --- src/midipin.cpp | 14 ++------------ src/midipin.h | 10 ++++------ src/uibuttons.cpp | 3 ++- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/midipin.cpp b/src/midipin.cpp index 0c41dea07..4b89e7899 100644 --- a/src/midipin.cpp +++ b/src/midipin.cpp @@ -24,7 +24,7 @@ LOGMODULE ("midipin"); CMIDIPin::CMIDIPin (unsigned nPinNumber) : m_nPinNumber (nPinNumber), - m_nValue (HIGH) + m_nValue (0) { } @@ -39,16 +39,6 @@ unsigned CMIDIPin::Read (void) void CMIDIPin::Write (unsigned nValue) { - // Takes values in the MIDI controller range 0 to 127 - // and OFF < 64 < ON. - // Simulates a PULLUP IO pin, so "true" is LOW (0) - if (nValue >= 64) { - // "on" - m_nValue = LOW; - } else { - // "off" - m_nValue = HIGH; - } - return; + m_nValue = nValue; } diff --git a/src/midipin.h b/src/midipin.h index 7fa3f1dbb..1b1dc8770 100644 --- a/src/midipin.h +++ b/src/midipin.h @@ -32,19 +32,17 @@ #define MidiPinToCC(p) (((p)>=MIDI_PINS)?((p)-MIDI_PINS):0) #define isMidiPin(p) (((p)>=MIDI_PINS)?1:0) +#define MIDIPIN_CENTER 64 + class CMIDIPin { public: CMIDIPin (unsigned nPinNumber); // pinNumber = ccToMidiPin (MIDI CC number) ~CMIDIPin (void); - // Will return MP_HIGH or MP_LOW. - // Should be treated as a PULLED UP IO pin - // i.e. treated as "active low" (LOW) when pressed. + // Will return the value written to unsigned Read (void); - - // MIDI CC values >=64 will set the MIDI pin to LOW ("on") - // MIDI CC values <= 63 will set the MIDI pin to HIGH ("off") + void Write (unsigned nValue); private: diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 07d1128e6..5254f1a0e 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -117,7 +117,8 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) // Always return "not pressed" if not configured return BtnTriggerNone; } - value = m_midipin->Read(); + // Simulates a PULLUP IO pin, so "true" is LOW (0) + value = m_midipin->Read() < MIDIPIN_CENTER ? HIGH : LOW; } else { From a8b482950142eb6f5d6b6bb180a09ac2f038961d Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 26 Nov 2024 00:43:30 +0100 Subject: [PATCH 131/136] CUIBUttons: add dec and inc trigger modes --- src/config.h | 4 ++-- src/minidexed.ini | 1 + src/uibuttons.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++--- src/uibuttons.h | 12 +++++++++-- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/config.h b/src/config.h index 015740ebf..5a254d97f 100644 --- a/src/config.h +++ b/src/config.h @@ -227,7 +227,7 @@ class CConfig // Configuration for MiniDexed unsigned GetMIDIButtonSelect (void) const; unsigned GetMIDIButtonHome (void) const; - // Action type for Midi buttons: "click", "doubleclick", "longpress", "" + // Action type for Midi buttons: "click", "doubleclick", "longpress", "dec", "inc", "" const char *GetMIDIButtonActionPrev (void) const; const char *GetMIDIButtonActionNext (void) const; const char *GetMIDIButtonActionBack (void) const; @@ -242,7 +242,7 @@ class CConfig // Configuration for MiniDexed unsigned GetMIDIButtonTGUp (void) const; unsigned GetMIDIButtonTGDown (void) const; - // Action type for buttons: "click", "doubleclick", "longpress", "" + // Action type for buttons: "click", "doubleclick", "longpress", "dec", "inc", "" const char *GetMIDIButtonActionPgmUp (void) const; const char *GetMIDIButtonActionPgmDown (void) const; const char *GetMIDIButtonActionBankUp (void) const; diff --git a/src/minidexed.ini b/src/minidexed.ini index 26d60101e..6f012dff3 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -123,6 +123,7 @@ LongPressTimeout=400 # MIDI Button Navigation # Specify MIDI CC to act as a button (0 = ununsed, so don't use CC 0) # NB: Off < 64 < ON for click / doubleclick / longpress actions +# DEC < 64 < INC for dec / inc actions # CC channel: 0=OFF; 1-16 MIDI Ch; >16 Omni # If MIDIButtonNotes>0 then treat MIDIButton numbers as MIDI # Note numbers, triggered with NoteOn/NoteOff, not CC numbers. diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 5254f1a0e..7e19ba78d 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -37,6 +37,8 @@ CUIButton::CUIButton (void) m_clickEvent(BtnEventNone), m_doubleClickEvent(BtnEventNone), m_longPressEvent(BtnEventNone), + m_decEvent(BtnEventNone), + m_incEvent(BtnEventNone), m_doubleClickTimeout(0), m_longPressTimeout(0) { @@ -102,6 +104,16 @@ void CUIButton::setLongPressEvent(BtnEvent longPressEvent) m_longPressEvent = longPressEvent; } +void CUIButton::setDecEvent(BtnEvent decEvent) +{ + m_decEvent = decEvent; +} + +void CUIButton::setIncEvent(BtnEvent incEvent) +{ + m_incEvent = incEvent; +} + unsigned CUIButton::getPinNumber(void) { return m_pinNumber; @@ -110,6 +122,7 @@ unsigned CUIButton::getPinNumber(void) CUIButton::BtnTrigger CUIButton::ReadTrigger (void) { unsigned value; + if (isMidiPin(m_pinNumber)) { if (!m_midipin) @@ -117,8 +130,23 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) // Always return "not pressed" if not configured return BtnTriggerNone; } - // Simulates a PULLUP IO pin, so "true" is LOW (0) - value = m_midipin->Read() < MIDIPIN_CENTER ? HIGH : LOW; + + if (m_decEvent || m_incEvent) + { + value = m_midipin->Read(); + + if (value == MIDIPIN_CENTER) + return BtnTriggerNone; + + // reset value to trigger only once + m_midipin->Write(MIDIPIN_CENTER); + return value < MIDIPIN_CENTER ? BtnTriggerDec : BtnTriggerInc; + } + else + { + // Simulates a PULLUP IO pin, so "true" is LOW (0) + value = m_midipin->Read() < MIDIPIN_CENTER ? HIGH : LOW; + } } else { @@ -232,6 +260,12 @@ CUIButton::BtnEvent CUIButton::Read (void) { else if (trigger == BtnTriggerLongPress) { return m_longPressEvent; } + else if (trigger == BtnTriggerDec) { + return m_decEvent; + } + else if (trigger == BtnTriggerInc) { + return m_incEvent; + } assert (trigger == BtnTriggerNone); @@ -252,6 +286,12 @@ CUIButton::BtnTrigger CUIButton::triggerTypeFromString(const char* triggerString else if (strcmp(triggerString, "longpress") == 0) { return BtnTriggerLongPress; } + else if (strcmp(triggerString, "dec") == 0) { + return BtnTriggerDec; + } + else if (strcmp(triggerString, "inc") == 0) { + return BtnTriggerInc; + } LOGERR("Invalid action: %s", triggerString); @@ -341,7 +381,7 @@ boolean CUIButtons::Initialize (void) // Each normal button can be assigned up to 3 actions: click, doubleclick and // longpress. We may not initialise all of the buttons. - // MIDI Buttons can be assigned to click, doubleclick, longpress + // MIDI buttons can be assigned to click, doubleclick, longpress, dec, inc unsigned pins[MAX_BUTTONS] = { m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, m_pgmUpPin, m_pgmDownPin, m_BankUpPin, m_BankDownPin, m_TGUpPin, m_TGDownPin, m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi, m_pgmUpMidi, m_pgmDownMidi, m_BankUpMidi, m_BankDownMidi, m_TGUpMidi, m_TGDownMidi @@ -452,6 +492,12 @@ void CUIButtons::bindButton(unsigned pinNumber, CUIButton::BtnTrigger trigger, C else if (trigger == CUIButton::BtnTriggerLongPress) { m_buttons[i].setLongPressEvent(event); } + else if (trigger == CUIButton::BtnTriggerDec) { + m_buttons[i].setDecEvent(event); + } + else if (trigger == CUIButton::BtnTriggerInc) { + m_buttons[i].setIncEvent(event); + } else { assert (trigger == CUIButton::BtnTriggerNone); } diff --git a/src/uibuttons.h b/src/uibuttons.h index bbe1fa9cf..4f05ee5bc 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -41,7 +41,9 @@ class CUIButton BtnTriggerNone = 0, BtnTriggerClick = 1, BtnTriggerDoubleClick = 2, - BtnTriggerLongPress = 3 + BtnTriggerLongPress = 3, + BtnTriggerDec = 4, + BtnTriggerInc = 5, }; enum BtnEvent @@ -70,6 +72,8 @@ class CUIButton void setClickEvent(BtnEvent clickEvent); void setDoubleClickEvent(BtnEvent doubleClickEvent); void setLongPressEvent(BtnEvent longPressEvent); + void setDecEvent(BtnEvent decEvent); + void setIncEvent(BtnEvent incEvent); unsigned getPinNumber(void); @@ -100,7 +104,11 @@ class CUIButton BtnEvent m_doubleClickEvent; // Event to fire on long press BtnEvent m_longPressEvent; - + // Event to fire on dec + BtnEvent m_decEvent; + // Event to fire on inc + BtnEvent m_incEvent; + // Timeout for double click in tenths of a millisecond unsigned m_doubleClickTimeout; // Timeout for long press in tenths of a millisecond From f2440aca0850c80da4fcccbf34a428a258e1567b Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 15:20:33 +0100 Subject: [PATCH 132/136] CUIButtons: remove the unused timeout members --- src/uibuttons.cpp | 7 ++----- src/uibuttons.h | 5 ----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 7e19ba78d..ebf41cc2a 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -314,9 +314,6 @@ boolean CUIButtons::Initialize (void) { assert (m_pConfig); - // Read the button configuration - m_doubleClickTimeout = m_pConfig->GetDoubleClickTimeout (); - m_longPressTimeout = m_pConfig->GetLongPressTimeout (); m_prevPin = m_pConfig->GetButtonPinPrev (); m_prevAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionPrev ()); m_nextPin = m_pConfig->GetButtonPinNext (); @@ -366,8 +363,8 @@ boolean CUIButtons::Initialize (void) // First sanity check and convert the timeouts: // Internally values are in tenths of a millisecond, but config values // are in milliseconds - unsigned doubleClickTimeout = m_doubleClickTimeout * 10; - unsigned longPressTimeout = m_longPressTimeout * 10; + unsigned doubleClickTimeout = m_pConfig->GetDoubleClickTimeout () * 10; + unsigned longPressTimeout = m_pConfig->GetLongPressTimeout () * 10; if (longPressTimeout < doubleClickTimeout) { // This is invalid - long press must be longest timeout diff --git a/src/uibuttons.h b/src/uibuttons.h index 4f05ee5bc..db0529f03 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -140,11 +140,6 @@ class CUIButtons // Array of normal GPIO buttons and "MIDI buttons" CUIButton m_buttons[MAX_BUTTONS]; - // Timeout for double click in tenths of a millisecond - unsigned m_doubleClickTimeout; - // Timeout for long press in tenths of a millisecond - unsigned m_longPressTimeout; - // Configuration for buttons unsigned m_prevPin; CUIButton::BtnTrigger m_prevAction; From 71c4c5d33e810abd4fd147e88f707b1fa6f00c00 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 15:37:38 +0100 Subject: [PATCH 133/136] CUIButtons: add debounce time for Relative MIDI messages It's needed for MPK MINI mk3 --- src/config.cpp | 6 ++++++ src/config.h | 2 ++ src/minidexed.ini | 4 ++++ src/uibuttons.cpp | 24 +++++++++++++++--------- src/uibuttons.h | 4 +++- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 24ba2f074..b6492e345 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -162,6 +162,7 @@ void CConfig::Load (void) m_nDoubleClickTimeout = m_Properties.GetNumber ("DoubleClickTimeout", 400); m_nLongPressTimeout = m_Properties.GetNumber ("LongPressTimeout", 600); + m_nMIDIRelativeDebounceTime = m_Properties.GetNumber ("MIDIRelativeDebounceTime", 0); m_nButtonPinPgmUp = m_Properties.GetNumber ("ButtonPinPgmUp", 0); m_nButtonPinPgmDown = m_Properties.GetNumber ("ButtonPinPgmDown", 0); @@ -596,6 +597,11 @@ unsigned CConfig::GetLongPressTimeout (void) const return m_nLongPressTimeout; } +unsigned CConfig::GetMIDIRelativeDebounceTime(void) const +{ + return m_nMIDIRelativeDebounceTime; +} + unsigned CConfig::GetButtonPinPgmUp (void) const { return m_nButtonPinPgmUp; diff --git a/src/config.h b/src/config.h index 5a254d97f..83d104775 100644 --- a/src/config.h +++ b/src/config.h @@ -199,6 +199,7 @@ class CConfig // Configuration for MiniDexed // Timeouts for button events in milliseconds unsigned GetDoubleClickTimeout (void) const; unsigned GetLongPressTimeout (void) const; + unsigned GetMIDIRelativeDebounceTime (void) const; // GPIO Button Program and TG Selection // GPIO pin numbers are chip numbers, not header positions @@ -385,6 +386,7 @@ class CConfig // Configuration for MiniDexed unsigned m_nDoubleClickTimeout; unsigned m_nLongPressTimeout; + unsigned m_nMIDIRelativeDebounceTime; unsigned m_nMIDIButtonCh; unsigned m_nMIDIButtonNotes; diff --git a/src/minidexed.ini b/src/minidexed.ini index 6f012dff3..0c1b9e870 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -157,6 +157,10 @@ MIDIButtonActionTGUp=click MIDIButtonTGDown=56 MIDIButtonActionTGDown=click +# Debounce time for dec / inc MIDI messages +# Can be adjusted if the controller sends dec / inc messages too quickly. +MIDIRelativeDebounceTime=0 + # KY-040 Rotary Encoder EncoderEnabled=1 EncoderPinClock=10 diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index ebf41cc2a..95a708f5b 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -40,7 +40,8 @@ CUIButton::CUIButton (void) m_decEvent(BtnEventNone), m_incEvent(BtnEventNone), m_doubleClickTimeout(0), - m_longPressTimeout(0) + m_longPressTimeout(0), + m_MIDIRelativeDebounceTime(0) { } @@ -62,7 +63,7 @@ void CUIButton::reset (void) m_numClicks = 0; } -boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout) +boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout, unsigned MIDIRelativeDebounceTime) { assert (!m_pin); assert(longPressTimeout >= doubleClickTimeout); @@ -70,6 +71,7 @@ boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, m_pinNumber = pinNumber; m_doubleClickTimeout = doubleClickTimeout; m_longPressTimeout = longPressTimeout; + m_MIDIRelativeDebounceTime = MIDIRelativeDebounceTime; // Initialise timing values m_timer = m_longPressTimeout; @@ -135,11 +137,14 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) { value = m_midipin->Read(); - if (value == MIDIPIN_CENTER) - return BtnTriggerNone; - // reset value to trigger only once m_midipin->Write(MIDIPIN_CENTER); + m_debounceTimer++; + + if (value == MIDIPIN_CENTER || m_debounceTimer < m_MIDIRelativeDebounceTime) + return BtnTriggerNone; + + m_debounceTimer = 0; return value < MIDIPIN_CENTER ? BtnTriggerDec : BtnTriggerInc; } else @@ -365,12 +370,13 @@ boolean CUIButtons::Initialize (void) // are in milliseconds unsigned doubleClickTimeout = m_pConfig->GetDoubleClickTimeout () * 10; unsigned longPressTimeout = m_pConfig->GetLongPressTimeout () * 10; + unsigned MIDIRelativeDebounceTime = m_pConfig->GetMIDIRelativeDebounceTime () * 10; if (longPressTimeout < doubleClickTimeout) { // This is invalid - long press must be longest timeout LOGERR("LongPressTimeout (%u) should not be shorter than DoubleClickTimeout (%u)", - m_longPressTimeout, - m_doubleClickTimeout); + longPressTimeout / 10, + doubleClickTimeout / 10); // Just make long press as long as double click longPressTimeout = doubleClickTimeout; @@ -436,7 +442,7 @@ boolean CUIButtons::Initialize (void) } else if (m_buttons[j].getPinNumber() == 0) { // This is un-initialised so can be assigned - m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout); + m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout, MIDIRelativeDebounceTime); break; } } @@ -455,7 +461,7 @@ boolean CUIButtons::Initialize (void) if (m_buttons[j].getPinNumber() == 0) { // This is un-initialised so can be assigned // doubleClickTimeout and longPressTimeout are ignored for MIDI buttons at present - m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout); + m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout, MIDIRelativeDebounceTime); break; } } diff --git a/src/uibuttons.h b/src/uibuttons.h index db0529f03..0621e3092 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -67,7 +67,7 @@ class CUIButton ~CUIButton (void); void reset (void); - boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout); + boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout, unsigned MIDIRelativeDebounceTime); void setClickEvent(BtnEvent clickEvent); void setDoubleClickEvent(BtnEvent doubleClickEvent); @@ -113,6 +113,8 @@ class CUIButton unsigned m_doubleClickTimeout; // Timeout for long press in tenths of a millisecond unsigned m_longPressTimeout; + // Debounce time for MIDI Relative messages in tenths of a millisecond + unsigned m_MIDIRelativeDebounceTime; }; class CUIButtons From 8632cdeb3dc4d87fd2f6311e77a55b3807641279 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Wed, 3 Dec 2025 16:14:01 +0100 Subject: [PATCH 134/136] README: add relative mode encoders --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 97ad4368d..b0acb0a7a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with the following additional features: - [x] Configurable default screen +- [x] Support for MIDI controller encoders with relative mode - [x] Noiseless performance and volume change - [x] Configurable TG compressors - [x] Master Compressor From c2dd6c61156ca78b0b52cb1d26b4765df5a97af8 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 10 Dec 2024 04:02:58 +0100 Subject: [PATCH 135/136] Add TGParameterEnabled --- src/mididevice.cpp | 8 ++++++++ src/minidexed.cpp | 18 +++++++++++++++++- src/minidexed.h | 10 +++++----- src/uimenu.cpp | 2 ++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 748d515b8..7f141db86 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -335,6 +335,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) { uint8_t ucSysExChannel = (pMessage[2] & 0x0F); for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) { + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, nTG) == 0) + continue; + if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode) { LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG); @@ -456,6 +460,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } else { for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators() && !bSystemCCHandled; nTG++) { + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, nTG) == 0) + continue; + if ( m_ChannelMap[nTG] == ucChannel || m_ChannelMap[nTG] == OmniMode) { switch (ucType) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 6120b7aa5..a8b52b3f8 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -146,6 +146,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nEQLowMidFreq[i] = 24; m_nEQMidHighFreq[i] = 44; + m_bEnabled[i] = 1; + // Active the required number of active TGs if (i= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); + + m_bEnabled[nTG] = enabled != 0; + + m_UI.ParameterChanged (); +} + void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG) { range = constrain (range, 0, 12); @@ -2719,6 +2734,7 @@ void CMiniDexed::LoadPerformanceParameters(void) setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); setTGLink(m_PerformanceConfig.GetTGLink(nTG), nTG); + setEnabled(1, nTG); SetFX1Send (m_PerformanceConfig.GetFX1Send (nTG), nTG); SetFX2Send (m_PerformanceConfig.GetFX2Send (nTG), nTG); diff --git a/src/minidexed.h b/src/minidexed.h index 5a7002e65..a34c5d9b9 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -123,10 +123,9 @@ class CMiniDexed void SetEQGain (int nValue, unsigned nTG); void SetEQLowMidFreq (unsigned nValue, unsigned nTG); void SetEQMidHighFreq (unsigned nValue, unsigned nTG); - void setMonoMode(uint8_t mono, uint8_t nTG); - void setTGLink(uint8_t nTGLink, uint8_t nTG); + void setEnabled(uint8_t enabled, uint8_t nTG); void setPitchbendRange(uint8_t range, uint8_t nTG); void setPitchbendStep(uint8_t step, uint8_t nTG); @@ -231,7 +230,8 @@ class CMiniDexed TGParameterNoteShift, TGParameterMonoMode, TGParameterTGLink, - + TGParameterEnabled, + TGParameterMWRange, TGParameterMWPitch, TGParameterMWAmplitude, @@ -336,9 +336,9 @@ class CMiniDexed unsigned m_nPortamentoGlissando[CConfig::AllToneGenerators]; unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; bool m_bMonoMode[CConfig::AllToneGenerators]; - unsigned m_nTGLink[CConfig::AllToneGenerators]; - + bool m_bEnabled[CConfig::AllToneGenerators]; + unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; unsigned m_nFootControlRange[CConfig::AllToneGenerators]; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 4d48d4830..a194c39c6 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -90,6 +90,7 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = {"Note Limit", MenuHandler, s_EditNoteLimitMenu}, {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, {"TG-Link", EditTGParameter, 0, CMiniDexed::TGParameterTGLink}, + {"Enabled", EditTGParameter, 0, CMiniDexed::TGParameterEnabled}, {"Modulation", MenuHandler, s_ModulationMenu}, {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, {"EQ", MenuHandler, s_EQMenu}, @@ -481,6 +482,7 @@ CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = {-24, 24, 1, ToMIDINoteShift}, // TGParameterNoteShift {0, 1, 1, ToPolyMono}, // TGParameterMonoMode {0, 4, 1, ToTGLinkName}, // TGParameterTGLink + {0, 1, 1, ToOnOff}, // TGParameterEnabled {0, 99, 1}, //MW Range {0, 1, 1, ToOnOff}, //MW Pitch {0, 1, 1, ToOnOff}, //MW Amp From b00e97e8d0ccf9f37f9c086bccfaca993b522272 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 5 Nov 2024 16:51:23 +0100 Subject: [PATCH 136/136] add DAW Controller support for various Arturia controllers MiniLab 3 Keylab Essential KeyLab Essential mk3 KeyLab mkII based on https://github.com/PrzemekBarski/arturia-keylab-essential-mk3-programming-guide Tested on a Arturia MiniLab 3 and KeyLab mkII Keylab Essential and Keylab Essential mk3 is not tested --- README.md | 167 +++ src/Makefile | 3 +- src/common.h | 8 + src/config.cpp | 9 +- src/config.h | 4 + src/dawcontroller.cpp | 2436 +++++++++++++++++++++++++++++++++++++++++ src/dawcontroller.h | 54 + src/mididevice.cpp | 202 +++- src/mididevice.h | 45 + src/midikeyboard.cpp | 59 +- src/midikeyboard.h | 15 + src/minidexed.cpp | 28 + src/minidexed.h | 6 + src/minidexed.ini | 3 + src/uimenu.cpp | 294 +++-- src/uimenu.h | 41 +- src/userinterface.cpp | 11 + src/userinterface.h | 4 + 18 files changed, 3239 insertions(+), 150 deletions(-) create mode 100644 src/dawcontroller.cpp create mode 100644 src/dawcontroller.h diff --git a/README.md b/README.md index b0acb0a7a..5d4909e1c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,173 @@ DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with th - [ ] Overlay Menu for easier parameter changes - [ ] MIDI Controller DAW integration +# DreamDexed Arturia fork + +This is a fork of DreamDexed that integrates better with Arturia keyboards. + +Maybe someday it will be part of the DreamDexed + +## Enabling + +This feature can be enabled in the minidexed.ini with: +``` +DAWControllerEnabled=1 +``` + +## Features + +### Controller Display, Main Encoder +The controller display in DAW mode shows the DreamDexed menu. + +With the main encoder you can navigate in the menu. + +The Home is the shift+Main click + +Supported: +- MiniLab 3 (tested) +- KeyLab mkII (tested) +- Keylab Essential +- Keylab Essential 3 + +### MiniLab 3 features: + +#### Encoders + +By holding down shift will bring up an overlay menu, where you can see and adjust what the encoders do. + +You can use the main encoder to select the current encoding page. + +Short pressing the shift will show the actual values. + +Holding down the shift will goes back to the normal menu. + +This overlay menu is context-aware, it is different if you are in the effect menu, or in a TG menu. + +If you are in a TG menu, it only affects the selected TG. + +If you are in the main menu, it affects the TGs on the first TG's channel. + +- Main Overlay 1 (default) + - Cutoff, Resonance, FX1Send, FX2Send + - PortamentoTime, Program, Volume, MasterVolume + - Faders: ChG 1 Vol, ChG 2 Vol, ChG 3 Vol, ChG 4 Vol + +- Effect Overlay 1 + - MasterEQLow, MasterEQMid, MasterEQHigh, MasterEQGain + - MasterEQLowMidFreq, MasterEQMidHighFreq, None, None + - Faders: MasterEQLow, MasterEQMid, MasterEQHigh, MasterEQGain + +- Effect Overlay 2 + - MasterCREnable, MasterCRPreGain, MasterCRAttack, MasterCRRelease + - MasterCRThresh, MasterCRRatio, MasterCRHPFilter, None + - Faders: MasterCRPreGain, MasterCRAttack, MasterCRRelease, MasterCRThresh + +- Main Overlay 2 + - Pan1, Pan2, Pan3, Pan4 + - Det1, Det2, Det3, Det4 + - Faders: TG1 Vol, TG2 Vol, TG3 Vol, TG4 Vol + +- Main Overlay 3 + - Pan5, Pan6, Pan7, Pan8 + - Det5, Det6, Det7, Det8 + - Faders: TG5 Vol, TG6 Vol, TG7 Vol, TG8 Vol + +- TG Overlay 1 + - Cutoff, Resonance, FX1Send, FX2Send + - MasterTune, PortamentoTime, Volume, Pan + - Faders: Cutoff, FX1Send, FX2Send, Volume + +- TG Overlay 2 + - MIDIChannel, Program, None, PitchBendRange + - PortamentoGlissando, MonoMode, None, PitchBendStep + +- TG Overlay 3 + - TGEQLow, TGEQMid, TGEQHigh, TGEQGain + - TGEQLowMidFreq, TGEQMidHighFreq, None, None + - Faders: TGEQLow, TGEQMid, TGEQHigh, TGEQGain + +- TG Overlay 4 + - CompressorEnable, CompressorPreGain, CompressorMakeupGain, None + - CompressorAttack, CompressorRelease, CompressorThresh, CompressorRatio + - Faders: CompressorPreGain, CompressorAttack, CompressorRelease, CompressorThresh + +- TG Overlay 5 + - MWRange, MWPitch, FCRange, FCPitch + - MWEGBias, MWAmplitude, FCEGBias, FCAmplitude + +- TG Overlay 6 + - BCRange, BCPitch, ATRange, ATPitch + - BCEGBias, BCAmplitude, ATEGBias, ATAmplitude + +- Voice Overlay 1 + - ALGORITHM, FEEDBACK, TRANSPOSE, None, + - None, None, None, None + +- Voice Overlay 2 + - PITCH_EG_R1, PITCH_EG_R2, PITCH_EG_R3, PITCH_EG_R4 + - PITCH_EG_L1, PITCH_EG_L2, PITCH_EG_L3, PITCH_EG_L4 + - Faders: PITCH_EG_L1, PITCH_EG_L2, PITCH_EG_L3, PITCH_EG_L4 + +- Voice Overlay 3 + - OSC_KEY_SYNC, LFO_SPEED, LFO_DELAY, LFO_PITCH_MOD_DEP + - LFO_SYNC, LFO_WAVE, LFO_PITCH_MOD_SENS, LFO_AMP_MOD_DEP + +- OP Overlay 1 + - OP_OUTPUT_LEV, OP_FREQ_COARSE, OP_FREQ_FINE, OP_OSC_DETUNE, + - OP_OSC_MODE, OP_ENABLE, None, None + +- OP Overlay 2 + - OP_EG_R1, OP_EG_R2, P_EG_R3, OP_EG_R4 + - OP_EG_L1, OP_EG_L2, OP_EG_L3, OP_EG_L4, + - Faders: OP_EG_L1, OP_EG_L2, OP_EG_L3, OP_EG_L4, + +- OP Overlay 3 + - OP_LEV_SCL_BRK_PT, OP_SCL_LEFT_DEPTH, OP_SCL_RGHT_DEPTH, OP_AMP_MOD_SENS + - OP_OSC_RATE_SCALE, OP_SCL_LEFT_CURVE, OP_SCL_RGHT_CURVE, OP_KEY_VEL_SENS + +In the Main overlay you can reach the TG and voice overlays also. + +In the voice overlay there is a page for every OP control also, with the 6 operator and with an encoder which sets all. + +#### Pads on Bank A +- Mono/Poly mode +- Portamento enable/disable, hard press to enable/disable Portamento Glissando +- Sostenuto +- Sustain +- All Sound Off +- Hold2 +- None +- Channel AfterTouch Pad + +#### Pads on Bank B +- Short press a TG will enable/disable that TG +- Long press will enable/disable all the TG on the TG's channel +- Hard press will enable only that TG (it uses the pad's AT messsages) + + +### KeyLab mkII features + +#### Faders +- The faders 1-8 adjust the volume of the MIDI channels of the current performance +- The fader 9 adjusts the master volume. + +#### Encoders +- Cutoff, Resonance, Portamento Time +- None, None, Dry Level, FX1 Send, FX2 Send, None + +#### DAW buttons +- Mono/Poly mode +- Portamento enable/disable, hard press to enable/disable Portamento Glissando +- Sostenuto +- Sustain +- Hold2 + +#### Track select buttons +- Short press a TG will enable/disable that TG +- Long press will enable only that TG + + + ![minidexed](https://user-images.githubusercontent.com/2480569/161813414-bb156a1c-efec-44c0-802a-8926412a08e0.jpg) DreamDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). diff --git a/src/Makefile b/src/Makefile index 89b9c8407..8ae5fda65 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,8 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ effect.o effect_cloudseed2.o effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ ../CloudSeedCore/DSP/Biquad.o ../CloudSeedCore/DSP/RandomBuffer.o ../CloudSeedCore/DSP/FastSin.o \ arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ - net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o + net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o \ + dawcontroller.o EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) diff --git a/src/common.h b/src/common.h index 902f74b7f..d982c821d 100644 --- a/src/common.h +++ b/src/common.h @@ -2,6 +2,8 @@ #ifndef _common_h #define _common_h +#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + inline long maplong(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } @@ -16,6 +18,12 @@ inline float32_t mapfloat(int val, int in_min, int in_max, float32_t out_min, fl return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } +inline long mapfloatr(int val, int in_min, int in_max, float32_t out_min, float32_t out_max) +{ + return lround((val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); +} + + #define constrain(amt, low, high) ({ \ __typeof__(amt) _amt = (amt); \ __typeof__(low) _low = (low); \ diff --git a/src/config.cpp b/src/config.cpp index b6492e345..8d67d3039 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -206,7 +206,9 @@ void CConfig::Load (void) m_MIDIButtonActionBankDown = m_Properties.GetString ("MIDIButtonActionBankDown", ""); m_MIDIButtonActionTGUp = m_Properties.GetString ("MIDIButtonActionTGUp", ""); m_MIDIButtonActionTGDown = m_Properties.GetString ("MIDIButtonActionTGDown", ""); - + + m_bDAWControllerEnabled = m_Properties.GetNumber ("DAWControllerEnabled", 0) != 0; + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); @@ -782,6 +784,11 @@ const char *CConfig::GetMIDIButtonActionTGDown (void) const return m_MIDIButtonActionTGDown.c_str(); } +bool CConfig::GetDAWControllerEnabled (void) const +{ + return m_bDAWControllerEnabled; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index 83d104775..c2dc7c776 100644 --- a/src/config.h +++ b/src/config.h @@ -251,6 +251,8 @@ class CConfig // Configuration for MiniDexed const char *GetMIDIButtonActionTGUp (void) const; const char *GetMIDIButtonActionTGDown (void) const; + bool GetDAWControllerEnabled (void) const; + // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions bool GetEncoderEnabled (void) const; @@ -402,6 +404,8 @@ class CConfig // Configuration for MiniDexed unsigned m_nMIDIButtonTGUp; unsigned m_nMIDIButtonTGDown; + bool m_bDAWControllerEnabled; + bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; unsigned m_nEncoderPinData; diff --git a/src/dawcontroller.cpp b/src/dawcontroller.cpp new file mode 100644 index 000000000..a90cbacfa --- /dev/null +++ b/src/dawcontroller.cpp @@ -0,0 +1,2436 @@ +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2024 The MiniDexed Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +#include + +#include "dawcontroller.h" +#include "midikeyboard.h" +#include "minidexed.h" +#include "midi.h" + +#define LINELEN 18 + +#define MIDI_DAW_CHANGE 0b10000 +#define MIDI_DAW_VOICE 1 +#define MIDI_DAW_TOGGLE_MONO 3 +#define MIDI_DAW_TOGGLE_PORTA_GLISS 4 +#define MIDI_DAW_TOGGLE_TG 5 +#define MIDI_DAW_SELECT_TG 6 +#define MIDI_DAW_SELECT_CHAN_TG 7 +#define MIDI_DAW_MENU_SELECT 8 +#define MIDI_DAW_MENU_BACK 9 +#define MIDI_DAW_MENU_PREV 10 +#define MIDI_DAW_MENU_NEXT 11 +#define MIDI_DAW_MENU_PRESS_PREV 12 +#define MIDI_DAW_MENU_PRESS_NEXT 13 +#define MIDI_DAW_MENU_HOME 14 +#define MIDI_DAW_DISPLAY_MODE_TOGGLE 17 +#define MIDI_DAW_ENC_VALUES_TOGGLE 18 +#define MIDI_DAW_ENC_0 20 +#define MIDI_DAW_ENC_1 21 +#define MIDI_DAW_ENC_2 22 +#define MIDI_DAW_ENC_3 23 +#define MIDI_DAW_ENC_4 24 +#define MIDI_DAW_ENC_5 25 +#define MIDI_DAW_ENC_6 26 +#define MIDI_DAW_ENC_7 27 +#define MIDI_DAW_ENC_8 28 +#define MIDI_DAW_FADER_0 29 +#define MIDI_DAW_FADER_1 30 +#define MIDI_DAW_FADER_2 31 +#define MIDI_DAW_FADER_3 32 +#define MIDI_DAW_FADER_4 33 +#define MIDI_DAW_FADER_5 34 +#define MIDI_DAW_FADER_6 35 +#define MIDI_DAW_FADER_7 36 +#define MIDI_DAW_MASTER_VOLUME 37 + + +static void ArturiaDisplayWrite (CMIDIKeyboard *pKeyboard, const u8 *pHdr, const unsigned nHdrSize, + size_t nLineMaxLen, const bool bFill1, const bool bFill2, const char *pMenu, + const char *pParam, const char *pValue, + const bool bArrowLeft, const bool bArrowRight, const bool bShowArrows) +{ + size_t nParamLen = std::min (nLineMaxLen, strlen (pParam)); + size_t nMenuLen = strlen (pMenu); + size_t nFill1Len = bFill1 && nLineMaxLen > nParamLen + nMenuLen ? + nLineMaxLen - nParamLen - nMenuLen : 1; + + nFill1Len = std:: min (nLineMaxLen - nParamLen, nFill1Len); + nMenuLen = std::min (nLineMaxLen - nParamLen - nFill1Len, nMenuLen); + + size_t nLine1Len = nParamLen + nFill1Len + nMenuLen; + + size_t nArrowsLen = bShowArrows ? 2 : 0; + size_t nValueLen = std::min (nLineMaxLen - nArrowsLen, strlen (pValue)); + size_t nFill2Len = bFill2 ? nLineMaxLen - nArrowsLen - nValueLen : 0; + size_t nLine2Len = nValueLen + nFill2Len + nArrowsLen; + + size_t nOffset = 0; + + uint8_t pLines[nHdrSize + nLine1Len + 2 + nLine2Len + 2]; + + memcpy (pLines, pHdr, nHdrSize); + nOffset += nHdrSize; + + memcpy (&pLines[nOffset], pParam, nParamLen); + nOffset += nParamLen; + + memset (&pLines[nOffset], ' ', nFill1Len); + nOffset += nFill1Len; + + memcpy (&pLines[nOffset], pMenu, nMenuLen); + nOffset += nMenuLen; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0x02; + + if (bShowArrows) + pLines[nOffset++] = bArrowLeft ? '<' : ' '; + + memcpy (&pLines[nOffset], pValue, nValueLen); + nOffset += nValueLen; + + memset (&pLines[nOffset], ' ', nFill2Len); + nOffset += nFill2Len; + + if (bShowArrows) + pLines[nOffset++] = bArrowRight ? '>' : ' '; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0xF7; + + // block character (0xFF) is not supported over MIDI, change to 0x7f + for (unsigned i = 0; i < sizeof pLines; ++i) + if (pLines[i] == 0xFF) + pLines[i] = 0x7F; + + pKeyboard->SendDisplay (pLines, nOffset, 0); +} + +enum ControlType +{ + CT_KNOB = 3, + CT_FADER, + CT_PAD, +}; + +enum HideAfter +{ + HA_NO = 0, + HA_YES = 2, +}; + +static std::string to_string (int nValue, int nWidth) +{ + return std::to_string(nValue); +} + +static std::string to_percent (int nValue, int nWidth) +{ + return std::to_string(mapfloatr (nValue, 0, 127, 0, 100)) + "%"; +} + +static std::string to_on_off (int nValue, int nWidth) +{ + return nValue < 64 ? "Off" : "On"; +} + +static std::string to_selected (int nValue, int nWidth) +{ + return nValue < 64 ? "Deselected" : "Selected"; +} + +std::string to_midi_channel (int nValue) +{ + switch (nValue) + { + case CMIDIDevice::OmniMode: return "Omni"; + case CMIDIDevice::Disabled: return "Off"; + default: return std::to_string (nValue + 1); + } +} + +static void ArturiaDisplayInfoWrite (CMIDIKeyboard *pKeyboard, const uint8_t pDisplayHdr[3], ControlType Type, u8 uValue, const char *pName, const char *pValue) +{ + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, pDisplayHdr[0], pDisplayHdr[1], pDisplayHdr[2], 0x1F, Type, HA_NO, uValue, 0x00, 0x00, 0x01}; + + int nLine1Len = strlen (pName); + int nLine2Len = strlen (pValue); + int nOffset = 0; + + uint8_t pLines[sizeof pHdr + nLine1Len + 2 + nLine2Len + 2]; + + memcpy (pLines, pHdr, sizeof pHdr); + nOffset += sizeof pHdr; + + memcpy (pLines + nOffset, pName, nLine1Len); + nOffset += nLine1Len; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0x02; + + memcpy (pLines + nOffset, pValue, nLine2Len); + nOffset += nLine2Len; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0xf7; + + pKeyboard->SendDisplay (pLines, nOffset, 0); +} + +static void ArturiaShowNewCCValue (CMIDIKeyboard *pKeyboard, const uint8_t pDisplayHdr[3], u8 ucCh, u8 ucCC, u8 ucValue) +{ + char line1[LINELEN]; + char line2[LINELEN]; + + switch (ucCC) + { + case MIDI_CC_PORTAMENTO_TIME: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Portamento Time", line2); + break; + case MIDI_CC_VOLUME: + snprintf(line1, LINELEN, "Volume Ch %d", ucCh + 1); + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 100)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_FADER, ucValue, line1, line2); + break; + case MIDI_CC_FREQUENCY_CUTOFF: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Cutoff", line2); + break; + case MIDI_CC_RESONANCE: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Resonance", line2); + break; + case MIDI_CC_EFFECT1_SEND: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Effect1 Send", line2); + break; + case MIDI_CC_EFFECT2_SEND: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Effect2 Send", line2); + break; + case MIDI_CC_DETUNE_LEVEL: + snprintf(line2, LINELEN, "%ld", mapfloatr (ucValue, 1, 127, -99, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Detune", line2); + break; + case MIDI_CC_PAN_POSITION: + snprintf(line2, LINELEN, "%d", ucValue); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Pan", line2); + break; + case MIDI_CC_SUSTAIN: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Sustain", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_PORTAMENTO: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Portamento", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_SOSTENUTO: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Sostenuto", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_HOLD2: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Hold", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_ALL_SOUND_OFF: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "All Sound Off", ""); + break; + } +} + +static void HandleMenuEvents (CUserInterface *pUI, u8 ucDC) +{ + switch (ucDC) + { + case MIDI_DAW_MENU_SELECT: + pUI->MIDIEventHandler (CUIMenu::MenuEventSelect); + break; + case MIDI_DAW_MENU_BACK: + pUI->MIDIEventHandler (CUIMenu::MenuEventBack); + break; + case MIDI_DAW_MENU_PREV: + pUI->MIDIEventHandler (CUIMenu::MenuEventStepDown); + break; + case MIDI_DAW_MENU_NEXT: + pUI->MIDIEventHandler (CUIMenu::MenuEventStepUp); + break; + case MIDI_DAW_MENU_PRESS_PREV: + pUI->MIDIEventHandler (CUIMenu::MenuEventPressAndStepDown); + break; + case MIDI_DAW_MENU_PRESS_NEXT: + pUI->MIDIEventHandler (CUIMenu::MenuEventPressAndStepUp); + break; + case MIDI_DAW_MENU_HOME: + pUI->MIDIEventHandler (CUIMenu::MenuEventHome); + break; + } +} + +class CDAWConnection +{ +public: + virtual void DisplayWrite (const char *pMenu, const char *pParam, + const char *pValue, bool bArrowDown, bool bArrowUp) = 0; + virtual void UpdateState () = 0; + virtual void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) = 0; + virtual void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) = 0; + virtual ~CDAWConnection (void) = default; + + static const unsigned nDefaultDisplayUpdateDelay = 2000; +}; + +struct CColor +{ + uint8_t r; + uint8_t g; + uint8_t b; +}; + +bool operator==(const CColor& l, const CColor& r) +{ + return l.r == r.r && l.g == r.g && l.b == r.b; +} + +bool operator!=(const CColor& l, const CColor& r) +{ + return !(l == r); +} + +static CColor padColors[8] = { + {0x3F, 0x3F, 0x11}, + {0x11, 0x11, 0x3F}, + {0x3F, 0x11, 0x3F}, + {0x11, 0x3F, 0x11}, + {0x3F, 0x11, 0x11}, + {0x11, 0x3F, 0x3F}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, +}; + +static CColor altPadColors[8] = { + {0x3F, 0x3F, 0x11}, + {0x11, 0x21, 0x3F}, + {0x3F, 0x11, 0x3F}, + {0x11, 0x3F, 0x11}, + {0x3F, 0x11, 0x11}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, +}; + +static CColor chColors[CMIDIDevice::TChannel::Disabled + 1] = { + {0x7F, 0x00, 0x00}, // 1 + {0x7F, 0x40, 0x00}, // 2 + {0x7F, 0x40, 0x40}, // 3 + {0x7F, 0x40, 0x7F}, // 4 + {0x7F, 0x7F, 0x00}, // 5 + {0x7F, 0x7F, 0x40}, // 6 + {0x7F, 0x7F, 0x7F}, // 7 + {0x40, 0x00, 0x40}, // 8 + {0x40, 0x40, 0x00}, // 9 + {0x40, 0x40, 0x40}, // 10 + {0x40, 0x40, 0x7F}, // 11 + {0x40, 0x7F, 0x00}, // 12 + {0x40, 0x7F, 0x40}, // 13 + {0x40, 0x7F, 0x7F}, // 14 + {0x00, 0x00, 0x40}, // 15 + {0x00, 0x40, 0x00}, // 16 + {0x7F, 0x7F, 0x7F}, // Omni + {0x00, 0x00, 0x00}, // Disabled +}; + +static CColor invalidColor = {0x80, 0x80, 0x80}; + +static CColor chColors_kl2[CMIDIDevice::TChannel::Disabled + 1] = { + {0x1F, 0x00, 0x00}, // 1 + {0x1F, 0x10, 0x00}, // 2 + {0x1F, 0x10, 0x10}, // 3 + {0x1F, 0x10, 0x1F}, // 4 + {0x1F, 0x1F, 0x00}, // 5 + {0x1F, 0x1F, 0x10}, // 6 + {0x1F, 0x1F, 0x1F}, // 7 + {0x10, 0x00, 0x10}, // 8 + {0x10, 0x10, 0x00}, // 9 + {0x10, 0x10, 0x10}, // 10 + {0x10, 0x10, 0x1F}, // 11 + {0x10, 0x1F, 0x00}, // 12 + {0x10, 0x1F, 0x10}, // 13 + {0x10, 0x1F, 0x1F}, // 14 + {0x00, 0x00, 0x10}, // 15 + {0x00, 0x10, 0x00}, // 16 + {0x1F, 0x1F, 0x1F}, // Omni + {0x00, 0x00, 0x00}, // Disabled +}; + +class CMiniLab3DawConnection : public CDAWConnection +{ +public: + CMiniLab3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + enum TPadID { + MonoPad = 0, + PortamentoPad = 1, + SostenutoPad = 2, + SustainPad = 3, + SoundOffPad = 4, + HoldPad = 5, + TBDPad7 = 6, + ATPad = 7, + }; + enum TBankID { + BankA = 0x34, + BankB = 0x44, + }; + + static const u8 AllOP = 8; + + void DisplayWriteSimple (const char *pMenu, const char *pParam, const char *pValue); + + static void s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext); + void QueueUpdateDisplay (unsigned msec); + void UpdateDisplay (); + void ShowEncoderDisplay (); + void ShowValueDisplay (); + + void UpdateEncoder (uint8_t ucEncID, uint8_t ucValue); + void UpdateEncoders (); + void UpdateTGColors (); + void UpdateMonoColor (); + void UpdatePortamentoColor (); + void UpdateATColor (u8 ucAT); + void UpdateChanGroups (); + + void SetPadColor (TBankID BankID, TPadID PadID, u8 state); + void SetPadColor (TBankID BankID, TPadID PadID, u8 state, u8 state2); + void SetPadColor (TBankID BankID, TPadID PadID, CColor color, u8 state); + void SetPadColor (TBankID BankID, TPadID PadID, CColor color); + + void SetChannelAT (u8 ucValue); + void SetVoice (u8 ucChannel, u8 ucVoice); + void SetAlgorithm (u8 ucChannel, u8 ucAlgorithm); + void SetEncoder (u8 ucChannel, u8 ucEncID, u8 ucVoice); + void ToggleMonoMode (u8 ucChannel); + void TogglePortamentoGlisssando (u8 ucChannel); + void ToggleTG (u8 ucTG); + void SelectTG (u8 ucTG); + void SelectChanTG (u8 ucTG); + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + bool m_bDisableEncoderUpdate = false; + + CUIMenu::TCPageType m_encoderPageType = CUIMenu::PageMain; + u8 m_ucEncoderPage = 0; + u8 m_ucEncoderOP = 0; + u8 m_ucEncoderTG = 0; + CUIMenu::TCParameterInfo *m_pEncoders; + + enum DisplayState { + DisplayMenu, + DisplayEncoder, + DisplayValues, + }; + DisplayState m_DisplayState = DisplayMenu; + + static constexpr size_t nEncoder = 8; + static constexpr size_t nFader = 4; + + CUIMenu::TCParameterInfo m_pMainEncoders[1 + 0 + 2 + 5 + 3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterResonance}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoTime}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterProgram}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterVolume, "Master Vol", "MVo", .ToString=to_percent}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=1, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=2, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=3, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=4, .ToString=to_percent}, + }, + /*{ + // Effect Master EQ + }, + { + // Effect Limiter + },*/ + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn1", .TG=1, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn2", .TG=2, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn3", .TG=3, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn4", .TG=4, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt1", .TG=1}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt2", .TG=2}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt3", .TG=3}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt4", .TG=4}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=1, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=2, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=3, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=4, .ToString=to_percent}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn5", .TG=5, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn6", .TG=6, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn7", .TG=7, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn8", .TG=8, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt5", .TG=5}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt6", .TG=6}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt7", .TG=7}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt8", .TG=8}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=5, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=6, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=7, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=8, .ToString=to_percent}, + }, + }; + + CUIMenu::TCParameterInfo m_pEffectEncoders[0][nEncoder + nFader] = { + /*{ + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLow, "MaEQ Low"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMid, "MaEQ Mid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQHigh, "MaEQ High"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQGain, "MaEQ Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLowMidFreq, "MaEQ LowMid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMidHighFreq, "MaEQ MidHigh"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLow, "MaEQ Low"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMid, "MaEQ Mid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQHigh, "MaEQ High"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQGain, "MaEQ Gain"}, + }, + { + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorEnable, "Master Compressor"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorPreGain, "MaCR Pre Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorAttack, "MaCR Attack"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRelease, "MaCR Release"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorThresh, "MaCR Thresh"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRatio, "MaCR Ratio"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorHPFilterEnable, "MaCR HP Filter"}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorPreGain, "MaCR Pre Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorAttack, "MaCR Attack"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRelease, "MaCR Release"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorThresh, "MaCR Thresh"}, + },*/ + }; + + CUIMenu::TCParameterInfo m_pTGEncoders[6 + 3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterResonance}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoTime}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .ToString=to_string}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMIDIChannel}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterProgram}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPitchBendRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoGlissando}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMonoMode}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPitchBendStep}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLow, "TGEQ Low"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMid, "TGEQ Mid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQHigh, "TGEQ High"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQGain, "TGEQ Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLowMidFreq, "TGEQ LowMid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMidHighFreq, "TGEQ MidHigh"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLow, "TGEQ Low"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMid, "TGEQ Mid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQHigh, "TGEQ High"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQGain, "TGEQ Gain"}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorEnable, "Compressor"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorPreGain, "Pre Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorMakeupGain, "Makeup Gain"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorAttack, "Attack"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRelease, "Release"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorThresh, "Thresh"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRatio, "Ratio"}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorPreGain, "Pre Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorAttack, "Attack"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRelease, "Release"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorThresh, "Thresh"}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWPitch, "MW Pitch", "MWP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCPitch, "FC Pitch", "FCP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWEGBias, "MW EG Bias", "MWEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWAmplitude, "MW Amp", "MWA"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCEGBias, "FC EG Bias", "FCEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCAmplitude, "FC Amp", "FCA"}, + + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCPitch, "BC Pitch", "BCP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATPitch, "AT Pitch", "ATP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCEGBias, "BC EG Bias", "BCEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCAmplitude, "BC Amp", "BCA"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATEGBias, "AT EG Bias", "ATEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATAmplitude, "AT Amp", "ATA"}, + }, + }; + + CUIMenu::TCParameterInfo m_pVoiceEncoders[3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterVoice, DEXED_ALGORITHM}, + {CUIMenu::ParameterVoice, DEXED_FEEDBACK}, + {CUIMenu::ParameterVoice, DEXED_TRANSPOSE}, + }, + { + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R4}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L4}, + + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L4}, + }, + { + {CUIMenu::ParameterVoice, DEXED_OSC_KEY_SYNC}, + {CUIMenu::ParameterVoice, DEXED_LFO_SPEED}, + {CUIMenu::ParameterVoice, DEXED_LFO_PITCH_MOD_SENS}, + {CUIMenu::ParameterVoice, DEXED_LFO_PITCH_MOD_DEP}, + {CUIMenu::ParameterVoice, DEXED_LFO_SYNC}, + {CUIMenu::ParameterVoice, DEXED_LFO_DELAY}, + {CUIMenu::ParameterVoice, DEXED_LFO_WAVE}, + {CUIMenu::ParameterVoice, DEXED_LFO_AMP_MOD_DEP}, + }, + }; + + CUIMenu::TCParameterInfo m_pOPEncoders[3][nEncoder + nFader] = { + { + {CUIMenu::ParameterOP, DEXED_OP_OUTPUT_LEV}, + {CUIMenu::ParameterOP, DEXED_OP_FREQ_COARSE}, + {CUIMenu::ParameterOP, DEXED_OP_FREQ_FINE}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_DETUNE}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_MODE}, + {CUIMenu::ParameterOP, DEXED_OP_ENABLE}, + }, + { + {CUIMenu::ParameterOP, DEXED_OP_EG_R1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R4}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L4}, + + {CUIMenu::ParameterOP, DEXED_OP_EG_L1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L4}, + }, + { + {CUIMenu::ParameterOP, DEXED_OP_LEV_SCL_BRK_PT}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_LEFT_DEPTH}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_RGHT_DEPTH}, + {CUIMenu::ParameterOP, DEXED_OP_AMP_MOD_SENS}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_RATE_SCALE}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_LEFT_CURVE}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_RGHT_CURVE}, + {CUIMenu::ParameterOP, DEXED_OP_KEY_VEL_SENS}, + }, + }; + + TKernelTimerHandle m_DisplayTimer = 0; + + u8 m_ucFirstTG = 0; + + CColor m_PadColorCache[8]; + CColor m_TGColorCache[8]; + + u8 m_EncoderCache[nEncoder]; + + u8 m_ChanGroups[nFader]; + + const uint8_t m_pEncoder[3] = {0x04, 0x02, 0x60}; + TMIDIRoute m_pRouteMap[75] = { + {0, 0, MIDI_CONTROL_CHANGE, 14, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_0, 0xFF}, // Fader1 + {0, 0, MIDI_CONTROL_CHANGE, 15, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_1, 0xFF}, // Fader2 + {0, 0, MIDI_CONTROL_CHANGE, 30, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_2, 0xFF}, // Fader3 + {0, 0, MIDI_CONTROL_CHANGE, 31, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_3, 0xFF}, // Fader4 + + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 119, 0x7F, .bSkip=true}, // Shift + Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 119, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_HOME, 0}, + + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Shift + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_VALUES_TOGGLE, 0xFF, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_DISPLAY_MODE_TOGGLE, 0xFF, .bGroup=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 86, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_0, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 87, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_1, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 89, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_2, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 90, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_3, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 110, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_4, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 111, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_5, 0xFF}, // Knob6 + {0, 0, MIDI_CONTROL_CHANGE, 116, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_6, 0xFF}, // Knob7 + {0, 0, MIDI_CONTROL_CHANGE, 117, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_7, 0xFF}, // Knob8 + + {0, 9, MIDI_NOTE_ON, 36, 0xFF, .bSkip=true}, // BankA Pad1 + {0, 9, MIDI_NOTE_OFF, 36, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_MONO, 0x7F}, + + {0, 9, MIDI_NOTE_ON, 37, 0xFF, .bSkip=true, .bGroupHead=true}, // BankA Pad2 + {0, 9, MIDI_NOTE_OFF, 37, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO, 0x7F, .bToggle=true, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 37, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_PORTA_GLISS, 0x7F, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 38, 0xFF, .bSkip=true}, // BankA Pad3 + {0, 9, MIDI_NOTE_OFF, 38, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SOSTENUTO, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 39, 0xFF, .bSkip=true}, // BankA Pad4 + {0, 9, MIDI_NOTE_OFF, 39, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SUSTAIN, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 40, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_ALL_SOUND_OFF, 0x7F}, // BankA Pad5 + {0, 9, MIDI_NOTE_OFF, 40, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_ALL_SOUND_OFF, 0x00}, + + {0, 9, MIDI_NOTE_ON, 41, 0xFF, .bSkip=true}, // BankA Pad6 + {0, 9, MIDI_NOTE_OFF, 41, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_HOLD2, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 42, 0xFF, .bSkip=true}, // BankA Pad7 + {0, 9, MIDI_NOTE_OFF, 42, 0xFF, .bSkip=true}, + + {0, 9, MIDI_NOTE_ON, 43, 0xFF, .bSkip=true}, // BankA Pad8 + {0, 9, MIDI_NOTE_OFF, 43, 0xFF, 0, MIDI_CHANNEL_AFTERTOUCH, 0x00, 0xFF}, + {0, 9, MIDI_AFTERTOUCH, 43, 0xFF, 0, MIDI_CHANNEL_AFTERTOUCH, TMIDIRoute::P2, 0xFF}, + + {0, 9, MIDI_NOTE_ON, 44, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad1 + {0, 9, MIDI_NOTE_OFF, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 0, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 0, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 45, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad2 + {0, 9, MIDI_NOTE_OFF, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 1, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 1, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 1, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 46, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad3 + {0, 9, MIDI_NOTE_OFF, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 2, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 2, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 2, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 47, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad4 + {0, 9, MIDI_NOTE_OFF, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 3, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 3, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 3, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 48, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad5 + {0, 9, MIDI_NOTE_OFF, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 4, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 4, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 4, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 49, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad6 + {0, 9, MIDI_NOTE_OFF, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 5, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 5, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 5, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 50, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad7 + {0, 9, MIDI_NOTE_OFF, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 6, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 6, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 6, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 51, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad8 + {0, 9, MIDI_NOTE_OFF, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 7, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 7, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 7, .bGroup=true}, + + {0xFF}, // Sentinel + }; +}; + +CMiniLab3DawConnection::CMiniLab3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7}; + + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On MiniLab 3", 0, 0); + + SetPadColor (BankA, MonoPad, 0); + SetPadColor (BankA, PortamentoPad, 0); + SetPadColor (BankA, SostenutoPad, 0); + SetPadColor (BankA, SustainPad, 0); + SetPadColor (BankA, SoundOffPad, 0); + SetPadColor (BankA, HoldPad, 0); + SetPadColor (BankA, TBDPad7, 0); + UpdateATColor (0); + + for (unsigned vIdx = 3,i = 0; i < ARRAY_LENGTH (m_pOPEncoders); ++i) + for (unsigned j = 0; j < nEncoder; ++j) + { + CUIMenu::TCParameterInfo *pInfo = &m_pOPEncoders[i][j]; + if (!pInfo->Type) + continue; + + for (unsigned k = 0; k < 6; ++k) + m_pVoiceEncoders[vIdx][k] = {pInfo->Type, pInfo->Parameter, .OP=static_cast(k+1)}; + + m_pVoiceEncoders[vIdx][7] = {pInfo->Type, pInfo->Parameter, .OP=AllOP}; + + vIdx++; + } + + assert (sizeof m_pTGEncoders == sizeof *m_pTGEncoders * 6 + sizeof m_pVoiceEncoders); + memcpy (m_pTGEncoders + 6, m_pVoiceEncoders, sizeof m_pVoiceEncoders); + + assert (sizeof m_pMainEncoders == sizeof *m_pMainEncoders * 1 + sizeof m_pEffectEncoders + sizeof *m_pMainEncoders * 2 + sizeof *m_pTGEncoders * 5 + sizeof m_pVoiceEncoders); + memcpy (m_pMainEncoders + 1, m_pEffectEncoders, sizeof m_pEffectEncoders); + memcpy (m_pMainEncoders + 5, m_pTGEncoders + 1, sizeof *m_pTGEncoders * 5); + memcpy (m_pMainEncoders + 10, m_pVoiceEncoders, sizeof m_pVoiceEncoders); + + for (unsigned i = 0; i < ARRAY_LENGTH (m_pMainEncoders); ++i) + m_pUI->GetParameterInfos (m_pMainEncoders[i], ARRAY_LENGTH (m_pMainEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pTGEncoders); ++i) + m_pUI->GetParameterInfos (m_pTGEncoders[i], ARRAY_LENGTH (m_pTGEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pEffectEncoders); ++i) + m_pUI->GetParameterInfos (m_pEffectEncoders[i], ARRAY_LENGTH (m_pEffectEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pVoiceEncoders); ++i) + m_pUI->GetParameterInfos (m_pVoiceEncoders[i], ARRAY_LENGTH (m_pVoiceEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pOPEncoders); ++i) + m_pUI->GetParameterInfos (m_pOPEncoders[i], ARRAY_LENGTH (m_pOPEncoders[i])); + + + memset (m_PadColorCache, 0xFF, sizeof (m_PadColorCache)); + memset (m_TGColorCache, 0xFF, sizeof (m_TGColorCache)); + memset (m_EncoderCache, 0xFF, sizeof (m_EncoderCache)); + + + UpdateMenu (m_encoderPageType, m_ucEncoderPage, m_ucEncoderOP, m_ucEncoderTG); + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +void CMiniLab3DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + const uint8_t page = bArrowDown == bArrowUp ? 0x11 : bArrowDown ? 0x10 : 0x00; + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x06, 0x00, 0x00, page, 0x00, 0x11, 0x00, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, false, pMenu, pParam, pValue, false, false, false); +} + +void CMiniLab3DawConnection::DisplayWriteSimple (const char *pMenu, const char *pParam, const char *pValue) +{ + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, false, pMenu, pParam, pValue, false, false, false); +} + +void CMiniLab3DawConnection::QueueUpdateDisplay (unsigned msec) +{ + if (m_DisplayTimer) + CTimer::Get ()->CancelKernelTimer (m_DisplayTimer); + m_DisplayTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (msec), s_UpdateDisplay, this, NULL); +} + +void CMiniLab3DawConnection::s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + assert (pParam != NULL); + static_cast(pParam)->UpdateDisplay (); +} + +void CMiniLab3DawConnection::UpdateDisplay () +{ + switch (m_DisplayState) + { + case DisplayMenu: + m_pUI->MIDIEventHandler (CUIMenu::MenuEventUpdate); + break; + case DisplayEncoder: + ShowEncoderDisplay (); + break; + case DisplayValues: + ShowValueDisplay (); + break; + } +} + +void CMiniLab3DawConnection::ShowEncoderDisplay () +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01}; + std::string pParam = ""; + std::string pValue = ""; + for (unsigned i = 0; i < nEncoder; ++i) + { + const char *pShort = m_pEncoders[i].Short ?: "..."; + if (i < 4) + pParam = pParam + pShort + " "; + else + pValue = pValue + pShort + " "; + } + + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, false, false, "", pParam.c_str(), pValue.c_str(), false, false, false); +} + +static int GetParameterValue (CMiniDexed *pSynthesizer, CUIMenu::TCParameterInfo *pInfo, uint8_t ucOP, uint8_t ucTG) +{ + switch (pInfo->Type) + { + case CUIMenu::ParameterGlobal: + return pSynthesizer->GetParameter (static_cast(pInfo->Parameter)); + break; + case CUIMenu::ParameterTG: + return pSynthesizer->GetTGParameter (static_cast(pInfo->Parameter), ucTG); + break; + case CUIMenu::ParameterVoice: + return pSynthesizer->GetVoiceParameter (pInfo->Parameter, CMiniDexed::NoOP, ucTG); + break; + case CUIMenu::ParameterOP: + return pSynthesizer->GetVoiceParameter (pInfo->Parameter, ucOP, ucTG); + break; + default: + return 0; + break; + } +} + +static std::string GetParameterValueStr (CMiniDexed *pSynthesizer, CUIMenu::TCParameterInfo *pInfo, uint8_t ucOP, uint8_t ucTG) +{ + if (pInfo->Type == CUIMenu::ParameterNone) + return "..."; + int value = GetParameterValue (pSynthesizer, pInfo, ucOP, ucTG); + if (pInfo->ToString) + return pInfo->ToString (value, 0); + return std::to_string (value); +} + + +void CMiniLab3DawConnection::ShowValueDisplay () +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x07, 0x01, 0x02, 0x02, 0x01, 0x00, 0x01}; + std::string pParam = ""; + std::string pValue = ""; + + for (unsigned i = 0; i < nEncoder; ++i) + { + CUIMenu::TCParameterInfo *enc = &m_pEncoders[i]; + uint8_t ucTG = enc->TG ? enc->TG - 1 : m_ucEncoderTG ? m_ucEncoderTG - 1 : m_ucFirstTG; + uint8_t ucOP = enc->OP ? enc->OP - 1 : m_ucEncoderOP; + if (enc->OP == AllOP) + ucOP = 0; + + std::string sValue = GetParameterValueStr (m_pSynthesizer, enc, ucOP, ucTG); + + if (i < 4) + pParam = pParam + sValue + " "; + else + pValue = pValue + sValue + " "; + } + + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, false, false, "", pParam.c_str(), pValue.c_str(), false, false, false); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, u8 state) +{ + SetPadColor (BankID, PadID, padColors[PadID], state); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, u8 state, u8 state2) +{ + SetPadColor (BankID, PadID, state2 ? altPadColors[PadID] : padColors[PadID], state); +} + +static CColor darken(CColor color, u8 enabled) +{ + if (!enabled) + { + color.r /= 32; + color.g /= 32; + color.b /= 32; + } + + return color; +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, CColor color, u8 state) +{ + SetPadColor (BankID, PadID, darken (color, state)); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, CColor color) +{ + if (BankID == BankA && m_PadColorCache[PadID] == color) + return; + + const uint8_t pSetPadColor[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x02, 0x16, (uint8_t)(PadID + BankID), color.r, color.g, color.b, 0xF7}; + m_pKeyboard->Send (pSetPadColor, sizeof pSetPadColor, 0); + + if (BankID == BankA) + m_PadColorCache[PadID] = color; +} + +void CMiniLab3DawConnection::UpdateEncoder (uint8_t ucEncID, uint8_t ucValue) +{ + uint8_t pUpdateEncoder[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x21, 0x10, 0x00, ucEncID+=7, 0x00, ucValue, 0xF7}; + m_pKeyboard->Send (pUpdateEncoder, sizeof pUpdateEncoder, 0); +} + +void CMiniLab3DawConnection::UpdateTGColors () +{ + bool need_update = false; + CColor colors[8]; + uint8_t numTG = std::min(m_pConfig->GetToneGenerators(), 8u); + + for (unsigned i = 0; i < numTG; ++i) + { + u8 ch = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i); + + colors[i] = darken (chColors[ch], enabled); + + if (m_TGColorCache[i] != colors[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < numTG; ++i) + { + SetPadColor (BankB, (TPadID)i, colors[i]); + m_TGColorCache[i] = colors[i]; + } +} + +void CMiniLab3DawConnection::UpdateMonoColor () +{ + SetPadColor (BankA, MonoPad, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG)); +} + +void CMiniLab3DawConnection::UpdatePortamentoColor () +{ + u8 mode = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoMode, m_ucFirstTG); + u8 mode2 = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG); + SetPadColor (BankA, PortamentoPad, mode, mode2); +} + +void CMiniLab3DawConnection::UpdateATColor (u8 ucAT) +{ + u8 c = ucAT ?: 1; + SetPadColor (BankA, ATPad, CColor {c, c, c}); +} + +void CMiniLab3DawConnection::UpdateEncoders () +{ + bool need_update = false; + u8 values[nEncoder]; + + if (m_bDisableEncoderUpdate) + return; + + for (unsigned i = 0; i < nEncoder; ++i) + { + CUIMenu::TCParameterInfo *enc = &m_pEncoders[i]; + u8 ucTG = enc->TG ? enc->TG - 1 : m_ucEncoderTG ? m_ucEncoderTG - 1 : m_ucFirstTG; + u8 ucOP = enc->OP ? enc->OP - 1 : m_ucEncoderOP; + if (enc->OP == AllOP) + ucOP = 0; + int value; + + switch (enc->Type) + { + case CUIMenu::ParameterGlobal: + value = m_pSynthesizer->GetParameter (static_cast(enc->Parameter)); + break; + case CUIMenu::ParameterTG: + value = m_pSynthesizer->GetTGParameter (static_cast(enc->Parameter), ucTG); + break; + case CUIMenu::ParameterVoice: + value = m_pSynthesizer->GetVoiceParameter (enc->Parameter, CMiniDexed::NoOP, ucTG); + break; + case CUIMenu::ParameterOP: + value = m_pSynthesizer->GetVoiceParameter (enc->Parameter, ucOP, ucTG); + break; + default: + continue; + } + values[i] = mapfloatr (value, enc->Min, enc->Max, 0, 127); + if (values[i] != m_EncoderCache[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < nEncoder; ++i) + { + UpdateEncoder (i, values[i]); + m_EncoderCache[i] = values[i]; + } +} + +void CMiniLab3DawConnection::UpdateChanGroups () +{ + memset (m_ChanGroups, CMIDIDevice::Disabled, sizeof m_ChanGroups); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + int channel = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + + if (channel == CMIDIDevice::ChannelUnknown || channel == CMIDIDevice::Disabled) + continue; + + if (channel == CMIDIDevice::OmniMode) + channel = 0; + + for (unsigned i = 0; i < sizeof m_ChanGroups; ++i) + { + if (m_ChanGroups[i] == channel) + break; + + if (m_ChanGroups[i] == CMIDIDevice::Disabled) { + m_ChanGroups[i] = channel; + break; + } + } + } +} + +void CMiniLab3DawConnection::UpdateState () +{ + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + u8 ucChannel = m_pKeyboard->GetChannel (i); + + if (ucChannel == CMIDIDevice::ChannelUnknown || ucChannel == CMIDIDevice::Disabled) + continue; + + if (ucChannel == CMIDIDevice::OmniMode) + ucChannel = 0; + + for (TMIDIRoute *r = m_pRouteMap; r->ucSCable != 0xFF; r++) + r->ucDCh = ucChannel; + + m_ucFirstTG = i; + + break; + } + + UpdateEncoders (); + + UpdateMonoColor (); + // TODO change the MIDIRouteMap's value also + UpdatePortamentoColor (); + + UpdateTGColors (); + + UpdateChanGroups (); +} + +void CMiniLab3DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + m_encoderPageType = Type; + m_ucEncoderOP = ucOP; + m_ucEncoderTG = ucTG; + + switch (Type) + { + case CUIMenu::PageMain: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pMainEncoders) - 1); + m_pEncoders = m_pMainEncoders[m_ucEncoderPage]; + m_ucEncoderTG = 0; // 0 -> first active TG + break; + case CUIMenu::PageTG: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pTGEncoders) - 1); + m_pEncoders = m_pTGEncoders[m_ucEncoderPage]; + break; + //case CUIMenu::PageEffect: + // m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pEffectEncoders) - 1); + // m_pEncoders = m_pEffectEncoders[m_ucEncoderPage]; + // break; + case CUIMenu::PageVoice: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pVoiceEncoders) - 1); + m_pEncoders = m_pVoiceEncoders[m_ucEncoderPage]; + break; + case CUIMenu::PageOP: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pOPEncoders) - 1); + m_pEncoders = m_pOPEncoders[m_ucEncoderPage]; + break; + default: + assert (false); + } + + UpdateState (); +} + +void CMiniLab3DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + unsigned nDisplayUpdateDelay = nDefaultDisplayUpdateDelay; + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + ArturiaShowNewCCValue (m_pKeyboard, m_pEncoder, ucChannel, ucP1, ucP2); + + switch (ucP1) + { + case MIDI_CC_PORTAMENTO: + UpdatePortamentoColor (); + break; + case MIDI_CC_SOSTENUTO: + SetPadColor (BankA, SostenutoPad, ucP2); + break; + case MIDI_CC_HOLD2: + SetPadColor (BankA, HoldPad, ucP2); + break; + case MIDI_CC_SUSTAIN: + SetPadColor (BankA, SustainPad, ucP2); + break; + case MIDI_CC_ALL_SOUND_OFF: + SetPadColor (BankA, SoundOffPad, ucP2); + break; + } + break; + case MIDI_DAW_CHANGE: + switch (m_DisplayState) + { + case DisplayMenu: + HandleMenuEvents (m_pUI, ucP1); + break; + case DisplayEncoder: + switch (ucP1) + { + case MIDI_DAW_MENU_PREV: + UpdateMenu (m_encoderPageType, m_ucEncoderPage - 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + break; + case MIDI_DAW_MENU_NEXT: + UpdateMenu (m_encoderPageType, m_ucEncoderPage + 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + break; + case MIDI_DAW_ENC_VALUES_TOGGLE: + m_DisplayState = DisplayValues; + UpdateDisplay (); + break; + } + break; + case DisplayValues: + switch (ucP1) + { + case MIDI_DAW_MENU_PREV: + UpdateMenu (m_encoderPageType, m_ucEncoderPage - 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + nDisplayUpdateDelay = 500; + break; + case MIDI_DAW_MENU_NEXT: + UpdateMenu (m_encoderPageType, m_ucEncoderPage + 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + nDisplayUpdateDelay = 500; + break; + case MIDI_DAW_ENC_VALUES_TOGGLE: + m_DisplayState = DisplayEncoder; + UpdateDisplay (); + break; + } + break; + } + + switch (ucP1) + { + case MIDI_DAW_VOICE: + SetVoice (ucChannel, ucP2); + break; + case MIDI_DAW_TOGGLE_MONO: + ToggleMonoMode (ucChannel); + break; + case MIDI_DAW_TOGGLE_PORTA_GLISS: + TogglePortamentoGlisssando (ucChannel); + break; + case MIDI_DAW_TOGGLE_TG: + ToggleTG (ucP2); + break; + case MIDI_DAW_SELECT_TG: + SelectTG (ucP2); + break; + case MIDI_DAW_SELECT_CHAN_TG: + SelectChanTG (ucP2); + break; + case MIDI_DAW_DISPLAY_MODE_TOGGLE: + m_DisplayState = m_DisplayState != DisplayMenu ? DisplayMenu : DisplayEncoder; + UpdateDisplay (); + break; + case MIDI_DAW_ENC_0: + case MIDI_DAW_ENC_1: + case MIDI_DAW_ENC_2: + case MIDI_DAW_ENC_3: + case MIDI_DAW_ENC_4: + case MIDI_DAW_ENC_5: + case MIDI_DAW_ENC_6: + case MIDI_DAW_ENC_7: + SetEncoder (ucChannel, ucP1 - MIDI_DAW_ENC_0, ucP2); + break; + case MIDI_DAW_FADER_0: + case MIDI_DAW_FADER_1: + case MIDI_DAW_FADER_2: + case MIDI_DAW_FADER_3: + SetEncoder (ucChannel, ucP1 - MIDI_DAW_FADER_0 + 8, ucP2); + break; + } + break; + case MIDI_CHANNEL_AFTERTOUCH: + SetChannelAT (ucP1); + break; + } + QueueUpdateDisplay (nDisplayUpdateDelay); +} + +void CMiniLab3DawConnection::SetChannelAT (u8 ucValue) +{ + char line2[LINELEN]; + snprintf(line2, LINELEN, "%d", ucValue); + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Channel AT", line2); + + UpdateATColor (ucValue); +} + +void CMiniLab3DawConnection::SetVoice (u8 ucChannel, u8 ucVoice) +{ + std::string line2; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->ProgramChange (ucVoice, i); + if (line2.length() == 0) { + std::string sVoiceName = m_pSynthesizer->GetVoiceName (i); + if (sVoiceName.length() > 0) + line2 = std::to_string (ucVoice + 1) + "=" + sVoiceName; + } + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_KNOB, ucVoice, "Voice", line2.c_str()); +} + +void CMiniLab3DawConnection::SetEncoder (u8 ucChannel, u8 ucEncID, u8 ucValue) +{ + char line1[LINELEN]; + char line2[LINELEN]; + + CUIMenu::TCParameterInfo *encoder = &m_pEncoders[ucEncID]; + + if (encoder->Type == CUIMenu::ParameterNone) + return; + + int value = mapfloatr (ucValue, 0, 127, encoder->Min, encoder->Max); + u8 ucOP = encoder->OP ? encoder->OP - 1 : m_ucEncoderOP; + + // If we update the encoders during setup, we will get rounding problems, so disable it (not for faders) + if (ucEncID < nEncoder) + m_bDisableEncoderUpdate = true; + + u8 setted = false; + + if (encoder->Type == CUIMenu::ParameterGlobal) + { + m_pSynthesizer->SetParameter (static_cast(encoder->Parameter), value); + setted = true; + } + else + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0) + continue; + + if (m_ucEncoderTG && m_ucEncoderTG - 1u != i) + continue; + + if (m_ucEncoderTG == 0 && !encoder->ChG && !encoder->TG && + m_pKeyboard->GetChannel (i) != ucChannel && + m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode) + continue; + + if (encoder->ChG) + { + if (m_ChanGroups[encoder->ChG - 1u] == CMIDIDevice::Disabled) + continue; + + if (m_pKeyboard->GetChannel (i) != m_ChanGroups[encoder->ChG - 1u] && + m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode) + continue; + } + + if (encoder->TG && i != encoder->TG - 1u) + continue; + + switch (encoder->Type) + { + case CUIMenu::ParameterTG: + m_pSynthesizer->SetTGParameter (static_cast(encoder->Parameter), value, i); + break; + case CUIMenu::ParameterVoice: + m_pSynthesizer->SetVoiceParameter (encoder->Parameter, value, CMiniDexed::NoOP, i); + break; + case CUIMenu::ParameterOP: + for (unsigned j = 0; j < 6; ++j) + { + if (encoder->OP != AllOP && j != ucOP) + continue; + + m_pSynthesizer->SetVoiceParameter (encoder->Parameter, value, j, i); + } + break; + default: + break; + } + setted = true; + } + + m_bDisableEncoderUpdate = false; + + if (!setted) + return; + + if (encoder->ChG) + snprintf(line1, LINELEN, "Ch %d %s", m_ChanGroups[encoder->ChG - 1u] + 1, encoder->Name); + else if (encoder->TG) + snprintf(line1, LINELEN, "TG%d %s", encoder->TG, encoder->Name); + else + snprintf(line1, LINELEN, "%s", encoder->Name); + + if (encoder->ToString) + snprintf(line2, LINELEN, "%s", encoder->ToString(value, 0).c_str()); + else + snprintf(line2, LINELEN, "%d", value); + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, ucEncID < nEncoder ? CT_KNOB : CT_FADER, ucValue, line1, line2); +} + +void CMiniLab3DawConnection::ToggleMonoMode (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setMonoMode (ucValue, i); + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Mono Mode", ucValue > 64 ? "On" : "Off"); + UpdateMonoColor (); +} + +void CMiniLab3DawConnection::TogglePortamentoGlisssando (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setPortamentoGlissando (ucValue, i); + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Porta Gliss", ucValue > 64 ? "On" : "Off"); + UpdatePortamentoColor (); +} + +void CMiniLab3DawConnection::ToggleTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 value = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG) ? 0x00 : 0x7F; + + m_pSynthesizer->setEnabled (value, ucTG); + m_pSynthesizer->panic (value, ucTG); + + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, value, line1, value > 64 ? "On" : "Off"); +} + +void CMiniLab3DawConnection::SelectTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabledOne = true; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (i == ucTG) + continue; + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + enabledOne = false; + break; + } + } + + if (enabledOne) { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + m_pSynthesizer->setEnabled (true, i); + } + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, "TG All", "On"); + } else { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (i == ucTG) { + m_pSynthesizer->setEnabled (true, i); + } else { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } + } + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, line1, "Selected"); + } +} + + +void CMiniLab3DawConnection::SelectChanTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG); + u8 channel = m_pKeyboard->GetChannel (ucTG); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (m_pKeyboard->GetChannel (i) == channel) { + if (enabled) { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } else { + m_pSynthesizer->setEnabled (true, i); + } + } + } + + snprintf(line1, LINELEN, "TGs on Ch %s", to_midi_channel(channel).c_str()); + + // this doesn't work well with Minilab 3 firmware 1.2.0 + // ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, line1, enabled ? "Off" : "On"); + + DisplayWriteSimple (line1, "", enabled ? "Off" : "On"); +} + +class CKeyLabEs3DawConnection : public CDAWConnection +{ +public: + CKeyLabEs3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite ( const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + void UpdateEncoder (uint8_t ucEncID, uint8_t ucValue); + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + const uint8_t m_pEncoder[3] = {0x04, 0x01, 0x60}; + TMIDIRoute m_pRouteMap[26] = { + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 44, 0x7F, .bSkip=true}, // Home + {0, 0, MIDI_CONTROL_CHANGE, 44, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_HOME, 0}, + + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {0, 0, MIDI_CONTROL_CHANGE, 105, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {0, 0, MIDI_CONTROL_CHANGE, 106, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {0, 0, MIDI_CONTROL_CHANGE, 107, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {0, 0, MIDI_CONTROL_CHANGE, 108, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {0, 0, MIDI_CONTROL_CHANGE, 109, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {0, 0, MIDI_CONTROL_CHANGE, 110, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {0, 0, MIDI_CONTROL_CHANGE, 111, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {0, 0, MIDI_CONTROL_CHANGE, 112, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {0, 0, MIDI_CONTROL_CHANGE, 113, 0xFF, 8, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader9 + + {0, 0, MIDI_CONTROL_CHANGE, 96, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_FREQUENCY_CUTOFF, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 97, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_RESONANCE, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 98, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_EFFECT1_SEND, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 99, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_EFFECT2_SEND, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 100, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 101, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob6 + {0, 0, MIDI_CONTROL_CHANGE, 102, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO_TIME, 0xFF}, // Knob7 + // {0, 0, MIDI_CONTROL_CHANGE, 103, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob8 + // {0, 0, MIDI_CONTROL_CHANGE, 104, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob9 + {0xFF}, // Sentinel + }; +}; + +CKeyLabEs3DawConnection::CKeyLabEs3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7}; + + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab 3 Essential", 0, 0); + + UpdateState (); +} + +void CKeyLabEs3DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x01, 0x60, 0x12, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLabEs3DawConnection::UpdateEncoder (uint8_t ucEncID, uint8_t ucValue) +{ + uint8_t pUpdateEncoder[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x0F, 0x40, ucEncID += 3, ucValue, 0xF7}; + m_pKeyboard->Send (pUpdateEncoder, sizeof pUpdateEncoder, 0); +} + +void CKeyLabEs3DawConnection::UpdateState () +{ + UpdateEncoder (0, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterCutoff, 0), 0, 99, 0, 127)); + UpdateEncoder (1, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterResonance, 0), 0, 99, 0, 127)); + UpdateEncoder (2, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterFX1Send, 0), 0, 99, 0, 127)); + UpdateEncoder (3, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterFX2Send, 0), 0, 99, 0, 127)); + UpdateEncoder (4, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMasterTune, 0), -99, 99, 1, 127)); + UpdateEncoder (5, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPan, 0)); + UpdateEncoder (6, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoTime, 0), 0, 99, 0, 127)); +} + +void CKeyLabEs3DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + +} + +void CKeyLabEs3DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + ArturiaShowNewCCValue (m_pKeyboard, m_pEncoder, ucChannel, ucP1, ucP2); + break; + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + break; + } +} + +class CKeyLab2DawConnection : public CDAWConnection +{ +public: + CKeyLab2DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + using TToString = CUIMenu::TToString; + struct TButton { + uint8_t sysexID; + const char* name; + uint8_t last_value; + }; + struct TRGBButton { + uint8_t sysexID; + CColor last_color = invalidColor; + }; + + bool m_bDisableStateUpdate = false; + + TButton m_MonoButton = {0x60, "Mono mode"}; + TButton m_PortamentoButton = {0x61, "Portamento"}; + TButton m_SostenutoButton = {0x62, "Sostenuto"}; + TButton m_SustainButton = {0x63, "Sustain"}; + TButton m_Hold2Button = {0x64, "Hold"}; + + TRGBButton m_SelButtons[8] = { + {0x22}, {0x23}, {0x24}, {0x25}, {0x26}, {0x27}, {0x28}, {0x29}, + }; + + static void s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext); + void QueueUpdateDisplay (unsigned msec); + void UpdateDisplay (); + void ShowNewValue (const char* name, u8 ucP2, TToString *ToString = NULL); + + void SetButtonColor (TRGBButton &button, CColor color); + + void SetButtonIntensity (TButton &button, uint8_t intensity); + void SetButtonLight (TButton &button, u8 state); + void SetButtonLight (TButton &button, u8 state, u8 state2); + + void UpdateVolumeFaders (); + void UpdateTGColors (); + void UpdateMonoColor (); + void UpdatePortamentoColor (); + void SetMasterVolume (u8 ucValue); + int SetParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TParameter parameter); + int SetTGParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TTGParameter parameter); + + void ToggleMonoMode (u8 ucChannel); + void TogglePortamentoGlisssando (u8 ucChannel); + + void ToggleTG (u8 ucTG); + void SelectTG (u8 ucTG); + + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + TKernelTimerHandle m_DisplayTimer = 0; + + u8 m_ucFirstTG = 0; + + TMIDIRoute m_pRouteMap[58] = { + {1, 0, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {1, 1, MIDI_PITCH_BEND, 0xFF, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {1, 2, MIDI_PITCH_BEND, 0xFF, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {1, 3, MIDI_PITCH_BEND, 0xFF, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {1, 4, MIDI_PITCH_BEND, 0xFF, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {1, 5, MIDI_PITCH_BEND, 0xFF, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {1, 6, MIDI_PITCH_BEND, 0xFF, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {1, 7, MIDI_PITCH_BEND, 0xFF, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {1, 8, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_MASTER_VOLUME, 0xFF}, // Fader9 + + {1, 0, MIDI_NOTE_ON, 0x54, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + //{1, 0, MIDI_NOTE_ON, 0x31, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Next + //{1, 0, MIDI_NOTE_ON, 0x30, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Prev + //{1, 0, MIDI_NOTE_ON, 0x21, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Bank? + + {1, 0, MIDI_NOTE_ON, 0x18, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select1 + {1, 0, MIDI_NOTE_ON, 0x18, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x18, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 0, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x19, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select2 + {1, 0, MIDI_NOTE_ON, 0x19, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 1, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x19, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 1, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1a, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select3 + {1, 0, MIDI_NOTE_ON, 0x1a, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 2, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1a, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 2, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1b, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select4 + {1, 0, MIDI_NOTE_ON, 0x1b, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 3, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1b, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 3, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1c, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select5 + {1, 0, MIDI_NOTE_ON, 0x1c, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 4, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1c, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 4, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1d, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select6 + {1, 0, MIDI_NOTE_ON, 0x1d, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 5, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1d, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 5, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1e, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select7 + {1, 0, MIDI_NOTE_ON, 0x1e, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 6, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1e, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 6, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1f, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select8 + {1, 0, MIDI_NOTE_ON, 0x1f, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 7, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1f, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 7, .bGroup=true}, + + //{1, 0, MIDI_NOTE_ON, 0x33, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Select9? + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw08n15, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_MONO, 0x7f}, // Solo + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Mute + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO, 0x7F, .bToggle=true, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_PORTA_GLISS, 0x7F, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw00n07, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SOSTENUTO, 0x7F, .bToggle=true}, // Record + + {1, 0, MIDI_NOTE_ON, 0x4a, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SUSTAIN, 0x7F, .bToggle=true}, // Read + + {1, 0, MIDI_NOTE_ON, 0x4b, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_HOLD2, 0x7F, .bToggle=true}, // Write + + {1, 0, MIDI_CONTROL_CHANGE, 16, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_0, 0xFF}, // Knob1 + {1, 0, MIDI_CONTROL_CHANGE, 17, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_1, 0xFF}, // Knob2 + {1, 0, MIDI_CONTROL_CHANGE, 18, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_2, 0xFF}, // Knob3 + {1, 0, MIDI_CONTROL_CHANGE, 19, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_3, 0xFF}, // Knob4 + {1, 0, MIDI_CONTROL_CHANGE, 20, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_4, 0xFF}, // Knob5 + {1, 0, MIDI_CONTROL_CHANGE, 21, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_5, 0xFF}, // Knob6 + {1, 0, MIDI_CONTROL_CHANGE, 22, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_6, 0xFF}, // Knob7 + {1, 0, MIDI_CONTROL_CHANGE, 23, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_7, 0xFF}, // Knob8 + {1, 0, MIDI_CONTROL_CHANGE, 24, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_8, 0xFF}, // Knob9 + {1, 0xFF, 0xFF, 0xFF, 0xFF, .bSkip = true}, // skip other messages on DAW cable + {0xFF}, // Sentinel + }; +}; + +/* +https://github.com/bitwig/bitwig-extensions/blob/da7d70e73cc055475d63ac6c7de17e69f89f4993/src/main/java/com/bitwig/extensions/controllers/arturia/keylab/mk2/ButtonId.java +SOLO(0x60, 0x08), +MUTE(0x61, 0x10), +RECORD_ARM(0x62, 0x00), +READ(0x63, 0x38), // 0x38 -> 0x4a +WRITE(0x64, 0x39), // 0x39 -> 0x4b + +SAVE(0x65,0x4A), +PUNCH_IN(0x66, 0x57), +PUNCH_OUT(0x67, 0x58), +METRO(0x68, 0x59), +UNDO(0x69, 0x51), + + +NEXT(0x1F, 0x31), +PREVIOUS(0x20, 0x30), +BANK(0x21, 0x21), +SELECT1(0x22, 0x18), +SELECT2(0x23, 0x19), +SELECT3(0x24, 0x1A), +SELECT4(0x25, 0x1B), +SELECT5(0x26, 0x1C), +SELECT6(0x27, 0x1D), +SELECT7(0x28, 0x1E), +SELECT8(0x29, 0x1F), +SELECT_MULTI(0x2A, 0x33); +*/ + +CKeyLab2DawConnection::CKeyLab2DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x52, 0x00, 0xF7}; + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab 2", 0, 0); + + SetButtonLight (m_SostenutoButton, 0); + SetButtonLight (m_SustainButton, 0); + SetButtonLight (m_Hold2Button, 0); + + UpdateState (); + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +void CKeyLab2DawConnection::SetButtonColor (TRGBButton &button, CColor color) +{ + const uint8_t pSetButtonColor[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x16, button.sysexID, color.r, color.g, color.b, 0xF7}; + m_pKeyboard->Send (pSetButtonColor, sizeof pSetButtonColor, 0); +} + +void CKeyLab2DawConnection::SetButtonIntensity (TButton &button, uint8_t intensity) +{ + if (button.last_value == intensity) + return; + + const uint8_t pSetButtonIntensity[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x10, button.sysexID, intensity, 0xF7}; + m_pKeyboard->Send (pSetButtonIntensity, sizeof pSetButtonIntensity, 0); + + button.last_value = intensity; +} + +void CKeyLab2DawConnection::SetButtonLight (TButton &button, u8 state) +{ + SetButtonIntensity (button, state ? 0x7F : 0x04); +} + +void CKeyLab2DawConnection::SetButtonLight (TButton &button, u8 state, u8 state2) +{ + SetButtonIntensity (button, state ? state2 ? 0x7F : 0x3f : 0x04); +} + +void CKeyLab2DawConnection::UpdateTGColors () +{ + bool need_update = false; + CColor colors[8]; + uint8_t numTG = std::min(m_pConfig->GetToneGenerators(), 8u); + + for (unsigned i = 0; i < numTG; ++i) + { + u8 ch = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i); + + colors[i] = chColors_kl2[ch]; + if (!enabled) + { + colors[i].r /= 8; + colors[i].g /= 8; + colors[i].b /= 8; + } + + if (m_SelButtons[i].last_color != colors[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < numTG; ++i) + { + SetButtonColor (m_SelButtons[i], colors[i]); + m_SelButtons[i].last_color = colors[i]; + } +} + + +void CKeyLab2DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x00, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 16, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLab2DawConnection::QueueUpdateDisplay (unsigned msec) +{ + if (m_DisplayTimer) + CTimer::Get ()->CancelKernelTimer (m_DisplayTimer); + m_DisplayTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (msec), s_UpdateDisplay, this, NULL); +} + +void CKeyLab2DawConnection::s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + assert (pParam != NULL); + static_cast(pParam)->UpdateDisplay (); +} + +void CKeyLab2DawConnection::UpdateDisplay () +{ + m_pUI->MIDIEventHandler (CUIMenu::MenuEventUpdate); +} + +void CKeyLab2DawConnection::ShowNewValue (const char* name, u8 ucP2, CUIMenu::TToString *ToString) +{ + std::string line2 = ToString ? ToString(ucP2, 0) : std::to_string(ucP2); + DisplayWrite (name, "", line2.c_str(), 0, 0); +} + +void CKeyLab2DawConnection::UpdateState () +{ + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + u8 ucChannel = m_pKeyboard->GetChannel (i); + + if (ucChannel == CMIDIDevice::ChannelUnknown || ucChannel == CMIDIDevice::Disabled) + continue; + + if (ucChannel == CMIDIDevice::OmniMode) + ucChannel = 0; + + for (TMIDIRoute *r = m_pRouteMap; r->ucSCable != 0xFF; r++) + r->ucDCh = ucChannel; + + m_ucFirstTG = i; + + break; + } + + UpdateVolumeFaders (); + + if (m_bDisableStateUpdate) + return; + + UpdateTGColors (); + UpdateMonoColor (); + UpdatePortamentoColor (); +} + +void CKeyLab2DawConnection::UpdateVolumeFaders () +{ + u8 chan_map[8] = { + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + }; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + int channel = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + + if (channel == CMIDIDevice::ChannelUnknown || channel == CMIDIDevice::Disabled) + continue; + + if (channel == CMIDIDevice::OmniMode) + channel = 0; + + for (unsigned i = 0; i < sizeof chan_map; ++i) + { + if (chan_map[i] == channel) + break; + + if (chan_map[i] == CMIDIDevice::Disabled) { + chan_map[i] = channel; + break; + } + } + } + + for (unsigned i = 0; i < sizeof chan_map; ++i) + { + if (chan_map[i] == CMIDIDevice::Disabled) + m_pRouteMap[i].bSkip = true; + else { + m_pRouteMap[i].bSkip = false; + m_pRouteMap[i].ucDCh = chan_map[i]; + } + } +} + +void CKeyLab2DawConnection::ToggleTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 value = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG) ? 0x00 : 0x7F; + + m_pSynthesizer->setEnabled (value, ucTG); + m_pSynthesizer->panic (value, ucTG); + + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ShowNewValue (line1, value, to_on_off); +} + +void CKeyLab2DawConnection::SelectTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabledOne = true; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (i == ucTG) + continue; + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + enabledOne = false; + break; + } + } + + m_bDisableStateUpdate = true; + + if (enabledOne) { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + m_pSynthesizer->setEnabled (true, i); + } + ShowNewValue ("TG All", 0x7f, to_on_off); + } else { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (i == ucTG) { + m_pSynthesizer->setEnabled (true, i); + } else { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } + } + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ShowNewValue (line1, 0x7f, to_selected); + } + + m_bDisableStateUpdate = false; + UpdateState (); +} + +void CKeyLab2DawConnection::ToggleMonoMode (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setMonoMode (ucValue, i); + } + + ShowNewValue ("Mono Mode", ucValue, to_on_off); +} + +void CKeyLab2DawConnection::SetMasterVolume (u8 ucValue) +{ + m_pSynthesizer->SetParameter (CMiniDexed::ParameterMasterVolume, ucValue); + ShowNewValue ("Master Volume", ucValue, to_percent); +} + +int CKeyLab2DawConnection::SetParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TParameter parameter) +{ + int ucValue = m_pSynthesizer->GetParameter (parameter); + + if (ucDiffValue < 64) // 1 2 3 + ucValue += ucDiffValue; + else // 65 66 67 + ucValue = std::max(0, ucValue - (ucDiffValue - 64)); + + m_pSynthesizer->SetParameter (parameter, ucValue); + + return m_pSynthesizer->GetParameter (parameter); +} + +int CKeyLab2DawConnection::SetTGParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TTGParameter parameter) +{ + int ucValue = m_pSynthesizer->GetTGParameter (parameter, m_ucFirstTG); + + if (ucDiffValue < 64) // 1 2 3 + ucValue += ucDiffValue; + else // 65 66 67 + ucValue = std::max(0, ucValue - (ucDiffValue - 64)); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->SetTGParameter (parameter, ucValue, i); + } + + return m_pSynthesizer->GetTGParameter (parameter, m_ucFirstTG); +} + +void CKeyLab2DawConnection::UpdateMonoColor () +{ + SetButtonLight (m_MonoButton, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG)); +} + +void CKeyLab2DawConnection::UpdatePortamentoColor () +{ + u8 mode = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoMode, m_ucFirstTG); + u8 mode2 = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG); + SetButtonLight (m_PortamentoButton, mode, mode2); +} + +void CKeyLab2DawConnection::TogglePortamentoGlisssando (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setPortamentoGlissando (ucValue, i); + } + + ShowNewValue ("Porta Gliss", ucValue, to_on_off); + UpdatePortamentoColor (); +} + + +void CKeyLab2DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ +} + +void CKeyLab2DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + int ucValue; + + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + switch (ucP1) + { + case MIDI_CC_VOLUME: + char line1[LINELEN]; + snprintf(line1, LINELEN, "Volume Ch %d", ucChannel + 1); + ShowNewValue (line1, ucP2, to_percent); + break; + case MIDI_CC_PORTAMENTO: + UpdatePortamentoColor (); + ShowNewValue (m_PortamentoButton.name, ucP2, to_on_off); + break; + case MIDI_CC_SOSTENUTO: + SetButtonLight (m_SostenutoButton, ucP2); + ShowNewValue (m_SostenutoButton.name, ucP2, to_on_off); + break; + case MIDI_CC_HOLD2: + SetButtonLight (m_Hold2Button, ucP2); + ShowNewValue (m_Hold2Button.name, ucP2, to_on_off); + break; + case MIDI_CC_SUSTAIN: + SetButtonLight (m_SustainButton, ucP2); + ShowNewValue (m_SustainButton.name, ucP2, to_on_off); + break; + } + break; + + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + + switch (ucP1) + { + case MIDI_DAW_TOGGLE_MONO: + ToggleMonoMode (ucChannel); + break; + case MIDI_DAW_TOGGLE_PORTA_GLISS: + TogglePortamentoGlisssando (ucChannel); + break; + case MIDI_DAW_SELECT_TG: + SelectTG (ucP2); + break; + case MIDI_DAW_TOGGLE_TG: + ToggleTG (ucP2); + break; + case MIDI_DAW_MASTER_VOLUME: + SetMasterVolume (ucP2); + break; + case MIDI_DAW_ENC_0: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterCutoff); + ShowNewValue ("Cutoff", ucValue, to_string); + break; + case MIDI_DAW_ENC_1: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterResonance); + ShowNewValue ("Resonance", ucValue, to_string); + break; + case MIDI_DAW_ENC_2: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterPortamentoTime); + ShowNewValue ("Portamento time", ucValue, to_string); + break; + case MIDI_DAW_ENC_5: + ucValue = SetParameter(ucChannel, ucP2, CMiniDexed::ParameterMixerDryLevel); + ShowNewValue ("Dry Level", ucValue, to_string); + break; + case MIDI_DAW_ENC_6: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterFX1Send); + ShowNewValue ("FX1Send", ucValue, to_string); + break; + case MIDI_DAW_ENC_7: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterFX2Send); + ShowNewValue ("FX2Send", ucValue, to_string); + break; + } + break; + } + + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +class CKeyLabEsDawConnection : public CDAWConnection +{ +public: + CKeyLabEsDawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + TMIDIRoute m_pRouteMap[18] = { + {1, 0, MIDI_NOTE_ON, 0x54, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {1, 0, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {1, 1, MIDI_PITCH_BEND, 0xFF, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {1, 2, MIDI_PITCH_BEND, 0xFF, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {1, 3, MIDI_PITCH_BEND, 0xFF, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {1, 4, MIDI_PITCH_BEND, 0xFF, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {1, 5, MIDI_PITCH_BEND, 0xFF, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {1, 6, MIDI_PITCH_BEND, 0xFF, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {1, 7, MIDI_PITCH_BEND, 0xFF, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {1, 8, MIDI_PITCH_BEND, 0xFF, 0xFF, 8, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader9 + /*{0, 0, MIDI_CONTROL_CHANGE, 96, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_FREQUENCY_CUTOFF, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 97, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_RESONANCE, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 98, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_REVERB_LEVEL, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 99, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 100, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 101, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO_TIME, 0xFF}, // Knob6 + // {0, 0, MIDI_CONTROL_CHANGE, 102, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob7 + // {0, 0, MIDI_CONTROL_CHANGE, 103, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob8 + // {0, 0, MIDI_CONTROL_CHANGE, 104, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob9*/ + {1, 0xFF, 0xFF, 0xFF, 0xFF, .bSkip = true}, // skip other messages on DAW cable + {0xFF}, // Sentinel + }; +}; + +CKeyLabEsDawConnection::CKeyLabEsDawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x51, 0x00, 0xF7}; // init DAW to Mackie mode + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab Essential", 0, 0); + + UpdateState (); +} + +void CKeyLabEsDawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x00, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 16, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLabEsDawConnection::UpdateState () +{ +} + +void CKeyLabEsDawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ +} + +void CKeyLabEsDawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + //static const uint8_t pEncoder[] = {0x04, 0x01, 0x60}; + //ArturiaShowNewCCValue (pKeyboard, pEncoder, ucCh, ucCC, ucValue); + switch (ucType) + { + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + break; + } +} + +CDAWController::CDAWController (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) +: m_pSynthesizer (pSynthesizer), + m_pKeyboard (pKeyboard), + m_pConfig (pConfig), + m_pUI (pUI), + m_pDAWConnection (0) +{ +} + +CDAWController::~CDAWController (void) +{ + delete m_pDAWConnection; +} + +void CDAWController::OnConnect (void) +{ + static const uint8_t inquiry[] = {0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7}; + + delete m_pDAWConnection; + m_pDAWConnection = 0; + + m_pKeyboard->Send (inquiry, sizeof inquiry, 0); +} + +void CDAWController::MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable) +{ + static const uint8_t pMiniLab3[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x04, 0x04}; + static const uint8_t pKeyLabEs_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x52}; + static const uint8_t pKeyLabEs_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x54}; + static const uint8_t pKeyLabEs_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x58}; + static const uint8_t pKeyLab2_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x62}; + static const uint8_t pKeyLab2_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x64}; + static const uint8_t pKeyLab2_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x68}; + static const uint8_t pKeyLabEs3_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x72}; + static const uint8_t pKeyLabEs3_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x74}; + static const uint8_t pKeyLabEs3_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x78}; + + if (nLength > sizeof pMiniLab3 && memcmp (pPacket, pMiniLab3, sizeof pMiniLab3) == 0) + { + m_pDAWConnection = new CMiniLab3DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLabEs_49 && ( + memcmp (pPacket, pKeyLabEs_49, sizeof pKeyLabEs_49) == 0 || + memcmp (pPacket, pKeyLabEs_61, sizeof pKeyLabEs_61) == 0 || + memcmp (pPacket, pKeyLabEs_88, sizeof pKeyLabEs_88) == 0)) + { + m_pDAWConnection = new CKeyLabEsDawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLab2_61 && ( + memcmp (pPacket, pKeyLab2_49, sizeof pKeyLab2_49) == 0 || + memcmp (pPacket, pKeyLab2_61, sizeof pKeyLab2_61) == 0 || + memcmp (pPacket, pKeyLab2_88, sizeof pKeyLab2_88) == 0)) + { + m_pDAWConnection = new CKeyLab2DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLabEs3_49 && ( + memcmp (pPacket, pKeyLabEs3_49, sizeof pKeyLabEs3_49) == 0 || + memcmp (pPacket, pKeyLabEs3_61, sizeof pKeyLabEs3_61) == 0 || + memcmp (pPacket, pKeyLabEs3_88, sizeof pKeyLabEs3_88) == 0)) + { + m_pDAWConnection = new CKeyLabEs3DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } +} + +void CDAWController::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + if (m_pDAWConnection) + m_pDAWConnection->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); +} + +void CDAWController::UpdateState (void) +{ + if (m_pDAWConnection) + m_pDAWConnection->UpdateState (); +} + +void CDAWController::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + if (m_pDAWConnection) + m_pDAWConnection->UpdateMenu (Type, ucPage, ucOP, ucTG); +} + +void CDAWController::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + if (m_pDAWConnection) + m_pDAWConnection->MIDIListener (ucCable, ucChannel, ucType, ucP1, ucP2); +} diff --git a/src/dawcontroller.h b/src/dawcontroller.h new file mode 100644 index 000000000..0b1f00511 --- /dev/null +++ b/src/dawcontroller.h @@ -0,0 +1,54 @@ +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2024 The MiniDexed Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +#ifndef _dawcontroller_h +#define _dawcontroller_h + +#include +#include "uimenu.h" + +class CMIDIKeyboard; +class CMiniDexed; +class CDAWConnection; +class CConfig; +class CUserInterface; + +class CDAWController +{ +public: + CDAWController (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + ~CDAWController (void); + + void OnConnect (void); + void MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable); + + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateState (void); + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); + + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2); + +private: + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + CDAWConnection *m_pDAWConnection; +}; + +#endif diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 7f141db86..a298ce990 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -22,6 +22,7 @@ // #include +#include #include "mididevice.h" #include "minidexed.h" #include "config.h" @@ -57,7 +58,8 @@ CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap; CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI) : m_pSynthesizer (pSynthesizer), m_pConfig (pConfig), - m_pUI (pUI) + m_pUI (pUI), + m_pRouteMap () { for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { @@ -209,14 +211,25 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_MIDISpinLock.Acquire (); + u8 ucCable = nCable; u8 ucStatus = pMessage[0]; u8 ucChannel = ucStatus & 0x0F; u8 ucType = ucStatus >> 4; + u8 ucP1 = pMessage[1]; + u8 ucP2 = nLength >= 3 ? pMessage[2] : 0xFF; + bool bSkip = false; + if (m_pRouteMap) + GetRoutedMIDI (m_pRouteMap, this, &ucCable, &ucChannel, &ucType, &ucP1, &ucP2, &bSkip); + + if (bSkip) + { + // skip (and release mutex at the end) + } // GLOBAL MIDI SYSEX // Set MIDI Channel for TX816/TX216 SysEx; in MiniDexed, we interpret the device parameter as the number of the TG (unlike the TX816/TX216 which has a hardware switch to select the TG) - if (nLength == 7 && + else if (nLength == 7 && pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[1] == 0x43 && // pMessage[2] & 0x0F = TG number @@ -272,13 +285,13 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) { - if (pMessage[1] == MIDI_CC_BANK_SELECT_MSB) + if (ucP1 == MIDI_CC_BANK_SELECT_MSB) { - m_pSynthesizer->BankSelectMSBPerformance (pMessage[2]); + m_pSynthesizer->BankSelectMSBPerformance (ucP2); } - else if (pMessage[1] == MIDI_CC_BANK_SELECT_LSB) + else if (ucP1 == MIDI_CC_BANK_SELECT_LSB) { - m_pSynthesizer->BankSelectLSBPerformance (pMessage[2]); + m_pSynthesizer->BankSelectLSBPerformance (ucP2); } else { @@ -300,7 +313,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } if (nLength == 3) { - m_pUI->UIMIDICmdHandler (ucChannel, ucType, pMessage[1], pMessage[2]); + m_pUI->UIMIDICmdHandler (ucChannel, ucType, ucP1, ucP2); } break; @@ -310,7 +323,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { break; } - m_pUI->UIMIDICmdHandler (ucChannel, ucType, pMessage[1], pMessage[2]); + m_pUI->UIMIDICmdHandler (ucChannel, ucType, ucP1, ucP2); break; case MIDI_PROGRAM_CHANGE: @@ -322,7 +335,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) { //printf("Performance Select Channel %d\n", nPerfCh); - m_pSynthesizer->ProgramChangePerformance (pMessage[1]); + m_pSynthesizer->ProgramChangePerformance (ucP1); } } } @@ -474,17 +487,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - if (pMessage[2] > 0) + if (ucP2 > 0) { - if (pMessage[2] <= 127) + if (ucP2 <= 127) { - m_pSynthesizer->keydown (pMessage[1], - pMessage[2], nTG); + m_pSynthesizer->keydown (ucP1, + ucP2, nTG); } } else { - m_pSynthesizer->keyup (pMessage[1], nTG); + m_pSynthesizer->keyup (ucP1, nTG); } break; @@ -494,12 +507,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - m_pSynthesizer->keyup (pMessage[1], nTG); + m_pSynthesizer->keyup (ucP1, nTG); break; case MIDI_CHANNEL_AFTERTOUCH: - m_pSynthesizer->setAftertouch (pMessage[1], nTG); + m_pSynthesizer->setAftertouch (ucP1, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; @@ -509,36 +522,36 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - switch (pMessage[1]) + switch (ucP1) { case MIDI_CC_MODULATION: - m_pSynthesizer->setModWheel (pMessage[2], nTG); + m_pSynthesizer->setModWheel (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_FOOT_PEDAL: - m_pSynthesizer->setFootController (pMessage[2], nTG); + m_pSynthesizer->setFootController (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_PORTAMENTO_TIME: - m_pSynthesizer->setPortamentoTime (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->setPortamentoTime (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_BREATH_CONTROLLER: - m_pSynthesizer->setBreathController (pMessage[2], nTG); + m_pSynthesizer->setBreathController (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_VOLUME: - m_pSynthesizer->SetVolume (pMessage[2], nTG); + m_pSynthesizer->SetVolume (ucP2, nTG); break; case MIDI_CC_PAN_POSITION: if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) break; - m_pSynthesizer->SetPan (pMessage[2], nTG); + m_pSynthesizer->SetPan (ucP2, nTG); break; case MIDI_CC_EXPRESSION: @@ -549,50 +562,50 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case MIDI_CC_BANK_SELECT_MSB: - m_pSynthesizer->BankSelectMSB (pMessage[2], nTG); + m_pSynthesizer->BankSelectMSB (ucP2, nTG); break; case MIDI_CC_BANK_SELECT_LSB: - m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); + m_pSynthesizer->BankSelectLSB (ucP2, nTG); break; case MIDI_CC_SUSTAIN: - m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); + m_pSynthesizer->setSustain (ucP2 >= 64, nTG); break; case MIDI_CC_SOSTENUTO: - m_pSynthesizer->setSostenuto (pMessage[2] >= 64, nTG); + m_pSynthesizer->setSostenuto (ucP2 >= 64, nTG); break; case MIDI_CC_PORTAMENTO: - m_pSynthesizer->setPortamentoMode (pMessage[2] >= 64, nTG); + m_pSynthesizer->setPortamentoMode (ucP2 >= 64, nTG); break; case MIDI_CC_HOLD2: - m_pSynthesizer->setHoldMode (pMessage[2] >= 64, nTG); + m_pSynthesizer->setHoldMode (ucP2 >= 64, nTG); break; case MIDI_CC_RESONANCE: - m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetResonance (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_FREQUENCY_CUTOFF: - m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetCutoff (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_EFFECT1_SEND: - m_pSynthesizer->SetFX1Send (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetFX1Send (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_EFFECT2_SEND: - m_pSynthesizer->SetFX2Send (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetFX2Send (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_DETUNE_LEVEL: if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) break; - if (pMessage[2] == 0) + if (ucP2 == 0) { // 0 to 127, with 0 being no detune effect applied at all m_pSynthesizer->SetMasterTune (0, nTG); @@ -600,12 +613,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign else { // Scale to -99 to +99 cents - m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG); + m_pSynthesizer->SetMasterTune (maplong (ucP2, 1, 127, -99, 99), nTG); } break; case MIDI_CC_ALL_SOUND_OFF: - m_pSynthesizer->panic (pMessage[2], nTG); + m_pSynthesizer->panic (ucP2, nTG); break; case MIDI_CC_ALL_NOTES_OFF: @@ -614,7 +627,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // "Receivers should ignore an All Notes Off message while Omni is on (Modes 1 & 2)" if (!m_pConfig->GetIgnoreAllNotesOff () && m_ChannelMap[nTG] != OmniMode) { - m_pSynthesizer->notesOff (pMessage[2], nTG); + m_pSynthesizer->notesOff (ucP2, nTG); } break; @@ -653,7 +666,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // so it is possible to break out of the main TG loop too. // Note: We handle this here so we get the TG MIDI channel checking. if (!bSystemCCChecked) { - bSystemCCHandled = HandleMIDISystemCC(pMessage[1], pMessage[2]); + bSystemCCHandled = HandleMIDISystemCC(ucP1, ucP2); bSystemCCChecked = true; } break; @@ -664,7 +677,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // do program change only if enabled in config and not in "Performance Select Channel" mode if( m_pConfig->GetMIDIRXProgramChange() && ( m_pSynthesizer->GetPerformanceSelectChannel() == Disabled) ) { //printf("Program Change to %d (%d)\n", ucChannel, m_pSynthesizer->GetPerformanceSelectChannel()); - m_pSynthesizer->ProgramChange (pMessage[1], nTG); + m_pSynthesizer->ProgramChange (ucP1, nTG); } break; @@ -674,8 +687,8 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - s16 nValue = pMessage[1]; - nValue |= (s16) pMessage[2] << 7; + s16 nValue = ucP1; + nValue |= (s16) ucP2 << 7; nValue -= 0x2000; m_pSynthesizer->setPitchbend (nValue, nTG); @@ -687,6 +700,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } } + + if (m_pRouteMap) + MIDIListener(ucCable, ucChannel, ucType, ucP1, ucP2); } m_MIDISpinLock.Release (); } @@ -750,6 +766,11 @@ bool CMIDIDevice::HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval) return false; } +void CMIDIDevice::SetRouteMap (TMIDIRoute *pRouteMap) +{ + m_pRouteMap = pRouteMap; +} + void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG) { @@ -859,3 +880,102 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const std::string& de LOGWARN("No device found in s_DeviceMap for name: %s", deviceName.c_str()); } } + +void CMIDIDevice::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ +} + +void CMIDIDevice::s_HandleTimerTimeout(TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + CMIDIDevice *pDevice = static_cast(pParam); + TMIDIRoute *pRoute = static_cast(pContext); + TMIDIRoute *pTarget = pRoute + pRoute->ucTimerTarget; + + pRoute->hTimer = 0; + pRoute->bGroupActive = false; + pRoute->bGroupHold = false; + if (!pTarget->bSkip) + pDevice->MIDIListener (pTarget->ucSCable, pTarget->ucDCh, pTarget->ucDType, pTarget->ucDP1, pTarget->ucDP2); +} + +static bool RouteMatch (u8 ucSP, u8 ucP) +{ + return ucSP == ucP || + ucSP == 0xFF || + ucSP == TMIDIRoute::LtCenter && ucP < 64 || + ucSP == TMIDIRoute::GtCenter && ucP > 64 || + ucSP == TMIDIRoute::Betw00n07 && ucP >= 0 && ucP <= 7 || + ucSP == TMIDIRoute::Betw08n15 && ucP >= 8 && ucP <= 15 || + ucSP == TMIDIRoute::Betw16n23 && ucP >= 16 && ucP <= 23; +} + +void GetRoutedMIDI (TMIDIRoute *pRouteMap, CMIDIDevice *pDevice, u8 *pCable, u8 *pCh, u8 *pType, u8 *pP1, u8 *pP2, bool *bSkip) +{ + assert (pRouteMap); + for (TMIDIRoute *r = pRouteMap; r->ucSCable != 0xFF ; r++) + { + if (r->ucSCable == *pCable && + (r->ucSCh == *pCh || r->ucSCh >= 16) && + (r->ucSType == *pType || r->ucSType >= 16) && + RouteMatch (r->ucSP1, *pP1) && + RouteMatch (r->ucSP2, *pP2) + ) + { + if (r->usTimerExpire) + r->hTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ(r->usTimerExpire), CMIDIDevice::s_HandleTimerTimeout, pDevice, r); + + if (r->usTimerExpire || r->bGroupHead) + r->bGroupActive = true; + + if (r->bSkip) { + *bSkip = true; + return; + } + + if (r->bGroup) { + TMIDIRoute *parent = r - 1; + for (; parent > pRouteMap && parent->bGroup; parent--); + + if (parent->hTimer) { + CTimer::Get ()->CancelKernelTimer (parent->hTimer); + parent->hTimer = 0; + } + + if (!r->bGroupHold) + parent->bGroupHold = false; + + if (!parent->bGroupActive && !parent->bGroupHold) { + // skip at the end if not captured by other routes + *bSkip = true; + continue; + } + + // hold the group for bGroupHold routes + if (r->bGroupHold) + parent->bGroupHold = true; + + parent->bGroupActive = false; + } + + *pCh = r->ucDCh; + *pType = r->ucDType; + if (r->ucDP1 <= 127) + *pP1 = r->ucDP1; + if (r->ucDP1 == TMIDIRoute::P2) + *pP1 = *pP2; + if (r->ucDP2 <= 127) + *pP2 = r->ucDP2; + if (r->bToggle) + r->ucDP2 = r->ucDP2 ? 0x0 : 0x7F; + *bSkip = false; + return; + } + } +} + +TMIDIRoute::~TMIDIRoute () +{ + if (hTimer) + CTimer::Get ()->CancelKernelTimer (hTimer); + hTimer = 0; +} diff --git a/src/mididevice.h b/src/mididevice.h index 7da871783..f76f70bd9 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -34,6 +34,43 @@ #define MAX_MIDI_MESSAGE MAX_DX7_SYSEX_LENGTH class CMiniDexed; +class CMIDIDevice; + +struct TMIDIRoute +{ + ~TMIDIRoute (); + + enum TRouteOP + { + P2 = 0x82, + LtCenter = 0x90, + GtCenter = 0x91, + Betw00n07 = 0x92, + Betw08n15 = 0x93, + Betw16n23 = 0x94 + }; + + u8 ucSCable; + u8 ucSCh; + u8 ucSType; + u8 ucSP1; + u8 ucSP2; + u8 ucDCh; + u8 ucDType; + u8 ucDP1; + u8 ucDP2; + u8 ucTimerTarget; + unsigned usTimerExpire; + TKernelTimerHandle hTimer; + bool bSkip; + bool bToggle; + bool bGroup; + bool bGroupHead; + bool bGroupActive; + bool bGroupHold; // hold flag for GroupHeads, or set hold the group +}; + +void GetRoutedMIDI (TMIDIRoute *pRouteMap, CMIDIDevice *pDevice, u8 *pCable, u8 *pChannel, u8 *pType, u8 *pP1, u8 *pP2, bool *bSkip); class CMIDIDevice { @@ -53,16 +90,22 @@ class CMIDIDevice void SetChannel (u8 ucChannel, unsigned nTG); u8 GetChannel (unsigned nTG) const; + void SetRouteMap (TMIDIRoute *pRouteMap); + virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {} // Change signature to specify device name void SendSystemExclusiveVoice(uint8_t nVoice, const std::string& deviceName, unsigned nCable, uint8_t nTG); const std::string& GetDeviceName() const { return m_DeviceName; } + static void s_HandleTimerTimeout(TKernelTimerHandle hTimer, void *pParam, void *pContext); + protected: void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void AddDevice (const char *pDeviceName); void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG); + virtual void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2); + private: bool HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval); @@ -82,6 +125,8 @@ class CMIDIDevice std::string m_DeviceName; + TMIDIRoute *m_pRouteMap; + typedef std::unordered_map TDeviceMap; static TDeviceMap s_DeviceMap; diff --git a/src/midikeyboard.cpp b/src/midikeyboard.cpp index db71168d1..274741896 100644 --- a/src/midikeyboard.cpp +++ b/src/midikeyboard.cpp @@ -25,19 +25,26 @@ #include #include +#define DISPLAY_REFRESH_RATE_US 25000 + CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI, unsigned nInstance) : CMIDIDevice (pSynthesizer, pConfig, pUI), m_nSysExIdx (0), m_nInstance (nInstance), - m_pMIDIDevice (0) + m_pMIDIDevice (0), + m_pDAWController (0) { m_DeviceName.Format ("umidi%u", nInstance+1); AddDevice (m_DeviceName); + + if (pConfig->GetDAWControllerEnabled ()) + m_pDAWController = new CDAWController (pSynthesizer, this, pConfig, pUI); } CMIDIKeyboard::~CMIDIKeyboard (void) { + delete m_pDAWController; } void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) @@ -55,6 +62,15 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) delete [] Entry.pMessage; } + unsigned time = CTimer::GetClockTicks (); + unsigned diff = time - m_LastDisplayRefreshTime; + if (m_LastDisplayEntry.nLength && diff > DISPLAY_REFRESH_RATE_US) + { + m_pMIDIDevice->SendPlainMIDI (m_LastDisplayEntry.nCable, m_LastDisplayEntry.pMessage, m_LastDisplayEntry.nLength); + m_LastDisplayEntry.nLength = 0; + m_LastDisplayRefreshTime = time; + } + if (!bPlugAndPlayUpdated) { return; @@ -69,6 +85,9 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) m_pMIDIDevice->RegisterPacketHandler (MIDIPacketHandler, this); m_pMIDIDevice->RegisterRemovedHandler (DeviceRemovedHandler, this); + + if (m_pDAWController) + m_pDAWController->OnConnect(); } } } @@ -85,6 +104,15 @@ void CMIDIKeyboard::Send (const u8 *pMessage, size_t nLength, unsigned nCable) m_SendQueue.push (Entry); } +void CMIDIKeyboard::SendDisplay (const u8 *pMessage, size_t nLength, unsigned nCable) +{ + assert (nLength <= sizeof m_LastMessage); + + m_LastDisplayEntry.nLength = nLength; + m_LastDisplayEntry.nCable = nCable; + memcpy (m_LastMessage, pMessage, nLength); +} + // Most packets will be passed straight onto the main MIDI message handler // but SysEx messages are multiple USB packets and so will need building up // before parsing. @@ -122,6 +150,10 @@ void CMIDIKeyboard::USBMIDIMessageHandler (u8 *pPacket, unsigned nLength, unsign m_SysEx[m_nSysExIdx++] = pPacket[i]; //printf ("SysEx End Idx=%d\n", m_nSysExIdx); MIDIMessageHandler (m_SysEx, m_nSysExIdx, nCable); + + if (m_pDAWController) + m_pDAWController->MIDISysexHandler (m_SysEx, m_nSysExIdx, nCable); + // Reset ready for next time m_nSysExIdx = 0; } @@ -160,3 +192,28 @@ void CMIDIKeyboard::DeviceRemovedHandler (CDevice *pDevice, void *pContext) pThis->m_pMIDIDevice = 0; } + +void CMIDIKeyboard::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); +} + +void CMIDIKeyboard::UpdateDAWState (void) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->UpdateState (); +} + +void CMIDIKeyboard::UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->UpdateMenu (Type, ucPage, ucOP, ucTG); +} + +void CMIDIKeyboard::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + if (m_pDAWController) + m_pDAWController->MIDIListener (ucCable, ucChannel, ucType, ucP1, ucP2); +} diff --git a/src/midikeyboard.h b/src/midikeyboard.h index bf6268903..ae49a3d77 100644 --- a/src/midikeyboard.h +++ b/src/midikeyboard.h @@ -25,6 +25,7 @@ #include "mididevice.h" #include "config.h" +#include "dawcontroller.h" #include #include #include @@ -44,6 +45,13 @@ class CMIDIKeyboard : public CMIDIDevice void Process (boolean bPlugAndPlayUpdated); void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override; + void SendDisplay (const u8 *pMessage, size_t nLength, unsigned nCable = 0); + + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateDAWState (void); + void UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); private: static void MIDIPacketHandler (unsigned nCable, u8 *pPacket, unsigned nLength, unsigned nDevice, void *pParam); @@ -51,6 +59,8 @@ class CMIDIKeyboard : public CMIDIDevice void USBMIDIMessageHandler (u8 *pPacket, unsigned nLength, unsigned nCable, unsigned nDevice); + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; + private: struct TSendQueueEntry { @@ -68,6 +78,11 @@ class CMIDIKeyboard : public CMIDIDevice CUSBMIDIDevice * volatile m_pMIDIDevice; std::queue m_SendQueue; + u8 m_LastMessage[256]; + TSendQueueEntry m_LastDisplayEntry = {m_LastMessage, 0, 0}; + unsigned m_LastDisplayRefreshTime = 0; + + CDAWController *m_pDAWController; }; #endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index a8b52b3f8..953cb118b 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1665,6 +1665,7 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne m_pTG[i]->setVoiceDataElement (offset, uchValue); } + m_UI.ParameterChanged (); } uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned nTG) @@ -2567,6 +2568,33 @@ void CMiniDexed::setMasterVolume(float32_t vol) m_fMasterVolumeW = vol; } +void CMiniDexed::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + m_UI.DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + } +} + +void CMiniDexed::UpdateDAWState () +{ + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->UpdateDAWState (); + } +} + +void CMiniDexed::UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->UpdateDAWMenu (Type, ucPage, ucOP, ucTG); + } +} + std::string CMiniDexed::GetPerformanceFileName(unsigned nID) { return m_PerformanceConfig.GetPerformanceFileName(nID); diff --git a/src/minidexed.h b/src/minidexed.h index a34c5d9b9..c9df5be78 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -289,6 +289,12 @@ class CMiniDexed void UpdateNetwork(); const CIPAddress& GetNetworkIPAddress(); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateDAWState (); + void UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); + private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note uint8_t m_uchOPMask[CConfig::AllToneGenerators]; diff --git a/src/minidexed.ini b/src/minidexed.ini index 0c1b9e870..ed268452e 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -161,6 +161,9 @@ MIDIButtonActionTGDown=click # Can be adjusted if the controller sends dec / inc messages too quickly. MIDIRelativeDebounceTime=0 +# DAW Controller (Arturia MiniLab 3, KeyLab Essential, KeyLab Essential 3, Keylab mkII) +DAWControllerEnabled=0 + # KY-040 Rotary Encoder EncoderEnabled=1 EncoderPinClock=10 diff --git a/src/uimenu.cpp b/src/uimenu.cpp index a194c39c6..55e56f3b3 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -74,25 +74,25 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = { - {"Voice", EditProgramNumber}, + {"Voice", EditProgramNumber, 0, CMiniDexed::TGParameterProgram, "Voice"}, {"Bank", EditVoiceBankNumber}, - {"Volume", EditTGParameter, 0, CMiniDexed::TGParameterVolume}, + {"Volume", EditTGParameter, 0, CMiniDexed::TGParameterVolume, "Vol"}, #ifdef ARM_ALLOW_MULTI_CORE - {"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan}, - {"FX1-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX1Send}, - {"FX2-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX2Send}, + {"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan, "Pan"}, + {"FX1-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX1Send, "FX1"}, + {"FX2-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX2Send, "FX2"}, #endif - {"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune}, - {"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff}, - {"Resonance", EditTGParameter, 0, CMiniDexed::TGParameterResonance}, + {"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune, "DeT"}, + {"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff, "Cut"}, + {"Resonance", EditTGParameter, 0, CMiniDexed::TGParameterResonance, "Res"}, {"Pitch Bend", MenuHandler, s_EditPitchBendMenu}, {"Portamento", MenuHandler, s_EditPortamentoMenu}, {"Note Limit", MenuHandler, s_EditNoteLimitMenu}, - {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, + {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode, "P/M"}, {"TG-Link", EditTGParameter, 0, CMiniDexed::TGParameterTGLink}, {"Enabled", EditTGParameter, 0, CMiniDexed::TGParameterEnabled}, {"Modulation", MenuHandler, s_ModulationMenu}, - {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, + {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel, "Chan"}, {"EQ", MenuHandler, s_EQMenu}, {"Compressor", MenuHandler, s_EditCompressorMenu}, {"Edit Voice", MenuHandler, s_EditVoiceMenu}, @@ -101,28 +101,28 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = { - {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable}, - {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain}, - {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh}, - {"Ratio", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRatio}, - {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack}, - {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease}, - {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain}, + {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable, "CEn"}, + {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain, "CPg"}, + {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh, "CTh"}, + {"Ratio", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRatio, "CRa"}, + {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack, "CAt"}, + {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease, "CRe"}, + {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain, "CPm"}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_EditPitchBendMenu[] = { - {"Bend Range", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendRange}, - {"Bend Step", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendStep}, + {"Bend Range", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendRange, "PiBR"}, + {"Bend Step", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendStep, "PiBS"}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_EditPortamentoMenu[] = { - {"Mode", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoMode}, - {"Glissando", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoGlissando}, - {"Time", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoTime}, + {"Mode", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoMode, "PorM"}, + {"Glissando", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoGlissando, "PorG"}, + {"Time", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoTime, "PorT"}, {0} }; @@ -136,10 +136,10 @@ const CUIMenu::TMenuItem CUIMenu::s_EditNoteLimitMenu[] = const CUIMenu::TMenuItem CUIMenu::s_ModulationMenu[] = { - {"Mod. Wheel", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterMWRange}, - {"Foot Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterFCRange}, - {"Breath Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterBCRange}, - {"Aftertouch", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterATRange}, + {"Mod. Wheel", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterMWRange, "MWR"}, + {"Foot Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterFCRange, "FCR"}, + {"Breath Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterBCRange, "BCR"}, + {"Aftertouch", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterATRange, "ATR"}, {0} }; @@ -154,12 +154,12 @@ const CUIMenu::TMenuItem CUIMenu::s_ModulationMenuParameters[] = const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = { - {"Low Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQLow}, - {"Mid Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQMid}, - {"High Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQHigh}, - {"Gain", EditTGParameter2, 0, CMiniDexed::TGParameterEQGain}, - {"Low-Mid Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQLowMidFreq}, - {"Mid-High Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQMidHighFreq}, + {"Low Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQLow, "TQL"}, + {"Mid Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQMid, "TQM"}, + {"High Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQHigh, "TQH"}, + {"Gain", EditTGParameter2, 0, CMiniDexed::TGParameterEQGain, "TQG"}, + {"Low-Mid Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQLowMidFreq, "TQLM"}, + {"Mid-High Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQMidHighFreq, "TQMH"}, {0} }; @@ -243,13 +243,13 @@ const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = { - {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterPlateReverbMix}, - {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize}, - {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp}, - {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp}, - {"Low pass", EditFXParameter2, 0, FX::FXParameterPlateReverbLowPass}, - {"Diffusion", EditFXParameter2, 0, FX::FXParameterPlateReverbDiffusion}, - {"Bypass", EditFXParameter2, 0, FX::FXParameterPlateReverbBypass}, + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterPlateReverbMix, "RvMx"}, + {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize, "RvS"}, + {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp, "RvHD"}, + {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp, "RvLD"}, + {"Low pass", EditFXParameter2, 0, FX::FXParameterPlateReverbLowPass, "RvLP"}, + {"Diffusion", EditFXParameter2, 0, FX::FXParameterPlateReverbDiffusion, "RvDi"}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterPlateReverbBypass, "RvBP"}, {0} }; @@ -389,53 +389,53 @@ const CUIMenu::TMenuItem CUIMenu::s_EditVoiceMenu[] = {"OP4", MenuHandler, s_OperatorMenu, 3}, {"OP5", MenuHandler, s_OperatorMenu, 4}, {"OP6", MenuHandler, s_OperatorMenu, 5}, - {"Algorithm", EditVoiceParameter, 0, DEXED_ALGORITHM}, - {"Feedback", EditVoiceParameter, 0, DEXED_FEEDBACK}, - {"P EG Rate 1", EditVoiceParameter, 0, DEXED_PITCH_EG_R1}, - {"P EG Rate 2", EditVoiceParameter, 0, DEXED_PITCH_EG_R2}, - {"P EG Rate 3", EditVoiceParameter, 0, DEXED_PITCH_EG_R3}, - {"P EG Rate 4", EditVoiceParameter, 0, DEXED_PITCH_EG_R4}, - {"P EG Level 1",EditVoiceParameter, 0, DEXED_PITCH_EG_L1}, - {"P EG Level 2",EditVoiceParameter, 0, DEXED_PITCH_EG_L2}, - {"P EG Level 3",EditVoiceParameter, 0, DEXED_PITCH_EG_L3}, - {"P EG Level 4",EditVoiceParameter, 0, DEXED_PITCH_EG_L4}, - {"Osc Key Sync",EditVoiceParameter, 0, DEXED_OSC_KEY_SYNC}, - {"LFO Speed", EditVoiceParameter, 0, DEXED_LFO_SPEED}, - {"LFO Delay", EditVoiceParameter, 0, DEXED_LFO_DELAY}, - {"LFO PMD", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_DEP}, - {"LFO AMD", EditVoiceParameter, 0, DEXED_LFO_AMP_MOD_DEP}, - {"LFO Sync", EditVoiceParameter, 0, DEXED_LFO_SYNC}, - {"LFO Wave", EditVoiceParameter, 0, DEXED_LFO_WAVE}, - {"P Mod Sens.", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_SENS}, - {"Transpose", EditVoiceParameter, 0, DEXED_TRANSPOSE}, + {"Algorithm", EditVoiceParameter, 0, DEXED_ALGORITHM, "Alg"}, + {"Feedback", EditVoiceParameter, 0, DEXED_FEEDBACK, "FB"}, + {"P EG Rate 1", EditVoiceParameter, 0, DEXED_PITCH_EG_R1, "PR1"}, + {"P EG Rate 2", EditVoiceParameter, 0, DEXED_PITCH_EG_R2, "PR2"}, + {"P EG Rate 3", EditVoiceParameter, 0, DEXED_PITCH_EG_R3, "PR3"}, + {"P EG Rate 4", EditVoiceParameter, 0, DEXED_PITCH_EG_R4, "PR4"}, + {"P EG Level 1",EditVoiceParameter, 0, DEXED_PITCH_EG_L1, "PL1"}, + {"P EG Level 2",EditVoiceParameter, 0, DEXED_PITCH_EG_L2, "PL2"}, + {"P EG Level 3",EditVoiceParameter, 0, DEXED_PITCH_EG_L3, "PL3"}, + {"P EG Level 4",EditVoiceParameter, 0, DEXED_PITCH_EG_L4, "PL4"}, + {"Osc Key Sync",EditVoiceParameter, 0, DEXED_OSC_KEY_SYNC, "OKS"}, + {"LFO Speed", EditVoiceParameter, 0, DEXED_LFO_SPEED, "LSP"}, + {"LFO Delay", EditVoiceParameter, 0, DEXED_LFO_DELAY, "LDE"}, + {"LFO PMD", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_DEP, "LPMD"}, + {"LFO AMD", EditVoiceParameter, 0, DEXED_LFO_AMP_MOD_DEP, "LAMD"}, + {"LFO Sync", EditVoiceParameter, 0, DEXED_LFO_SYNC, "LSYN"}, + {"LFO Wave", EditVoiceParameter, 0, DEXED_LFO_WAVE, "LWAV"}, + {"P Mod Sens.", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_SENS, "LPMS"}, + {"Transpose", EditVoiceParameter, 0, DEXED_TRANSPOSE, "TRP"}, {"Name", InputTxt,0 , 3}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_OperatorMenu[] = { - {"Output Level",EditOPParameter, 0, DEXED_OP_OUTPUT_LEV}, - {"Freq Coarse", EditOPParameter, 0, DEXED_OP_FREQ_COARSE}, - {"Freq Fine", EditOPParameter, 0, DEXED_OP_FREQ_FINE}, - {"Osc Detune", EditOPParameter, 0, DEXED_OP_OSC_DETUNE}, - {"Osc Mode", EditOPParameter, 0, DEXED_OP_OSC_MODE}, - {"EG Rate 1", EditOPParameter, 0, DEXED_OP_EG_R1}, - {"EG Rate 2", EditOPParameter, 0, DEXED_OP_EG_R2}, - {"EG Rate 3", EditOPParameter, 0, DEXED_OP_EG_R3}, - {"EG Rate 4", EditOPParameter, 0, DEXED_OP_EG_R4}, - {"EG Level 1", EditOPParameter, 0, DEXED_OP_EG_L1}, - {"EG Level 2", EditOPParameter, 0, DEXED_OP_EG_L2}, - {"EG Level 3", EditOPParameter, 0, DEXED_OP_EG_L3}, - {"EG Level 4", EditOPParameter, 0, DEXED_OP_EG_L4}, - {"Break Point", EditOPParameter, 0, DEXED_OP_LEV_SCL_BRK_PT}, - {"L Key Depth", EditOPParameter, 0, DEXED_OP_SCL_LEFT_DEPTH}, - {"R Key Depth", EditOPParameter, 0, DEXED_OP_SCL_RGHT_DEPTH}, - {"L Key Scale", EditOPParameter, 0, DEXED_OP_SCL_LEFT_CURVE}, - {"R Key Scale", EditOPParameter, 0, DEXED_OP_SCL_RGHT_CURVE}, - {"Rate Scaling",EditOPParameter, 0, DEXED_OP_OSC_RATE_SCALE}, - {"A Mod Sens.", EditOPParameter, 0, DEXED_OP_AMP_MOD_SENS}, - {"K Vel. Sens.",EditOPParameter, 0, DEXED_OP_KEY_VEL_SENS}, - {"Enable", EditOPParameter, 0, DEXED_OP_ENABLE}, + {"Output Level",EditOPParameter, 0, DEXED_OP_OUTPUT_LEV, "OutL"}, + {"Freq Coarse", EditOPParameter, 0, DEXED_OP_FREQ_COARSE, "FrC"}, + {"Freq Fine", EditOPParameter, 0, DEXED_OP_FREQ_FINE, "FrF"}, + {"Osc Detune", EditOPParameter, 0, DEXED_OP_OSC_DETUNE, "OsDT"}, + {"Osc Mode", EditOPParameter, 0, DEXED_OP_OSC_MODE, "OsM"}, + {"EG Rate 1", EditOPParameter, 0, DEXED_OP_EG_R1, "R1"}, + {"EG Rate 2", EditOPParameter, 0, DEXED_OP_EG_R2, "R2"}, + {"EG Rate 3", EditOPParameter, 0, DEXED_OP_EG_R3, "R3"}, + {"EG Rate 4", EditOPParameter, 0, DEXED_OP_EG_R4, "R4"}, + {"EG Level 1", EditOPParameter, 0, DEXED_OP_EG_L1, "L1"}, + {"EG Level 2", EditOPParameter, 0, DEXED_OP_EG_L2, "L2"}, + {"EG Level 3", EditOPParameter, 0, DEXED_OP_EG_L3, "L3"}, + {"EG Level 4", EditOPParameter, 0, DEXED_OP_EG_L4, "L4"}, + {"Break Point", EditOPParameter, 0, DEXED_OP_LEV_SCL_BRK_PT, "BP"}, + {"L Key Depth", EditOPParameter, 0, DEXED_OP_SCL_LEFT_DEPTH, "LDep"}, + {"R Key Depth", EditOPParameter, 0, DEXED_OP_SCL_RGHT_DEPTH, "RDep"}, + {"L Key Scale", EditOPParameter, 0, DEXED_OP_SCL_LEFT_CURVE, "LSca"}, + {"R Key Scale", EditOPParameter, 0, DEXED_OP_SCL_RGHT_CURVE, "RSca"}, + {"Rate Scaling",EditOPParameter, 0, DEXED_OP_OSC_RATE_SCALE, "RS"}, + {"A Mod Sens.", EditOPParameter, 0, DEXED_OP_AMP_MOD_SENS, "AMS"}, + {"K Vel. Sens.",EditOPParameter, 0, DEXED_OP_KEY_VEL_SENS, "KVS"}, + {"Enable", EditOPParameter, 0, DEXED_OP_ENABLE, "OPEn"}, {0} }; @@ -632,7 +632,7 @@ void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) case MenuEventUpdate: case MenuEventUpdateParameter: break; - + default: return; } @@ -642,7 +642,7 @@ void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) char info[17]; snprintf(info, sizeof(info), "%d/%d C", pStatus->nCPUTemp.load(), pStatus->nCPUMaxTemp); - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, info, pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); @@ -669,7 +669,7 @@ void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) char info[17]; snprintf(info, sizeof(info), "%d/%d MHz", pStatus->nCPUClockRate.load() / 1000000, pStatus->nCPUMaxClockRate / 1000000); - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, info, pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); @@ -699,7 +699,7 @@ void CUIMenu::ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event) IPAddr.Format(&IPString); } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, (const char*)IPString, pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); @@ -721,12 +721,80 @@ void CUIMenu::ShowVersion (CUIMenu *pUIMenu, TMenuEvent Event) return; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, VERSION, pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); } +const void CUIMenu::GetParameterInfo (CUIMenu::TCParameterInfo *pParam) +{ + static const CUIMenu::TMenuItem *globalSources[] = { +//#ifdef ARM_ALLOW_MULTI_CORE +// s_PlateReverbMenu, +// s_MasterEQMenu, +// s_MasterCompressorMenu, +//#endif + 0}; + static const CUIMenu::TMenuItem *tgSources[] = {s_TGMenu, s_EditPortamentoMenu, s_EditPitchBendMenu, s_ModulationMenu, s_EQMenu, s_EditCompressorMenu, 0}; + static const CUIMenu::TMenuItem *voiceSources[] = {s_EditVoiceMenu + 6, 0}; // skip Operators + static const CUIMenu::TMenuItem *opSources[] = {s_OperatorMenu, 0}; + const CUIMenu::TMenuItem **pSources = NULL; + const CUIMenu::TParameter *pInfo = NULL; + + switch (pParam->Type) + { + case ParameterGlobal: + pSources = globalSources; + pInfo = s_GlobalParameter; + break; + case ParameterTG: + pSources = tgSources; + pInfo = s_TGParameter; + break; + case ParameterVoice: + pSources = voiceSources; + pInfo = s_VoiceParameter; + break; + case ParameterOP: + pSources = opSources; + pInfo = s_OPParameter; + break; + default: + return; + } + + pParam->Min = pInfo[pParam->Parameter].Minimum; + pParam->Max = pInfo[pParam->Parameter].Maximum; + if (!pParam->ToString) + pParam->ToString = pInfo[pParam->Parameter].ToString; + + // There are some parameters without entry eg TGParameterMWRange + // skip them + if (pParam->Name && pParam->Short) + return; + + for (const CUIMenu::TMenuItem **source = pSources; *source; ++source) + for (const CUIMenu::TMenuItem *m = *source; m->Name; ++m) + if (m->Parameter == pParam->Parameter) + { + if (!pParam->Name) + pParam->Name = m->Name; + if (!pParam->Short) + pParam->Short = m->Short; + return; + } + + pParam->Type = ParameterNone; + pParam->Parameter = 0; +} + +const void CUIMenu::GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n) +{ + for (size_t i = 0; i < n; ++i) + GetParameterInfo(&pParamInfo[i]); +} + CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), m_pMiniDexed (pMiniDexed), @@ -836,6 +904,26 @@ void CUIMenu::EventHandler (TMenuEvent Event) (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); break; } + + switch (Event) + { + case MenuEventBack: + case MenuEventHome: + case MenuEventSelect: + if (m_pCurrentMenu == s_MainMenu) + m_pMiniDexed->UpdateDAWMenu (PageMain, 0, 0, 0); + //else if (m_pCurrentMenu == s_EffectsMenu) + // m_pMiniDexed->UpdateDAWMenu (PageEffect, 0, 0, 0); + else if (m_pCurrentMenu == s_TGMenu) + m_pMiniDexed->UpdateDAWMenu (PageTG, 0, 0, m_nCurrentParameter + 1); + else if (m_pCurrentMenu == s_EditVoiceMenu) + m_pMiniDexed->UpdateDAWMenu (PageVoice, 0, 0, m_nMenuStackParameter[m_nCurrentMenuDepth - 1] + 1); + else if (m_pCurrentMenu == s_OperatorMenu) + m_pMiniDexed->UpdateDAWMenu (PageOP, 0, m_nCurrentParameter, m_nMenuStackParameter[m_nCurrentMenuDepth - 2] + 1); + break; + default: + break; + } } void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) @@ -981,7 +1069,7 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) if (nTGLink) selectionName += ToTGLinkName(nTGLink, 0); } - pUIMenu->m_pUI->DisplayWrite ( + pUIMenu->m_pMiniDexed->DisplayWrite ( menuName.c_str(), "", selectionName.c_str(), @@ -1042,7 +1130,7 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->GetParameter (Param), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1089,7 +1177,7 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) std::string Value = std::to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetBankName (nValue); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > 0, nValue < (int) CSysExFileLoader::MaxVoiceBankID); @@ -1172,7 +1260,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) std::string Value = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); - pUIMenu->m_pUI->DisplayWrite (TG.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str(), voice.c_str(), Value.c_str(), nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank); @@ -1235,7 +1323,7 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1298,7 +1386,7 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1348,7 +1436,7 @@ void CUIMenu::EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (FX.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (FX.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1398,7 +1486,7 @@ void CUIMenu::EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (FX.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (FX.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1453,7 +1541,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) std::string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1557,7 +1645,7 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) Value = GetOPValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); } - pUIMenu->m_pUI->DisplayWrite (OP.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (OP.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1576,7 +1664,7 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, bOK ? "Completed" : "Error", false, false); @@ -2539,7 +2627,7 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { pUIMenu->m_nSelectedPerformanceID = 0; pUIMenu->m_bConfirmDeletePerformance=false; - pUIMenu->m_pUI->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); pUIMenu->m_bSplashShow=true; CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandlerNoBack, 0, pUIMenu); return; @@ -2572,13 +2660,13 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), true, true); // (int) nValue > 0, (int) nValue < (int) pUIMenu->m_pMiniDexed->GetLastPerformance()); } else { - pUIMenu->m_pUI->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); } } @@ -2660,7 +2748,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), true, true); } @@ -2771,7 +2859,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetNewPerformanceName(pUIMenu->m_InputText); bOK = pUIMenu->m_pMiniDexed->SavePerformanceNewFile (); MsgOk=bOK ? "Completed" : "Error"; - pUIMenu->m_pUI->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); return; } @@ -2822,7 +2910,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) } Value = Value + " " + escCursor ; - pUIMenu->m_pUI->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); } @@ -2880,7 +2968,7 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); diff --git a/src/uimenu.h b/src/uimenu.h index 7b3b9bc84..c305fceaa 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -56,11 +56,46 @@ class CUIMenu MenuEventUnknown }; + typedef std::string TToString (int nValue, int nWidth); + + enum TCPageType + { + PageMain, + PageEffect, + PageTG, + PageVoice, + PageOP, + }; + + enum TCParameterType + { + ParameterNone, + ParameterGlobal, + ParameterTG, + ParameterVoice, + ParameterOP, + }; + + struct TCParameterInfo { + TCParameterType Type; + unsigned Parameter; + const char* Name; + const char* Short; + u8 ChG; + u8 TG; + u8 OP; + int Min; + int Max; + TToString *ToString; + }; + public: CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig); void EventHandler (TMenuEvent Event); + const void GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n); + private: typedef void TMenuHandler (CUIMenu *pUIMenu, TMenuEvent Event); @@ -70,6 +105,7 @@ class CUIMenu TMenuHandler *Handler; const TMenuItem *MenuItem; unsigned Parameter; + const char *Short; TMenuHandler* OnSelect; TMenuHandler* StepDown; TMenuHandler* StepUp; @@ -77,8 +113,6 @@ class CUIMenu bool ShowDirect; }; - typedef std::string TToString (int nValue, int nWidth); - struct TParameter { int Minimum; @@ -160,7 +194,8 @@ class CUIMenu static void StepDownEffect (CUIMenu *pUIMenu, TMenuEvent Event); static void StepUpEffect (CUIMenu *pUIMenu, TMenuEvent Event); static bool FXSlotFilter (CUIMenu *pUIMenu, TMenuEvent Event, int nValue); - + + const void GetParameterInfo (TCParameterInfo *pParam); private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 5dc1ce4fa..492e4eb1e 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -210,6 +210,16 @@ void CUserInterface::LoadDefaultScreen () } } +void CUserInterface::MIDIEventHandler (CUIMenu::TMenuEvent Event) +{ + m_Menu.EventHandler (Event); +} + +const void CUserInterface::GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n) +{ + m_Menu.GetParameterInfos (pParamInfo, n); +} + void CUserInterface::Process (void) { if (m_pLCDBuffered) @@ -225,6 +235,7 @@ void CUserInterface::Process (void) void CUserInterface::ParameterChanged (void) { m_Menu.EventHandler (CUIMenu::MenuEventUpdateParameter); + m_pMiniDexed->UpdateDAWState (); } void CUserInterface::DisplayChanged (void) diff --git a/src/userinterface.h b/src/userinterface.h index ba7daef96..aa5ef9fa1 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -60,6 +60,10 @@ class CUserInterface // To be called from the MIDI device on reception of a MIDI CC message void UIMIDICmdHandler (unsigned nMidiCh, unsigned nMidiType, unsigned nMidiData1, unsigned nMidiData2); + void MIDIEventHandler (CUIMenu::TMenuEvent Event); + + const void GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n); + private: void LCDWrite (const char *pString); // Print to optional HD44780 display