refactor and block select font size option
This commit is contained in:
parent
56c1189c5e
commit
8be4f85cb6
12 changed files with 217 additions and 357 deletions
|
|
@ -9,7 +9,6 @@
|
|||
#include <memory> // Added for std::shared_ptr
|
||||
|
||||
#include "src/memllib/synth/maxiPAF.hpp"
|
||||
#include "src/memllib/synth/ADSRLite.hpp"
|
||||
#include "src/memllib/interface/InterfaceBase.hpp" // Added missing include
|
||||
|
||||
#include <span>
|
||||
|
|
@ -132,294 +131,6 @@ private:
|
|||
// 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>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//machine config
|
||||
|
||||
#define JOYSTICK_IS_4D false
|
||||
#define JOYSTICK_IS_4D true
|
||||
#define MEMLNAUT_ANALOG_INPUTS 3 + (JOYSTICK_IS_4D ? 1 : 0)
|
||||
#define MEMLNAUT_INPUT_MODE InterfaceRL::INPUT_MODES::JOYSTICK
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <span>
|
||||
#include "../../voicespaces/VoiceSpaces.hpp"
|
||||
#include "../../voicespaces/VerbFX/basic.hpp"
|
||||
#include "../../src/memllib/synth/OnePoleSmoother.hpp"
|
||||
#include "../../src/memllib/synth/maximilian.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>
|
||||
{
|
||||
public:
|
||||
|
|
@ -31,6 +32,25 @@ public:
|
|||
|
||||
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> names;
|
||||
for(size_t i=0; i < voiceSpaces.size(); i++) {
|
||||
|
|
@ -46,90 +66,132 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
static float verbFB = 0.f;
|
||||
static float delaysFB = 0.f;
|
||||
|
||||
float mix = x.L + x.R;
|
||||
|
||||
smoother.Process(neuralNetOutputs.data(), smoothParams.data());
|
||||
|
||||
//mapping
|
||||
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;
|
||||
const float lp1cutoff = (smoothParams[4] * 0.5f) + 0.05f;
|
||||
lp0fb = smoothParams[1] * 0.9f;
|
||||
lp0cutoff = (smoothParams[2] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp2fb = smoothParams[5] * 0.98f;
|
||||
const float lp2cutoff = (smoothParams[6] * 0.5f) + 0.05f;
|
||||
lp1fb = smoothParams[3] * 0.9f;
|
||||
lp1cutoff = (smoothParams[4] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp3fb = smoothParams[7] * 0.98f;
|
||||
const float lp3cutoff = (smoothParams[8] * 0.5f) + 0.05f;
|
||||
lp2fb = smoothParams[5] * 0.9f;
|
||||
lp2cutoff = (smoothParams[6] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp4fb = smoothParams[9] * 0.98f;
|
||||
const float lp4cutoff = (smoothParams[10] * 0.5f) + 0.05f;
|
||||
lp3fb = smoothParams[7] * 0.9f;
|
||||
lp3cutoff = (smoothParams[8] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp5fb = smoothParams[11] * 0.98f;
|
||||
const float lp5cutoff = (smoothParams[12] * 0.5f) + 0.05f;
|
||||
lp4fb = smoothParams[9] * 0.9f;
|
||||
lp4cutoff = (smoothParams[10] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp6fb = smoothParams[13] * 0.98f;
|
||||
const float lp6cutoff = (smoothParams[14] * 0.5f) + 0.05f;
|
||||
lp5fb = smoothParams[11] * 0.98f;
|
||||
lp5cutoff = (smoothParams[12] * 0.5f) + 0.05f;
|
||||
|
||||
const float lp7fb = smoothParams[15] * 0.98f;
|
||||
const float lp7cutoff = (smoothParams[16] * 0.5f) + 0.05f;
|
||||
lp6fb = smoothParams[13] * 0.9;
|
||||
lp6cutoff = (smoothParams[14] * 0.5f) + 0.05f;
|
||||
|
||||
const float allp0fb = smoothParams[17] * 0.98f;
|
||||
const float allp1fb = smoothParams[18] * 0.98f;
|
||||
const float allp2fb = smoothParams[19] * 0.98f;
|
||||
const float allp3fb = smoothParams[20] * 0.98f;
|
||||
lp7fb = smoothParams[15] * 0.9f;
|
||||
lp7cutoff = (smoothParams[16] * 0.5f) + 0.05f;
|
||||
|
||||
const float filterBankF0 = 40.f + (smoothParams[21] * 40.f);
|
||||
const float filterBankF1 = 80.f + (smoothParams[22] * 80.f);
|
||||
const float filterBankF2 = 160.f + (smoothParams[23] * 160.f);
|
||||
const float filterBankF3 = 320.f + (smoothParams[24] * 320.f);
|
||||
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);
|
||||
allp0fb = smoothParams[17] * 0.9f;
|
||||
allp1fb = smoothParams[18] * 0.9f;
|
||||
allp2fb = smoothParams[19] * 0.9f;
|
||||
allp3fb = smoothParams[20] * 0.9f;
|
||||
|
||||
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);
|
||||
const float filterBankRes1 = 1.f + (smoothParams[30] * 18.f);
|
||||
const float filterBankRes2 = 1.f + (smoothParams[31] * 18.f);
|
||||
const float filterBankRes3 = 1.f + (smoothParams[32] * 18.f);
|
||||
const float filterBankRes4 = 1.f + (smoothParams[33] * 18.f);
|
||||
const float filterBankRes5 = 1.f + (smoothParams[34] * 18.f);
|
||||
const float filterBankRes6 = 1.f + (smoothParams[35] * 18.f);
|
||||
const float filterBankRes7 = 1.f + (smoothParams[36] * 18.f);
|
||||
filterBankRes0 = 1.f + (smoothParams[29] * 19.f);
|
||||
filterBankRes1 = 1.f + (smoothParams[30] * 19.f);
|
||||
filterBankRes2 = 1.f + (smoothParams[31] * 19.f);
|
||||
filterBankRes3 = 1.f + (smoothParams[32] * 19.f);
|
||||
filterBankRes4 = 1.f + (smoothParams[33] * 19.f);
|
||||
filterBankRes5 = 1.f + (smoothParams[34] * 19.f);
|
||||
filterBankRes6 = 1.f + (smoothParams[35] * 19.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);
|
||||
const float ddelayFeedback = (smoothParams[38] * 0.98f);
|
||||
ddelayTime1 = 10.f + (smoothParams[39] * 2037.f);
|
||||
ddelayFeedback1 = (smoothParams[40] * 0.98f);
|
||||
|
||||
const float filterBankLFOFreq = (smoothParams[39] * 0.5f);
|
||||
const float filterBankLFODepth = (smoothParams[40] * 0.3f);
|
||||
ddelayTime2 = 10.f + (smoothParams[41] * 501.f);
|
||||
ddelayFeedback2 = (smoothParams[42] * 0.98f);
|
||||
|
||||
float filterBankIn = mix;
|
||||
float filterBankOut=0;
|
||||
verbVsDelayLevel = smoothParams[43];
|
||||
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);
|
||||
filterBankOut += filterBank1.bandpassChamberlain(filterBankIn, filterBankF1 * filterBankFreqMod, filterBankRes1);
|
||||
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);
|
||||
const float filterBankDelayFBLevel = sqrtf(filterBankDelayXFade);
|
||||
const float filterBankDelayFBLevelInv = sqrtf(1.f - filterBankDelayXFade);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
verbOut = lpcomb0.lpcombfb(filterBankOut, SIZE_comb0, lp0fb, lp0cutoff);
|
||||
verbOut += lpcomb1.lpcombfb(filterBankOut, SIZE_comb1, lp1fb, lp1cutoff);
|
||||
verbOut += lpcomb2.lpcombfb(filterBankOut, SIZE_comb2, lp2fb, lp2cutoff);
|
||||
|
|
@ -147,11 +209,11 @@ public:
|
|||
verbOut = allp2.allpass(verbOut, SIZE_allp2, allp2fb);
|
||||
verbOut = allp3.allpass(verbOut, SIZE_allp3, allp3fb);
|
||||
|
||||
float y= (sqrtf(verbVsDelayLevel) * delaySum) + (sqrtf(1.f - verbVsDelayLevel) * verbOut);
|
||||
|
||||
float delayed = ddelay.read(ddelayTime);
|
||||
ddelay.write(filterBankOut + (ddelayFeedback * delayed));
|
||||
|
||||
float y= delayed + verbOut;
|
||||
//feedback
|
||||
delaysFB = delaySum;
|
||||
verbFB = verbOut;
|
||||
|
||||
|
||||
|
||||
|
|
@ -172,8 +234,30 @@ public:
|
|||
|
||||
__attribute__((always_inline)) void ProcessParams(const std::array<float, NPARAMS>& params)
|
||||
{
|
||||
// currentVoiceSpace(params);
|
||||
neuralNetOutputs = params;
|
||||
controlMessages msg;
|
||||
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 filterBank7;
|
||||
|
||||
DynamicDelay<8192> ddelay;
|
||||
DynamicDelay<16384> ddelay;
|
||||
DynamicDelay<2048> ddelay1;
|
||||
DynamicDelay<512> ddelay2;
|
||||
|
||||
maxiDCBlocker dcb;
|
||||
|
||||
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};
|
||||
|
||||
maxiOsc lfo1;
|
||||
maxiDynamicsLite limiter;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, BreakOrAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
|
||||
interface.setModeInfo("breakor", "BreakOr");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
|
||||
MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); //set 4D joystick
|
||||
interface.setModeInfo("chstrip", "ChannelStrip");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, ElysiamorfAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
|
||||
interface.setModeInfo("elysia", "Elysiamorfs");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
|
||||
MEMLNaut::Instance()->setTogA2Callback([this](bool state) { // scr_ref no longer captured directly
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
|
||||
interface.setModeInfo("pafsynth", "PAFSynth");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, ThruAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK_AND_MACHINE_LISTENING);
|
||||
interface.setModeInfo("samidi", "SoundAnalMIDI");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,15 @@ public:
|
|||
// SharedBuffer<float, XiasriAnalysis::kN_Params> machine_list_buffer;
|
||||
|
||||
VerbFXAudioApp<> audioAppVerbFX;
|
||||
std::array<String, VerbFXAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
||||
std::shared_ptr<MIDIInOut> midi_interf;
|
||||
std::shared_ptr<BlockSelectView> enableView;
|
||||
|
||||
|
||||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, VerbFXAudioApp<>::kN_Params);
|
||||
interface.bindInterface(MEMLNAUT_INPUT_MODE, JOYSTICK_IS_4D);
|
||||
interface.setModeInfo("verbfx", "VerbFX");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
}
|
||||
|
||||
|
|
@ -46,10 +50,36 @@ public:
|
|||
}
|
||||
|
||||
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) {
|
||||
audioAppVerbFX.Setup(sample_rate, interfacePtr);
|
||||
voiceSpaceList = audioAppVerbFX.getVoiceSpaceNames();
|
||||
// Reinitialize XiasriAnalysis filters after maxiSettings is properly configured
|
||||
// mlAnalysis.ReinitFilters();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public:
|
|||
void setupInterface() {
|
||||
interface.setup(kN_InputParams, XIASRIAudioApp<>::kN_Params);
|
||||
interface.bindInterface(InterfaceRL::INPUT_MODES::MACHINE_LISTENING);
|
||||
interface.setModeInfo("xiasri", "XIASRI");
|
||||
interfacePtr = make_non_owning(interface);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5d67d157228572f458b2744296c3e9585289187d
|
||||
Subproject commit 18b6f28f764e9515b3213808d6b96cb5b7f5cefa
|
||||
7
voicespaces/VerbFX/basic.hpp
Normal file
7
voicespaces/VerbFX/basic.hpp
Normal 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
|
||||
Loading…
Reference in a new issue