refactor and block select font size option

This commit is contained in:
chriskiefer 2026-03-29 16:45:53 +01:00
parent 56c1189c5e
commit 8be4f85cb6
12 changed files with 217 additions and 357 deletions

View file

@ -9,7 +9,6 @@
#include <memory> // Added for std::shared_ptr #include <memory> // Added for std::shared_ptr
#include "src/memllib/synth/maxiPAF.hpp" #include "src/memllib/synth/maxiPAF.hpp"
#include "src/memllib/synth/ADSRLite.hpp"
#include "src/memllib/interface/InterfaceBase.hpp" // Added missing include #include "src/memllib/interface/InterfaceBase.hpp" // Added missing include
#include <span> #include <span>
@ -132,294 +131,6 @@ private:
// float runningRMS=0; // float runningRMS=0;
// }; // };
class maxiDynamicsLite {
public:
enum ANALYSERS {PEAK, RMS};
static constexpr float maxRMSSizeMS = 300.f;
maxiDynamicsLite() {
//define detector functions
inputPeak = [](float sig) {
return abs(sig);
};
rms.setup(maxRMSSizeMS,300);
inputRMS = [&](float sig) {
return rms.play(sig);
};
//default RMS
inputAnalyser = inputRMS;
//setup envelopes
arEnvHigh.setup(10,0,1.f,10.f, maxiSettings::sampleRate);
arEnvLow.setup(10,0,1.f,10.f, maxiSettings::sampleRate);
lookAheadDelay.setup(maxiSettings::sampleRate * 0.1); //max 0.1s
}
/**
* This functions compands the signal, providing download compression or upward expansion above an upper thresold, and
* upward compression or downward expansion below a lower threshold.
* \param sig The input signal to be companded
* \param control This signal is used to trigger the compander. Use it for sidechaining, or if no sidechain is needed, use the same signal for this and the input signal
* \param thresholdHigh The high threshold, in Dbs
* \param ratioHigh The ratio for companding above the high threshold
* \param kneeHigh The size of the knee for companding above the high threshold (in Dbs)
* \param thresholdLow The low threshold, in Dbs
* \param ratioLow The ratio for companding below the low threshold
* \param kneeLow The size of the knee for companding below the low threshold (in Dbs)
* \returns a companded signal
*/
__attribute__((always_inline)) __attribute__((hot)) float play(float sig, float control,
float thresholdHigh, float ratioHigh, float kneeHigh,
float thresholdLow, float ratioLow, float kneeLow
) {
const float inputEnv = inputAnalyser(control) + 0.00001f; //avoid log of zero
const float controlDB = maxiConvert::ampToDbs(inputEnv);
float outDB = controlDB;
const float halfKneeHigh = kneeHigh * 0.5f;
//companding above the high threshold
if (ratioHigh > 0) {
if (kneeHigh > 0) {
float lowerKnee = thresholdHigh - (kneeHigh*0.5f);
float higherKnee = thresholdHigh +(kneeHigh*0.5f);
//attack/release
float envRatio = 1.f;
if (controlDB >= lowerKnee) {
arEnvHigh.triggerIfReady(1.f);
float envVal = arEnvHigh.play();
envRatio = envToRatio(envVal, ratioHigh);
}else {
arEnvHigh.release();
}
if ((controlDB >= lowerKnee) && (controlDB < higherKnee)) {
float kneeHighOut = ((higherKnee - thresholdHigh) / envRatio) + thresholdHigh;
float kneeRange = (kneeHighOut - lowerKnee);
float t = (controlDB - lowerKnee) / kneeHigh;
//bezier on x only
float curve = ratioHigh > 1.f ? 0.8f : 0.2f;
float kneex = (2.f * (1.f-t) * t * curve) + (t*t);
outDB = lowerKnee + (kneex * kneeRange);
}
else if (controlDB >= higherKnee) {
outDB = ((controlDB - thresholdHigh) / envRatio) + thresholdHigh;
}else{
outDB = controlDB;
}
}
else {
//no knee
if (controlDB > thresholdHigh) {
arEnvHigh.trigger(1.f);
}else {
arEnvHigh.release();
}
float envVal = arEnvHigh.play();
// const float envVal = arEnvHigh.play(controlDB > thresholdHigh ? 1.f : 0.f);
const float envRatio = envToRatio(envVal, ratioHigh);
outDB = ((controlDB - thresholdHigh) / envRatio) + thresholdHigh;
}
}
// //companding below the low threshold
// if (ratioLow > 0) {
// if (kneeLow > 0) {
// float lowerKnee = thresholdLow - (kneeLow*0.5f);
// float higherKnee = thresholdLow +(kneeLow*0.5f);
// //attack/release
// float envRatio = 1;
// if (controlDB < lowerKnee) {
// float envVal = arEnvLow.play(1.f);
// envRatio = envToRatio(envVal, ratioLow);
// }else {
// float envVal = arEnvLow.play(-1.f);
// }
// if ((controlDB >= lowerKnee) && (controlDB < higherKnee)) {
// float kneeLowOut = thresholdLow - ((thresholdLow-lowerKnee) / ratioLow);
// float kneeRange = (higherKnee - kneeLowOut);
// float t = (controlDB - lowerKnee) / kneeLow;
// //bezier on x only
// float curve = ratioLow > 1.f ? 0.2f : 0.8f;
// float kneex = (2.f * (1.f-t) * t * curve) + (t*t);
// outDB = kneeLowOut + (kneex * kneeRange);
// }
// else if (controlDB < lowerKnee) {
// outDB = thresholdLow - ((thresholdLow-controlDB) / ratioLow);
// }
// }
// else {
// //no knee
// if (controlDB < thresholdLow) {
// float envVal = arEnvLow.play(1.f);
// // float envRatio = envToRatio(envVal, ratioLow);
// outDB = thresholdLow - ((thresholdLow-controlDB) / ratioLow);
// }else {
// float envVal = arEnvLow.play(-1.f);
// outDB = maxiConvert::ampToDbs(fabsf(sig));
// }
// }
// }
//scale the signal according to the amount of compansion on the control signal
float outAmp = maxiConvert::dbsToAmp(outDB);
// float ctrlAmp = maxiConvert::dbsToAmp(controlDB);
float sigOut = sig;
if (outAmp > 0.f) {
if (lookAheadSize > 0.f) {
lookAheadDelay.push(sig);
sigOut = lookAheadDelay.tail(lookAheadSize);
}
// sigOut = sigOut * fabsf(control / outAmp);
float gainReduction = outAmp / inputEnv;
sigOut = sig * gainReduction;
// PERIODIC_DEBUG(1000,
// Serial.printf("%f %f %f %f %f\n",controlDB, outDB, control, outAmp, gainReduction);
// )
}else{
// printf("Warning: maxiDynamicsLite output amplitude is zero or negative!\n");
}
return sigOut;
}
/**
* Compress a signal (using downward compression)
* \param sig The input signal to be compressed
* \param threshold The threshold, in Dbs
* \param ratio The compression ratio (>1 provides compression, <1 provides expansion)
* \param knee The size of the knee (in Dbs)
* \returns a compressed signal
*/
__attribute__((always_inline)) __attribute__((hot)) float compress(float sig, float threshold, float ratio, float knee) {
return play(sig, sig, threshold, ratio, knee, 0.f, 0.f, 0.f);
}
/**
* Compress a signal with sidechaining (using downward compression)
* \param sig The input signal to be compressed
* \param control The sidechain signal
* \param threshold The threshold, in Dbs
* \param ratio The compression ratio (>1 provides compression, <1 provides expansion)
* \param knee The size of the knee (in Dbs)
* \returns a compressed signal
*/
float sidechainCompress(float sig, float control, float threshold, float ratio, float knee) {
return play(sig, control, threshold, ratio, knee, 0, 0, 0);
}
/**
* Compand a signal, using detection above a threshold (provides downward compression or upward expansion)
* \param sig The input signal to be compressed
* \param control The sidechain signal
* \param threshold The threshold, in Dbs
* \param ratio The compression ratio (>1 provides compression, <1 provides expansion)
* \param knee The size of the knee (in Dbs)
* \returns a companded signal
*/
float compandAbove(float sig, float control, float threshold, float ratio, float knee) {
return play(sig, control, threshold, ratio, knee, 0, 0, 0);
}
/**
* Compand a signal, using detection below a threshold (provides upward compression or downward expansion)
* \param sig The input signal to be compressed
* \param control The sidechain signal
* \param threshold The threshold, in Dbs
* \param ratio The compression ratio (>1 provides compression, <1 provides expansion)
* \param knee The size of the knee (in Dbs)
* \returns a companded signal
*/
float compandBelow(float sig, float control, float threshold, float ratio, float knee) {
return play(sig, control, 0, 0, 0, threshold, ratio, knee);
}
/**
* Set the attack time for the high threshold. This is the amount of time over which the ratio moves from 1 to its full value, following the input analyser going over the threshold.
* \param attack The attack time (in milliseconds)
*/
__attribute__((always_inline)) void setAttackHigh(float attack) {
arEnvHigh.setAttackTime(attack, maxiSettings::sampleRate);
}
/**
* Set the release time for the high threshold. This is the amount of time over which the ratio moves from its full value to 1, following the input analyser going under the threshold.
* \param release The release time (in milliseconds)
*/
__attribute__((always_inline)) void setReleaseHigh(float release) {
arEnvHigh.setReleaseTime(release, maxiSettings::sampleRate);
}
/**
* Set the attack time for the low threshold. This is the amount of time over which the ratio moves from 1 to its full value, following the input analyser going under the threshold.
* \param attack The attack time (in milliseconds)
*/
__attribute__((always_inline)) void setAttackLow(float attack) {
arEnvLow.setAttackTime(attack, maxiSettings::sampleRate);
}
/**
* Set the release time for the low threshold. This is the amount of time over which the ratio moves from its full value to 1, following the input analyser going over the threshold.
* \param release The release time (in milliseconds)
*/
__attribute__((always_inline)) void setReleaseLow(float release) {
arEnvLow.setReleaseTime(release, maxiSettings::sampleRate);
}
/**
* The look ahead creates a delay on the input signal, meaning that that the signal is compressed according to event that have already happened in the control signal. This can be useful for limiting and catching fast transients.
* \param length The amount of time the compressor looks ahead (in milliseconds)
*/
void setLookAhead(float length) {
lookAheadSize = maxiConvert::msToSamps(length);
lookAheadSize = std::min(lookAheadSize, lookAheadDelay.size());
}
/**
* \returns the look ahead time (in milliseconds)
*/
float getLookAhead() {
return maxiConvert::sampsToMs(lookAheadSize);
}
/**
* Set the size of the RMS window. Longer times give a slower response
* \param winSize The size of the window (in milliseconds)
*/
void setRMSWindowSize(float winSize) {
rms.setWindowSize(std::min(winSize, maxRMSSizeMS));
}
/**
* Set the method by which the compressor analyses the control input
* \mode maxiDynamics::PEAK for peak analysis, maxiDynamics::RMS for rms analysis
*/
void setInputAnalyser(ANALYSERS mode) {
if (mode == PEAK) {
inputAnalyser = inputPeak;
}else{
inputAnalyser = inputRMS;
}
}
private:
ADSRLite arEnvHigh, arEnvLow;
maxiRingBuf lookAheadDelay;
size_t lookAheadSize = 0;
maxiRMS rms;
std::function<float(float)> inputPeak;
std::function<float(float)> inputRMS;
std::function<float(float)> inputAnalyser;
// maxiPoll poll;
//mapping from attack/release envelope to ratio
inline float envToRatio(float envVal, float ratio) {
float envRatio = 1.f;
if (ratio > 1.f) {
envRatio = 1.f + ((ratio-1.f) * envVal);
}else {
envRatio = 1.f - ((1.f-ratio) * envVal);
}
return envRatio;
}
};
template<size_t NPARAMS=24> template<size_t NPARAMS=24>

View file

@ -1,6 +1,6 @@
//machine config //machine config
#define JOYSTICK_IS_4D false #define JOYSTICK_IS_4D true
#define MEMLNAUT_ANALOG_INPUTS 3 + (JOYSTICK_IS_4D ? 1 : 0) #define MEMLNAUT_ANALOG_INPUTS 3 + (JOYSTICK_IS_4D ? 1 : 0)
#define MEMLNAUT_INPUT_MODE InterfaceRL::INPUT_MODES::JOYSTICK #define MEMLNAUT_INPUT_MODE InterfaceRL::INPUT_MODES::JOYSTICK

View file

@ -11,6 +11,7 @@
#include <span> #include <span>
#include "../../voicespaces/VoiceSpaces.hpp" #include "../../voicespaces/VoiceSpaces.hpp"
#include "../../voicespaces/VerbFX/basic.hpp"
#include "../../src/memllib/synth/OnePoleSmoother.hpp" #include "../../src/memllib/synth/OnePoleSmoother.hpp"
#include "../../src/memllib/synth/maximilian.h" #include "../../src/memllib/synth/maximilian.h"
#include "../../src/daisysp/Effects/pitchshifter.h" #include "../../src/daisysp/Effects/pitchshifter.h"
@ -19,7 +20,7 @@
template<size_t NPARAMS=41> template<size_t NPARAMS=46>
class VerbFXAudioApp : public AudioAppBase<NPARAMS> class VerbFXAudioApp : public AudioAppBase<NPARAMS>
{ {
public: public:
@ -31,6 +32,25 @@ public:
VoiceSpaceFn<NPARAMS> currentVoiceSpace; VoiceSpaceFn<NPARAMS> currentVoiceSpace;
enum class controlMessages {
MSG_ENABLE_FILTERBANK=0,
MSG_ENABLE_REVERB,
MSG_ENABLE_SHORT_DELAY,
MSG_ENABLE_MEDIUM_DELAY,
MSG_ENABLE_LONG_DELAY,
MSG_ENABLE_DELAY_TO_REVERB,
};
queue_t controlMessageQueue;
bool enableFilterbank=true;
bool enableReverb=true;
bool enableShortDelay=true;
bool enableMediumDelay=true;
bool enableLongDelay=true;
bool enableDelayToReverb=true;
std::array<String, nVoiceSpaces> getVoiceSpaceNames() { std::array<String, nVoiceSpaces> getVoiceSpaceNames() {
std::array<String, nVoiceSpaces> names; std::array<String, nVoiceSpaces> names;
for(size_t i=0; i < voiceSpaces.size(); i++) { for(size_t i=0; i < voiceSpaces.size(); i++) {
@ -46,90 +66,132 @@ public:
} }
VerbFXAudioApp() : AudioAppBase<NPARAMS>() { VerbFXAudioApp() : AudioAppBase<NPARAMS>() {
auto voiceSpaceDefault = [this](const std::array<float, NPARAMS>& params) {
VOICE_SPACE_VERBFX_DEFAULT_BODY
};
voiceSpaces[0] = {"Default", voiceSpaceDefault};
currentVoiceSpace = voiceSpaces[0].mappingFunction;
queue_init(&controlMessageQueue, sizeof(controlMessages), 1);
}; };
__attribute__((hot)) stereosample_t __force_inline Process(const stereosample_t x) override __attribute__((hot)) stereosample_t __force_inline Process(const stereosample_t x) override
{ {
static float verbFB = 0.f;
static float delaysFB = 0.f;
float mix = x.L + x.R; float mix = x.L + x.R;
smoother.Process(neuralNetOutputs.data(), smoothParams.data()); smoother.Process(neuralNetOutputs.data(), smoothParams.data());
//mapping
wetdry_mix_ = (smoothParams[0] * 0.9f) + 0.1f; wetdry_mix_ = (smoothParams[0] * 0.9f) + 0.1f;
const float lp0fb = smoothParams[1] * 0.98f;
const float lp0cutoff = (smoothParams[2] * 0.5f) + 0.05f;
const float lp1fb = smoothParams[3] * 0.98f; lp0fb = smoothParams[1] * 0.9f;
const float lp1cutoff = (smoothParams[4] * 0.5f) + 0.05f; lp0cutoff = (smoothParams[2] * 0.5f) + 0.05f;
const float lp2fb = smoothParams[5] * 0.98f; lp1fb = smoothParams[3] * 0.9f;
const float lp2cutoff = (smoothParams[6] * 0.5f) + 0.05f; lp1cutoff = (smoothParams[4] * 0.5f) + 0.05f;
const float lp3fb = smoothParams[7] * 0.98f; lp2fb = smoothParams[5] * 0.9f;
const float lp3cutoff = (smoothParams[8] * 0.5f) + 0.05f; lp2cutoff = (smoothParams[6] * 0.5f) + 0.05f;
const float lp4fb = smoothParams[9] * 0.98f; lp3fb = smoothParams[7] * 0.9f;
const float lp4cutoff = (smoothParams[10] * 0.5f) + 0.05f; lp3cutoff = (smoothParams[8] * 0.5f) + 0.05f;
const float lp5fb = smoothParams[11] * 0.98f; lp4fb = smoothParams[9] * 0.9f;
const float lp5cutoff = (smoothParams[12] * 0.5f) + 0.05f; lp4cutoff = (smoothParams[10] * 0.5f) + 0.05f;
const float lp6fb = smoothParams[13] * 0.98f; lp5fb = smoothParams[11] * 0.98f;
const float lp6cutoff = (smoothParams[14] * 0.5f) + 0.05f; lp5cutoff = (smoothParams[12] * 0.5f) + 0.05f;
const float lp7fb = smoothParams[15] * 0.98f; lp6fb = smoothParams[13] * 0.9;
const float lp7cutoff = (smoothParams[16] * 0.5f) + 0.05f; lp6cutoff = (smoothParams[14] * 0.5f) + 0.05f;
const float allp0fb = smoothParams[17] * 0.98f; lp7fb = smoothParams[15] * 0.9f;
const float allp1fb = smoothParams[18] * 0.98f; lp7cutoff = (smoothParams[16] * 0.5f) + 0.05f;
const float allp2fb = smoothParams[19] * 0.98f;
const float allp3fb = smoothParams[20] * 0.98f;
const float filterBankF0 = 40.f + (smoothParams[21] * 40.f); allp0fb = smoothParams[17] * 0.9f;
const float filterBankF1 = 80.f + (smoothParams[22] * 80.f); allp1fb = smoothParams[18] * 0.9f;
const float filterBankF2 = 160.f + (smoothParams[23] * 160.f); allp2fb = smoothParams[19] * 0.9f;
const float filterBankF3 = 320.f + (smoothParams[24] * 320.f); allp3fb = smoothParams[20] * 0.9f;
const float filterBankF4 = 640.f + (smoothParams[25] * 640.f);
const float filterBankF5 = 1280.f + (smoothParams[26] * 1280.f);
const float filterBankF6 = 2560.f + (smoothParams[27] * 2560.f);
const float filterBankF7 = 5120.f + (smoothParams[28] * 5120.f);
filterBankF0 = 40.f + (smoothParams[21] * 40.f);
filterBankF1 = 80.f + (smoothParams[22] * 80.f);
filterBankF2 = 160.f + (smoothParams[23] * 160.f);
filterBankF3 = 320.f + (smoothParams[24] * 320.f);
filterBankF4 = 640.f + (smoothParams[25] * 640.f);
filterBankF5 = 1280.f + (smoothParams[26] * 1280.f);
filterBankF6 = 2560.f + (smoothParams[27] * 2560.f);
filterBankF7 = 5120.f + (smoothParams[28] * 5120.f);
const float filterBankRes0 = 1.f + (smoothParams[29] * 18.f); filterBankRes0 = 1.f + (smoothParams[29] * 19.f);
const float filterBankRes1 = 1.f + (smoothParams[30] * 18.f); filterBankRes1 = 1.f + (smoothParams[30] * 19.f);
const float filterBankRes2 = 1.f + (smoothParams[31] * 18.f); filterBankRes2 = 1.f + (smoothParams[31] * 19.f);
const float filterBankRes3 = 1.f + (smoothParams[32] * 18.f); filterBankRes3 = 1.f + (smoothParams[32] * 19.f);
const float filterBankRes4 = 1.f + (smoothParams[33] * 18.f); filterBankRes4 = 1.f + (smoothParams[33] * 19.f);
const float filterBankRes5 = 1.f + (smoothParams[34] * 18.f); filterBankRes5 = 1.f + (smoothParams[34] * 19.f);
const float filterBankRes6 = 1.f + (smoothParams[35] * 18.f); filterBankRes6 = 1.f + (smoothParams[35] * 19.f);
const float filterBankRes7 = 1.f + (smoothParams[36] * 18.f); filterBankRes7 = 1.f + (smoothParams[36] * 19.f);
ddelayTime = 10.f + (smoothParams[37] * 16373.f);
ddelayFeedback = (smoothParams[38] * 0.98f);
const float ddelayTime = 10.f + (smoothParams[37] * 8181.f); ddelayTime1 = 10.f + (smoothParams[39] * 2037.f);
const float ddelayFeedback = (smoothParams[38] * 0.98f); ddelayFeedback1 = (smoothParams[40] * 0.98f);
const float filterBankLFOFreq = (smoothParams[39] * 0.5f); ddelayTime2 = 10.f + (smoothParams[41] * 501.f);
const float filterBankLFODepth = (smoothParams[40] * 0.3f); ddelayFeedback2 = (smoothParams[42] * 0.98f);
float filterBankIn = mix; verbVsDelayLevel = smoothParams[43];
float filterBankOut=0; delayToVerbLevel = smoothParams[44] * 0.99f;
filterBankDelayXFade = smoothParams[45];
const float filterBankFreqMod = 1.f + lfo1.sinebuf4(filterBankLFOFreq) * filterBankLFODepth; //XFADE
filterBankOut = filterBank0.bandpassChamberlain(filterBankIn, filterBankF0 * filterBankFreqMod, filterBankRes0); const float filterBankDelayFBLevel = sqrtf(filterBankDelayXFade);
filterBankOut += filterBank1.bandpassChamberlain(filterBankIn, filterBankF1 * filterBankFreqMod, filterBankRes1); const float filterBankDelayFBLevelInv = sqrtf(1.f - filterBankDelayXFade);
filterBankOut += filterBank2.bandpassChamberlain(filterBankIn, filterBankF2 * filterBankFreqMod, filterBankRes2);
filterBankOut += filterBank3.bandpassChamberlain(filterBankIn, filterBankF3 * filterBankFreqMod, filterBankRes3);
filterBankOut += filterBank4.bandpassChamberlain(filterBankIn, filterBankF4 * filterBankFreqMod, filterBankRes4);
filterBankOut += filterBank5.bandpassChamberlain(filterBankIn, filterBankF5 * filterBankFreqMod, filterBankRes5);
filterBankOut += filterBank6.bandpassChamberlain(filterBankIn, filterBankF6 * filterBankFreqMod, filterBankRes6);
filterBankOut += filterBank7.bandpassChamberlain(filterBankIn, filterBankF7 * filterBankFreqMod, filterBankRes7);
filterBankOut *= 0.5f; /////////////////// FILTERBANK
float verbIn = filterBankOut; float filterBankIn = mix + (filterBankDelayFBLevel * ddelayFeedback);
float filterBankOut=mix;
if (enableFilterbank) {
filterBankOut = filterBank0.bandpassChamberlain(filterBankIn, filterBankF0, filterBankRes0);
filterBankOut += filterBank1.bandpassChamberlain(filterBankIn, filterBankF1, filterBankRes1);
filterBankOut += filterBank2.bandpassChamberlain(filterBankIn, filterBankF2, filterBankRes2);
filterBankOut += filterBank3.bandpassChamberlain(filterBankIn, filterBankF3, filterBankRes3);
filterBankOut += filterBank4.bandpassChamberlain(filterBankIn, filterBankF4, filterBankRes4);
filterBankOut += filterBank5.bandpassChamberlain(filterBankIn, filterBankF5, filterBankRes5);
filterBankOut += filterBank6.bandpassChamberlain(filterBankIn, filterBankF6, filterBankRes6);
filterBankOut += filterBank7.bandpassChamberlain(filterBankIn, filterBankF7, filterBankRes7);
filterBankOut *= 0.5f;
}
////////////// DELAYS
float delayIn = filterBankOut;
float delayed = enableLongDelay ? ddelay.read(ddelayTime) : 0.f;
ddelay.write((delayIn * filterBankDelayFBLevelInv) + ((ddelayFeedback + (delayIn * filterBankDelayFBLevel)) * delayed));
float delayed1 = enableMediumDelay ? ddelay1.read(ddelayTime1) : 0.f;
ddelay1.write(delayIn + (ddelayFeedback1 * delayed1));
float delayed2 = enableShortDelay ? ddelay2.read(ddelayTime2) : 0.f;
ddelay2.write(delayIn + (ddelayFeedback2 * delayed2));
float delaySum = delayed + delayed1 + delayed2;
//////////////// VERB
float verbIn = enableReverb ? filterBankOut : 0.f;
if (enableDelayToReverb && enableReverb) {
verbIn += (delayToVerbLevel * delaySum);
}
float verbOut=0.f; float verbOut=0.f;
verbOut = lpcomb0.lpcombfb(filterBankOut, SIZE_comb0, lp0fb, lp0cutoff); verbOut = lpcomb0.lpcombfb(filterBankOut, SIZE_comb0, lp0fb, lp0cutoff);
verbOut += lpcomb1.lpcombfb(filterBankOut, SIZE_comb1, lp1fb, lp1cutoff); verbOut += lpcomb1.lpcombfb(filterBankOut, SIZE_comb1, lp1fb, lp1cutoff);
verbOut += lpcomb2.lpcombfb(filterBankOut, SIZE_comb2, lp2fb, lp2cutoff); verbOut += lpcomb2.lpcombfb(filterBankOut, SIZE_comb2, lp2fb, lp2cutoff);
@ -147,11 +209,11 @@ public:
verbOut = allp2.allpass(verbOut, SIZE_allp2, allp2fb); verbOut = allp2.allpass(verbOut, SIZE_allp2, allp2fb);
verbOut = allp3.allpass(verbOut, SIZE_allp3, allp3fb); verbOut = allp3.allpass(verbOut, SIZE_allp3, allp3fb);
float y= (sqrtf(verbVsDelayLevel) * delaySum) + (sqrtf(1.f - verbVsDelayLevel) * verbOut);
float delayed = ddelay.read(ddelayTime); //feedback
ddelay.write(filterBankOut + (ddelayFeedback * delayed)); delaysFB = delaySum;
verbFB = verbOut;
float y= delayed + verbOut;
@ -172,8 +234,30 @@ public:
__attribute__((always_inline)) void ProcessParams(const std::array<float, NPARAMS>& params) __attribute__((always_inline)) void ProcessParams(const std::array<float, NPARAMS>& params)
{ {
// currentVoiceSpace(params); controlMessages msg;
neuralNetOutputs = params; while (queue_try_remove(&controlMessageQueue, &msg)) {
switch(msg) {
case controlMessages::MSG_ENABLE_FILTERBANK:
enableFilterbank = !enableFilterbank;
break;
case controlMessages::MSG_ENABLE_REVERB:
enableReverb = !enableReverb;
break;
case controlMessages::MSG_ENABLE_SHORT_DELAY:
enableShortDelay = !enableShortDelay;
break;
case controlMessages::MSG_ENABLE_MEDIUM_DELAY:
enableMediumDelay = !enableMediumDelay;
break;
case controlMessages::MSG_ENABLE_LONG_DELAY:
enableLongDelay = !enableLongDelay;
break;
case controlMessages::MSG_ENABLE_DELAY_TO_REVERB:
enableDelayToReverb = !enableDelayToReverb;
break;
}
}
currentVoiceSpace(params);
} }
@ -219,15 +303,37 @@ protected:
maxiFilter filterBank6; maxiFilter filterBank6;
maxiFilter filterBank7; maxiFilter filterBank7;
DynamicDelay<8192> ddelay; DynamicDelay<16384> ddelay;
DynamicDelay<2048> ddelay1;
DynamicDelay<512> ddelay2;
maxiDCBlocker dcb; maxiDCBlocker dcb;
float wetdry_mix_{0.5f}; float wetdry_mix_{0.5f};
// mapping
float lp0fb{0}, lp0cutoff{0};
float lp1fb{0}, lp1cutoff{0};
float lp2fb{0}, lp2cutoff{0};
float lp3fb{0}, lp3cutoff{0};
float lp4fb{0}, lp4cutoff{0};
float lp5fb{0}, lp5cutoff{0};
float lp6fb{0}, lp6cutoff{0};
float lp7fb{0}, lp7cutoff{0};
float allp0fb{0}, allp1fb{0}, allp2fb{0}, allp3fb{0};
float filterBankF0{0}, filterBankF1{0}, filterBankF2{0}, filterBankF3{0};
float filterBankF4{0}, filterBankF5{0}, filterBankF6{0}, filterBankF7{0};
float filterBankRes0{0}, filterBankRes1{0}, filterBankRes2{0}, filterBankRes3{0};
float filterBankRes4{0}, filterBankRes5{0}, filterBankRes6{0}, filterBankRes7{0};
float ddelayTime{0}, ddelayFeedback{0};
float ddelayTime1{0}, ddelayFeedback1{0};
float ddelayTime2{0}, ddelayFeedback2{0};
float verbVsDelayLevel{0}, delayToVerbLevel{0}, filterBankDelayXFade{0};
OnePoleSmoother<kN_Params> smoother{150.f, kSampleRate}; OnePoleSmoother<kN_Params> smoother{150.f, kSampleRate};
maxiOsc lfo1; maxiDynamicsLite limiter;
}; };

View file

@ -32,6 +32,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, BreakOrAudioApp<>::kN_Params); interface.setup(kN_InputParams, BreakOrAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
interface.setModeInfo("breakor", "BreakOr");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly

View file

@ -20,6 +20,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params); interface.setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); //set 4D joystick interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); //set 4D joystick
interface.setModeInfo("chstrip", "ChannelStrip");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
} }

View file

@ -32,6 +32,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, ElysiamorfAudioApp<>::kN_Params); interface.setup(kN_InputParams, ElysiamorfAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
interface.setModeInfo("elysia", "Elysiamorfs");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly

View file

@ -23,6 +23,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params); interface.setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
interface.setModeInfo("pafsynth", "PAFSynth");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
} }

View file

@ -28,6 +28,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, ThruAudioApp<>::kN_Params); interface.setup(kN_InputParams, ThruAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK_AND_MACHINE_LISTENING); interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK_AND_MACHINE_LISTENING);
interface.setModeInfo("samidi", "SoundAnalMIDI");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
} }

View file

@ -22,11 +22,15 @@ public:
// SharedBuffer<float, XiasriAnalysis::kN_Params> machine_list_buffer; // SharedBuffer<float, XiasriAnalysis::kN_Params> machine_list_buffer;
VerbFXAudioApp<> audioAppVerbFX; VerbFXAudioApp<> audioAppVerbFX;
std::array<String, VerbFXAudioApp<>::nVoiceSpaces> voiceSpaceList;
std::shared_ptr<MIDIInOut> midi_interf; std::shared_ptr<MIDIInOut> midi_interf;
std::shared_ptr<BlockSelectView> enableView;
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, VerbFXAudioApp<>::kN_Params); interface.setup(kN_InputParams, VerbFXAudioApp<>::kN_Params);
interface.bindInterface(MEMLNAUT_INPUT_MODE, JOYSTICK_IS_4D); interface.bindInterface(MEMLNAUT_INPUT_MODE, JOYSTICK_IS_4D);
interface.setModeInfo("verbfx", "VerbFX");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
} }
@ -46,10 +50,36 @@ public:
} }
void addViews() { void addViews() {
enableView = std::make_shared<BlockSelectView>("FX Enable", TFT_YELLOW, 6, 80, 70, TFT_BLACK,
std::vector<String>{ "FilterBnk", "Reverb", "ShortDly", "MedDly", "LongDly", "Dly->Verb" },
TFT_BLUE, 2);
enableView->SetOnSelectCallback([this](size_t id) {
enableView->toggleAlt(id - 1);
queue_t& q = audioAppVerbFX.controlMessageQueue;
switch(id) {
case 1: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_FILTERBANK; queue_try_add(&q, &msg); } break;
case 2: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_REVERB; queue_try_add(&q, &msg); } break;
case 3: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_SHORT_DELAY; queue_try_add(&q, &msg); } break;
case 4: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_MEDIUM_DELAY; queue_try_add(&q, &msg); } break;
case 5: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_LONG_DELAY; queue_try_add(&q, &msg); } break;
case 6: { auto msg = VerbFXAudioApp<>::controlMessages::MSG_ENABLE_DELAY_TO_REVERB; queue_try_add(&q, &msg); } break;
}
});
MEMLNaut::Instance()->disp->AddView(enableView);
std::shared_ptr<VoiceSpaceSelectView> voiceSpaceSelectView;
voiceSpaceSelectView = std::make_shared<VoiceSpaceSelectView>("Voice Spaces");
MEMLNaut::Instance()->disp->InsertViewAfter(interface.rlStatsView, voiceSpaceSelectView);
voiceSpaceSelectView->setOptions(voiceSpaceList);
voiceSpaceSelectView->setNewVoiceCallback(
[this](size_t idx) {
audioAppVerbFX.setVoiceSpace(idx);
});
}; };
void setupAudio(float sample_rate) { void setupAudio(float sample_rate) {
audioAppVerbFX.Setup(sample_rate, interfacePtr); audioAppVerbFX.Setup(sample_rate, interfacePtr);
voiceSpaceList = audioAppVerbFX.getVoiceSpaceNames();
// Reinitialize XiasriAnalysis filters after maxiSettings is properly configured // Reinitialize XiasriAnalysis filters after maxiSettings is properly configured
// mlAnalysis.ReinitFilters(); // mlAnalysis.ReinitFilters();
} }

View file

@ -27,6 +27,7 @@ public:
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, XIASRIAudioApp<>::kN_Params); interface.setup(kN_InputParams, XIASRIAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::MACHINE_LISTENING); interface.bindInterface(InterfaceRL::INPUT_MODES::MACHINE_LISTENING);
interface.setModeInfo("xiasri", "XIASRI");
interfacePtr = make_non_owning(interface); interfacePtr = make_non_owning(interface);
} }

@ -1 +1 @@
Subproject commit 5d67d157228572f458b2744296c3e9585289187d Subproject commit 18b6f28f764e9515b3213808d6b96cb5b7f5cefa

View file

@ -0,0 +1,7 @@
#ifndef __VOICE_SPACE_VERBFX_BASIC_HPP__
#define __VOICE_SPACE_VERBFX_BASIC_HPP__
#define VOICE_SPACE_VERBFX_DEFAULT_BODY \
neuralNetOutputs = params; \
#endif