Update fx with faust helpers, change oversampling strategy

This commit is contained in:
Jean Pierre Cimalando 2021-02-25 00:16:24 +01:00
parent cd43cac59b
commit 5c5c434297
10 changed files with 88 additions and 82 deletions

View file

@ -340,6 +340,44 @@ foreach(filter_type
"sfizz/gen/filters/sfz2ch${filter_type}.hxx") "sfizz/gen/filters/sfz2ch${filter_type}.hxx")
endforeach() endforeach()
# Faust effects
add_faust_command(
"sfizz/effects/dsp/compressor.dsp"
"sfizz/effects/gen/compressor.hxx"
IN_PLACE
CLASS_NAME "faustCompressor"
IMPORT_DIRS "sfizz/dsp")
add_faust_command(
"sfizz/effects/dsp/disto_stage.dsp"
"sfizz/effects/gen/disto_stage.hxx"
IN_PLACE
CLASS_NAME "faustDisto"
IMPORT_DIRS "sfizz/dsp")
add_faust_command(
"sfizz/effects/dsp/fverb.dsp"
"sfizz/effects/gen/fverb.hxx"
IN_PLACE
CLASS_NAME "faustFverb"
IMPORT_DIRS "sfizz/dsp")
add_faust_command(
"sfizz/effects/dsp/gate.dsp"
"sfizz/effects/gen/gate.hxx"
IN_PLACE
CLASS_NAME "faustGate"
IMPORT_DIRS "sfizz/dsp")
add_faust_command(
"sfizz/effects/dsp/limiter.dsp"
"sfizz/effects/gen/limiter.hxx"
IN_PLACE
CLASS_NAME "faustLimiter"
IMPORT_DIRS "sfizz/dsp")
target_sources(sfizz_internal PRIVATE
"sfizz/effects/gen/compressor.hxx"
"sfizz/effects/gen/disto_stage.hxx"
"sfizz/effects/gen/fverb.hxx"
"sfizz/effects/gen/gate.hxx"
"sfizz/effects/gen/limiter.hxx")
# Windows installer # Windows installer
if(WIN32) if(WIN32)
include(VSTConfig) include(VSTConfig)

View file

@ -17,6 +17,7 @@
*/ */
#include "Compressor.h" #include "Compressor.h"
#include "gen/compressor.hxx"
#include "Opcode.h" #include "Opcode.h"
#include "AudioSpan.h" #include "AudioSpan.h"
#include "MathHelpers.h" #include "MathHelpers.h"
@ -24,8 +25,6 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
static constexpr int _oversampling = 2; static constexpr int _oversampling = 2;
#define FAUST_UIMACROS 1
#include "gen/compressor.hxx"
namespace sfz { namespace sfz {
namespace fx { namespace fx {
@ -38,12 +37,6 @@ namespace fx {
AudioBuffer<float, 2> _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer<float, 2> _gain2x { 2, _oversampling * config::defaultSamplesPerBlock };
hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; hiir::Downsampler2x<12> _downsampler2x[EffectChannels];
hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; hiir::Upsampler2x<12> _upsampler2x[EffectChannels];
#define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \
float get_##ident(size_t i) const noexcept { return _compressor[i].var; } \
void set_##ident(size_t i, float value) noexcept { _compressor[i].var = value; }
FAUST_LIST_ACTIVES(DEFINE_SET_GET);
#undef DEFINE_SET_GET
}; };
Compressor::Compressor() Compressor::Compressor()
@ -62,8 +55,8 @@ namespace fx {
{ {
Impl& impl = *_impl; Impl& impl = *_impl;
for (faustCompressor& comp : impl._compressor) { for (faustCompressor& comp : impl._compressor) {
comp.classInit(sampleRate); comp.classInit(_oversampling * sampleRate);
comp.instanceConstants(sampleRate); comp.instanceConstants(_oversampling * sampleRate);
} }
for (unsigned c = 0; c < EffectChannels; ++c) { for (unsigned c = 0; c < EffectChannels; ++c) {
@ -164,29 +157,29 @@ namespace fx {
case hash("comp_attack"): case hash("comp_attack"):
{ {
auto value = opc.read(Default::compAttack); auto value = opc.read(Default::compAttack);
for (size_t c = 0; c < 2; ++c) for (faustCompressor& comp : impl._compressor)
impl.set_Attack(c, value); comp.setAttack(value);
} }
break; break;
case hash("comp_release"): case hash("comp_release"):
{ {
auto value = opc.read(Default::compRelease); auto value = opc.read(Default::compRelease);
for (size_t c = 0; c < 2; ++c) for (faustCompressor& comp : impl._compressor)
impl.set_Release(c, value); comp.setRelease(value);
} }
break; break;
case hash("comp_threshold"): case hash("comp_threshold"):
{ {
auto value = opc.read(Default::compThreshold); auto value = opc.read(Default::compThreshold);
for (size_t c = 0; c < 2; ++c) for (faustCompressor& comp : impl._compressor)
impl.set_Threshold(c, value); comp.setThreshold(value);
} }
break; break;
case hash("comp_ratio"): case hash("comp_ratio"):
{ {
auto value = opc.read(Default::compRatio); auto value = opc.read(Default::compRatio);
for (size_t c = 0; c < 2; ++c) for (faustCompressor& comp : impl._compressor)
impl.set_Ratio(c, value); comp.setRatio(value);
} }
break; break;
case hash("comp_gain"): case hash("comp_gain"):

View file

@ -19,6 +19,7 @@
*/ */
#include "Disto.h" #include "Disto.h"
#include "gen/disto_stage.hxx"
#include "Opcode.h" #include "Opcode.h"
#include "Config.h" #include "Config.h"
#include "MathHelpers.h" #include "MathHelpers.h"
@ -27,8 +28,6 @@
#include <cmath> #include <cmath>
static constexpr int _oversampling = 8; static constexpr int _oversampling = 8;
#define FAUST_UIMACROS 1
#include "gen/disto_stage.hxx"
namespace sfz { namespace sfz {
namespace fx { namespace fx {
@ -56,12 +55,6 @@ struct Disto::Impl {
float mk = 21.0f + _tone * 1.08f; float mk = 21.0f + _tone * 1.08f;
return 440.0f * std::exp2((mk - 69.0f) * (1.0f / 12.0f)); return 440.0f * std::exp2((mk - 69.0f) * (1.0f / 12.0f));
} }
#define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \
float get_##ident(size_t c, size_t s) const noexcept { return _stages[c][s].var; } \
void set_##ident(size_t c, size_t s, float value) noexcept { _stages[c][s].var = value; }
FAUST_LIST_ACTIVES(DEFINE_SET_GET);
#undef DEFINE_SET_GET
}; };
Disto::Disto() Disto::Disto()
@ -71,7 +64,7 @@ Disto::Disto()
for (unsigned c = 0; c < EffectChannels; ++c) { for (unsigned c = 0; c < EffectChannels; ++c) {
for (faustDisto& stage : impl._stages[c]) for (faustDisto& stage : impl._stages[c])
stage.init(config::defaultSampleRate); stage.init(_oversampling * config::defaultSampleRate);
} }
} }
@ -86,8 +79,8 @@ void Disto::setSampleRate(double sampleRate)
for (unsigned c = 0; c < EffectChannels; ++c) { for (unsigned c = 0; c < EffectChannels; ++c) {
for (faustDisto& stage : impl._stages[c]) { for (faustDisto& stage : impl._stages[c]) {
stage.classInit(sampleRate); stage.classInit(_oversampling * sampleRate);
stage.instanceConstants(sampleRate); stage.instanceConstants(_oversampling * sampleRate);
} }
} }
} }
@ -150,7 +143,7 @@ void Disto::process(const float* const inputs[], float* const outputs[], unsigne
absl::Span<float> stageInOut = upsamplerOut; absl::Span<float> stageInOut = upsamplerOut;
for (unsigned s = 0, numStages = impl._numStages; s < numStages; ++s) { for (unsigned s = 0, numStages = impl._numStages; s < numStages; ++s) {
// set depth parameter (TODO modulation) // set depth parameter (TODO modulation)
impl.set_Depth(c, s, depth); impl._stages[c][s].setDepth(depth);
// //
float *faustIn[] = { stageInOut.data() }; float *faustIn[] = { stageInOut.data() };
float *faustOut[] = { stageInOut.data() }; float *faustOut[] = { stageInOut.data() };

View file

@ -5,14 +5,13 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "Fverb.h" #include "Fverb.h"
#include "gen/fverb.hxx"
#include "Opcode.h" #include "Opcode.h"
#include "Config.h" #include "Config.h"
#include "MathHelpers.h" #include "MathHelpers.h"
#include <absl/memory/memory.h> #include <absl/memory/memory.h>
#include <absl/strings/ascii.h> #include <absl/strings/ascii.h>
#include <cmath> #include <cmath>
#define FAUST_UIMACROS 1
#include "gen/fverb.hxx"
/** /**
Note(jpc): implementation status Note(jpc): implementation status
@ -40,12 +39,6 @@ namespace fx {
struct Fverb::Impl { struct Fverb::Impl {
faustFverb dsp; faustFverb dsp;
#define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \
float get_##ident() const noexcept { return dsp.var; } \
void set_##ident(float value) noexcept { dsp.var = value; }
FAUST_LIST_ACTIVES(DEFINE_SET_GET);
#undef DEFINE_SET_GET
struct Profile { struct Profile {
float tailDensity; // % float tailDensity; // %
float decayAtMaxSize; // % float decayAtMaxSize; // %
@ -240,17 +233,18 @@ namespace fx {
const float decayMin = decayMax * 0.5f; const float decayMin = decayMax * 0.5f;
Impl& impl = *reverb->impl_; Impl& impl = *reverb->impl_;
impl.set_Predelay(predelay * 1e3); faustFverb& dsp = impl.dsp;
impl.set_Tail_density(profile->tailDensity); dsp.setPredelay(predelay * 1e3);
impl.set_Decay(decayMax * size * 0.01f + decayMin * (1.0f - size * 0.01f)); dsp.setTailDensity(profile->tailDensity);
impl.set_Modulator_frequency(profile->modulationFrequency); dsp.setDecay(decayMax * size * 0.01f + decayMin * (1.0f - size * 0.01f));
impl.set_Modulator_depth(profile->modulationDepth); dsp.setModulatorFrequency(profile->modulationFrequency);
impl.set_Dry(profile->dry * dry * 0.01f); dsp.setModulatorDepth(profile->modulationDepth);
impl.set_Wet(profile->wet * wet * 0.01f); dsp.setDry(profile->dry * dry * 0.01f);
impl.set_Input_amount(input); dsp.setWet(profile->wet * wet * 0.01f);
impl.set_Input_low_pass_cutoff(Impl::lpfCutoff(tone)); dsp.setInputAmount(input);
dsp.setInputLowPassCutoff(Impl::lpfCutoff(tone));
// NOTE(jpc): damp formula not well calibrated, but sounds ok-ish // NOTE(jpc): damp formula not well calibrated, but sounds ok-ish
impl.set_Damping(Impl::lpfCutoff(100 - 0.5 * damp)); dsp.setDamping(Impl::lpfCutoff(100 - 0.5 * damp));
return fx; return fx;
} }

View file

@ -20,6 +20,7 @@
*/ */
#include "Gate.h" #include "Gate.h"
#include "gen/gate.hxx"
#include "Opcode.h" #include "Opcode.h"
#include "AudioSpan.h" #include "AudioSpan.h"
#include "MathHelpers.h" #include "MathHelpers.h"
@ -27,8 +28,6 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
static constexpr int _oversampling = 2; static constexpr int _oversampling = 2;
#define FAUST_UIMACROS 1
#include "gen/gate.hxx"
namespace sfz { namespace sfz {
namespace fx { namespace fx {
@ -41,12 +40,6 @@ namespace fx {
AudioBuffer<float, 2> _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer<float, 2> _gain2x { 2, _oversampling * config::defaultSamplesPerBlock };
hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; hiir::Downsampler2x<12> _downsampler2x[EffectChannels];
hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; hiir::Upsampler2x<12> _upsampler2x[EffectChannels];
#define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \
float get_##ident(size_t i) const noexcept { return _gate[i].var; } \
void set_##ident(size_t i, float value) noexcept { _gate[i].var = value; }
FAUST_LIST_ACTIVES(DEFINE_SET_GET);
#undef DEFINE_SET_GET
}; };
Gate::Gate() Gate::Gate()
@ -65,8 +58,8 @@ namespace fx {
{ {
Impl& impl = *_impl; Impl& impl = *_impl;
for (faustGate& gate : impl._gate) { for (faustGate& gate : impl._gate) {
gate.classInit(sampleRate); gate.classInit(_oversampling * sampleRate);
gate.instanceConstants(sampleRate); gate.instanceConstants(_oversampling * sampleRate);
} }
for (unsigned c = 0; c < EffectChannels; ++c) { for (unsigned c = 0; c < EffectChannels; ++c) {
@ -167,29 +160,29 @@ namespace fx {
case hash("gate_attack"): case hash("gate_attack"):
{ {
auto value = opc.read(Default::gateAttack); auto value = opc.read(Default::gateAttack);
for (size_t c = 0; c < 2; ++c) for (faustGate& gate : impl._gate)
impl.set_Attack(c, value); gate.setAttack(value);
} }
break; break;
case hash("gate_hold"): case hash("gate_hold"):
{ {
auto value = opc.read(Default::gateHold); auto value = opc.read(Default::gateHold);
for (size_t c = 0; c < 2; ++c) for (faustGate& gate : impl._gate)
impl.set_Hold(c, value); gate.setHold(value);
} }
break; break;
case hash("gate_release"): case hash("gate_release"):
{ {
auto value = opc.read(Default::gateRelease); auto value = opc.read(Default::gateRelease);
for (size_t c = 0; c < 2; ++c) for (faustGate& gate : impl._gate)
impl.set_Release(c, value); gate.setRelease(value);
} }
break; break;
case hash("gate_threshold"): case hash("gate_threshold"):
{ {
auto value = opc.read(Default::gateThreshold); auto value = opc.read(Default::gateThreshold);
for (size_t c = 0; c < 2; ++c) for (faustGate& gate : impl._gate)
impl.set_Threshold(c, value); gate.setThreshold(value);
} }
break; break;
case hash("gate_stlink"): case hash("gate_stlink"):

View file

@ -11,12 +11,12 @@
*/ */
#include "Limiter.h" #include "Limiter.h"
#include "gen/limiter.hxx"
#include "Opcode.h" #include "Opcode.h"
#include "AudioSpan.h" #include "AudioSpan.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
static constexpr int _oversampling = 2; static constexpr int _oversampling = 2;
#include "gen/limiter.hxx"
namespace sfz { namespace sfz {
namespace fx { namespace fx {
@ -33,8 +33,8 @@ namespace fx {
void Limiter::setSampleRate(double sampleRate) void Limiter::setSampleRate(double sampleRate)
{ {
_limiter->classInit(sampleRate); _limiter->classInit(_oversampling * sampleRate);
_limiter->instanceConstants(sampleRate); _limiter->instanceConstants(_oversampling * sampleRate);
for (unsigned c = 0; c < EffectChannels; ++c) { for (unsigned c = 0; c < EffectChannels; ++c) {
_downsampler2x[c].set_coefs(OSCoeffs2x); _downsampler2x[c].set_coefs(OSCoeffs2x);

View file

@ -3,9 +3,8 @@ import("stdfaust.lib");
cgain = co.compression_gain_mono(ratio, thresh, att, rel) with { cgain = co.compression_gain_mono(ratio, thresh, att, rel) with {
ratio = hslider("[1] Ratio", 1.0, 1.0, 20.0, 0.01); ratio = hslider("[1] Ratio", 1.0, 1.0, 20.0, 0.01);
thresh = hslider("[2] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01); thresh = hslider("[2] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01);
over = fconstant(int _oversampling, <math.h>); att = hslider("[3] Attack [unit:s]", 0.0, 0.0, 0.5, 1e-3);
att = hslider("[3] Attack [unit:s]", 0.0, 0.0, 0.5, 1e-3) : *(over); rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3);
rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3) : *(over);
}; };
process = cgain; process = cgain;

View file

@ -1,14 +1,12 @@
import("stdfaust.lib"); import("stdfaust.lib");
disto_stage(depth, x) = shs*hh(x)+(1.0-shs)*lh(x) : fi.dcblockerat(5.0) with { disto_stage(depth, x) = shs*hh(x)+(1.0-shs)*lh(x) : fi.dcblockerat(5.0) with {
over = fconstant(int _oversampling, <math.h>);
// sigmoid parameters // sigmoid parameters
a = depth*0.2+2.0; a = depth*0.2+2.0;
b = 2.0; b = 2.0;
// smooth hysteresis transition // smooth hysteresis transition
shs = hs : si.smooth(ba.tau2pole(10e-3*over)); shs = hs : si.smooth(ba.tau2pole(10e-3));
// the low and high hysteresis // the low and high hysteresis
lh(x) = sig(a*x)*b; lh(x) = sig(a*x)*b;

View file

@ -2,10 +2,9 @@ import("stdfaust.lib");
ggain = ef.gate_gain_mono(thresh, att, hold, rel) with { ggain = ef.gate_gain_mono(thresh, att, hold, rel) with {
thresh = hslider("[1] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01); thresh = hslider("[1] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01);
over = fconstant(int _oversampling, <math.h>); att = hslider("[2] Attack [unit:s]", 0.0, 0.0, 10.0, 1e-3);
att = hslider("[2] Attack [unit:s]", 0.0, 0.0, 10.0, 1e-3) : *(over); hold = hslider("[3] Hold [unit:s]", 0.0, 0.0, 10.0, 1e-3);
hold = hslider("[3] Hold [unit:s]", 0.0, 0.0, 10.0, 1e-3) : *(over); rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3);
rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3) : *(over);
}; };
process = ggain; process = ggain;

View file

@ -1,9 +1,8 @@
import("stdfaust.lib"); import("stdfaust.lib");
limiter(x) = gain*x with { limiter(x) = gain*x with {
att = 0.0008 * over; att = 0.0008;
rel = 0.5 * over; rel = 0.5;
over = fconstant(int _oversampling, <math.h>);
peak = x : an.amp_follower_ud(att, rel); peak = x : an.amp_follower_ud(att, rel);
gain = ba.if(peak>1.0, 1.0/peak, 1.0) : si.smooth(ba.tau2pole(0.5*att)); gain = ba.if(peak>1.0, 1.0/peak, 1.0) : si.smooth(ba.tau2pole(0.5*att));
}; };