diff --git a/libs/sst/sst-basic-blocks b/libs/sst/sst-basic-blocks index 42675840a0d..a91558d6d92 160000 --- a/libs/sst/sst-basic-blocks +++ b/libs/sst/sst-basic-blocks @@ -1 +1 @@ -Subproject commit 42675840a0dd18bfd997f6394b874e0ec984b651 +Subproject commit a91558d6d92039a10e30d46ebffcdf13fb620b90 diff --git a/libs/sst/sst-effects b/libs/sst/sst-effects index a3384e447dd..28bd9994dc3 160000 --- a/libs/sst/sst-effects +++ b/libs/sst/sst-effects @@ -1 +1 @@ -Subproject commit a3384e447ddb010029288cc9579a493369cb5e60 +Subproject commit 28bd9994dc3cd54ab9f7e51e466cbb47bcd8816b diff --git a/src/common/dsp/effects/NimbusEffect.cpp b/src/common/dsp/effects/NimbusEffect.cpp index 36a93ed403e..9205884ad9f 100644 --- a/src/common/dsp/effects/NimbusEffect.cpp +++ b/src/common/dsp/effects/NimbusEffect.cpp @@ -21,222 +21,18 @@ */ #include "NimbusEffect.h" +#include "sst/effects/NimbusImpl.h" + #include "DebugHelpers.h" #include "fmt/core.h" -#ifdef _MSC_VER -#define __attribute__(x) -#endif - -#define TEST // remember this is how you tell the eurorack code to use dsp not hardware -#if EURORACK_CLOUDS_IS_SUPERPARASITES -#include "supercell/dsp/granular_processor.h" -#else -#include "clouds/dsp/granular_processor.h" -#endif - NimbusEffect::NimbusEffect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd) - : Effect(storage, fxdata, pd) + : parent_t(storage, fxdata, pd) { - const int memLen = 118784; - const int ccmLen = 65536 - 128; - block_mem = new uint8_t[memLen](); - block_ccm = new uint8_t[ccmLen](); - processor = new clouds::GranularProcessor(); -#if EURORACK_CLOUDS_IS_SUPERPARASITES -#else - memset(processor, 0, sizeof(*processor)); -#endif - - processor->Init(block_mem, memLen, block_ccm, ccmLen); - mix.set_blocksize(BLOCK_SIZE); sampleRateReset(); } -NimbusEffect::~NimbusEffect() -{ - delete[] block_mem; - delete[] block_ccm; - delete processor; -} - -void NimbusEffect::init() -{ - mix.set_target(1.f); - mix.instantize(); - - surgeSR_to_euroSR = std::make_unique(storage->samplerate, processor_sr); - euroSR_to_surgeSR = std::make_unique(processor_sr, storage->samplerate); - - memset(resampled_output, 0, raw_out_sz * 2 * sizeof(float)); - - consumed = 0; - created = 0; - builtBuffer = false; - resampReadPtr = 0; - resampWritePtr = 1; // why 1? well while we are stalling we want to output 0 so write 1 ahead -} - -void NimbusEffect::setvars(bool init) {} - -void NimbusEffect::process(float *dataL, float *dataR) -{ - setvars(false); - - if (!surgeSR_to_euroSR || !euroSR_to_surgeSR) - return; - - /* Resample Temp Buffers */ - float resample_this[2][BLOCK_SIZE << 3]; - float resample_into[2][BLOCK_SIZE << 3]; - - for (int i = 0; i < BLOCK_SIZE; ++i) - { - surgeSR_to_euroSR->push(dataL[i], dataR[i]); - } - - float srgToEur[2][BLOCK_SIZE << 3]; - auto outputFramesGen = - surgeSR_to_euroSR->populateNext(resample_into[0], resample_into[1], BLOCK_SIZE << 3); - - if (outputFramesGen) - { - clouds::ShortFrame input[BLOCK_SIZE << 3]; - clouds::ShortFrame output[BLOCK_SIZE << 3]; - - int frames_to_go = outputFramesGen; - int outpos = 0; - - auto modeInt = *pd_int[nmb_mode]; - // Just make sure we are safe if we swap between superparasites and not -#if EURORACK_CLOUDS_IS_SUPERPARASITES - modeInt = std::clamp(modeInt, 0, 7); -#else - modeInt = std::clamp(modeInt, 0, 3); -#endif - processor->set_playback_mode( - (clouds::PlaybackMode)((int)clouds::PLAYBACK_MODE_GRANULAR + modeInt)); - processor->set_quality(*pd_int[nmb_quality]); - - int consume_ptr = 0; - - while (frames_to_go + numStubs >= nimbusprocess_blocksize) - { - int sp = 0; - while (numStubs > 0) - { - input[sp].l = (short)(clamp1bp(stub_input[0][sp]) * 32767.0f); - input[sp].r = (short)(clamp1bp(stub_input[1][sp]) * 32767.0f); - sp++; - numStubs--; - } - - for (int i = sp; i < nimbusprocess_blocksize; ++i) - { - input[i].l = (short)(clamp1bp(resample_into[0][consume_ptr]) * 32767.0f); - input[i].r = (short)(clamp1bp(resample_into[1][consume_ptr]) * 32767.0f); - consume_ptr++; - } - - int inputSz = nimbusprocess_blocksize; // sdata.output_frames_gen + sp; - - auto parm = processor->mutable_parameters(); - - float den_val, tex_val; - - den_val = (*pd_float[nmb_density] + 1.f) * 0.5; - tex_val = (*pd_float[nmb_texture] + 1.f) * 0.5; - - parm->position = clamp01(*pd_float[nmb_position]); - parm->size = clamp01(*pd_float[nmb_size]); - parm->density = clamp01(den_val); - parm->texture = clamp01(tex_val); - parm->pitch = limit_range(*pd_float[nmb_pitch], -48.f, 48.f); - parm->stereo_spread = clamp01(*pd_float[nmb_spread]); - parm->feedback = clamp01(*pd_float[nmb_feedback]); - parm->freeze = *pd_float[nmb_freeze] > 0.5; - parm->reverb = clamp01(*pd_float[nmb_reverb]); - parm->dry_wet = 1.f; - -#if EURORACK_CLOUDS_IS_SUPERPARASITES - parm->capture = nimbusTrigger; -#else - parm->trigger = nimbusTrigger; // this is an external granulating source. Skip it -#endif - parm->gate = parm->freeze; // This is the CV for the freeze button - - processor->Prepare(); - processor->Process(input, output, inputSz); - - for (int i = 0; i < inputSz; ++i) - { - resample_this[0][outpos + i] = output[i].l / 32767.0f; - resample_this[1][outpos + i] = output[i].r / 32767.0f; - } - outpos += inputSz; - frames_to_go -= (nimbusprocess_blocksize - sp); - } - - if (frames_to_go > 0) - { - int startSub = numStubs; - int addStub = frames_to_go; - numStubs += frames_to_go; - - for (int i = 0; i < addStub; ++i) - { - stub_input[0][i + startSub] = resample_into[0][consume_ptr]; - stub_input[1][i + startSub] = resample_into[1][consume_ptr]; - consume_ptr++; - } - } - - if (outpos > 0) - { - for (int i = 0; i < outpos; ++i) - { - euroSR_to_surgeSR->push(resample_this[0][i], resample_this[1][i]); - } - - auto dsoutputFramesGen = euroSR_to_surgeSR->populateNext( - resample_into[0], resample_into[1], BLOCK_SIZE << 3); - created += dsoutputFramesGen; - - size_t w = resampWritePtr; - for (int i = 0; i < dsoutputFramesGen; ++i) - { - resampled_output[0][w] = resample_into[0][i]; - resampled_output[1][w] = resample_into[1][i]; - - w = (w + 1U) & (raw_out_sz - 1U); - } - resampWritePtr = w; - } - } - - // If you hit this you need to adjust this gapping ratio probably. - static_assert(BLOCK_SIZE >= nimbusprocess_blocksize); - int ratio = std::max((int)std::ceil(processor_sr_inv * storage->samplerate) - 2, 0); - bool rpi = (created) > (BLOCK_SIZE * (1 + ratio) + 8); // leave some buffer - if (rpi) - builtBuffer = true; - - size_t rp = resampReadPtr; - for (int i = 0; i < BLOCK_SIZE; ++i) - { - L[i] = resampled_output[0][rp]; - R[i] = resampled_output[1][rp]; - rp = (rp + rpi) & (raw_out_sz - 1); - } - resampReadPtr = rp; - - mix.set_target_smoothed(clamp01(*pd_float[nmb_mix])); - mix.fade_2_blocks_inplace(dataL, L, dataR, R, BLOCK_SIZE_QUAD); -} - -void NimbusEffect::suspend() { init(); } - const char *NimbusEffect::group_label(int id) { switch (id) @@ -415,26 +211,10 @@ void NimbusEffect::init_ctrltypes() fxdata->p[nmb_mix].set_type(ct_percent); fxdata->p[nmb_mix].val_default.f = 0.5; fxdata->p[nmb_mix].posy_offset = ypos; -} -void NimbusEffect::init_default_values() -{ - fxdata->p[nmb_mode].val.i = 0; - fxdata->p[nmb_quality].val.i = 0; - fxdata->p[nmb_position].val.f = 0.f; - fxdata->p[nmb_size].val.f = 0.5; - fxdata->p[nmb_density].val.f = 0.f; - fxdata->p[nmb_texture].val.f = 0.f; - fxdata->p[nmb_pitch].val.f = 0.f; - fxdata->p[nmb_freeze].val.f = 0.f; - fxdata->p[nmb_feedback].val.f = 0.f; - fxdata->p[nmb_reverb].val.f = 0.f; - fxdata->p[nmb_spread].val.f = 0.f; - fxdata->p[nmb_mix].val.f = 0.5; -} -void NimbusEffect::sampleRateReset() -{ - Effect::sampleRateReset(); - surgeSR_to_euroSR = std::make_unique(storage->samplerate, processor_sr); - euroSR_to_surgeSR = std::make_unique(processor_sr, storage->samplerate); + configureControlsFromFXMetadata(); } + +// Just to be safe, explicitly instantiate the base class. +template struct surge::sstfx::SurgeSSTFXBase< + sst::effects::nimbus::Nimbus>; \ No newline at end of file diff --git a/src/common/dsp/effects/NimbusEffect.h b/src/common/dsp/effects/NimbusEffect.h index f417667429c..ebc70f02d8d 100644 --- a/src/common/dsp/effects/NimbusEffect.h +++ b/src/common/dsp/effects/NimbusEffect.h @@ -24,87 +24,28 @@ #define SURGE_SRC_COMMON_DSP_EFFECTS_NIMBUSEFFECT_H #include "Effect.h" +#include "SurgeSSTFXAdapter.h" #include #include #include "sst/basic-blocks/dsp/LanczosResampler.h" +#include "sst/effects/Nimbus.h" namespace clouds { class GranularProcessor; } -struct SRC_STATE_tag; - -class NimbusEffect : public Effect +struct NimbusEffect + : public surge::sstfx::SurgeSSTFXBase> { - public: - enum nmb_params - { - nmb_mode, - nmb_quality, - - nmb_position, - nmb_size, - nmb_pitch, - nmb_density, - nmb_texture, - nmb_spread, - - nmb_freeze, - nmb_feedback, - - nmb_reverb, - nmb_mix, + using parent_t = + surge::sstfx::SurgeSSTFXBase>; - nmb_num_params, - }; - - private: - lipol_ps_blocksz mix alignas(16); - float L alignas(16)[BLOCK_SIZE], R alignas(16)[BLOCK_SIZE]; - - public: NimbusEffect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd); - virtual ~NimbusEffect(); - virtual const char *get_effectname() override { return "Nimbus"; } - virtual void init() override; - virtual void process(float *dataL, float *dataR) override; - virtual void suspend() override; - void setvars(bool init); virtual void init_ctrltypes() override; - virtual void init_default_values() override; - virtual const char *group_label(int id) override; virtual int group_label_ypos(int id) override; - - virtual int get_ringout_decay() override { return -1; } - - // Only used by rack - void setNimbusTrigger(bool b) { nimbusTrigger = b; } - - void sampleRateReset() override; - - private: - uint8_t *block_mem, *block_ccm; - clouds::GranularProcessor *processor; - static constexpr int processor_sr = 32000; - static constexpr float processor_sr_inv = 1.f / 32000; - int old_nmb_mode = 0; - bool nimbusTrigger{false}; - - using resamp_t = sst::basic_blocks::dsp::LanczosResampler; - std::unique_ptr surgeSR_to_euroSR, euroSR_to_surgeSR; - - static constexpr int raw_out_sz = BLOCK_SIZE_OS << 5; // power of 2 pls - float resampled_output[2][raw_out_sz]; // at sr - size_t resampReadPtr = 0, resampWritePtr = 1; // see comment in init - - static constexpr int nimbusprocess_blocksize = 8; - float stub_input[2][nimbusprocess_blocksize]; // This is the extra sample we have around - size_t numStubs{0}; - int consumed = 0, created = 0; - bool builtBuffer{false}; }; #endif // SURGE_NIMBUSEFFECT_H diff --git a/src/common/dsp/effects/Reverb2Effect.h b/src/common/dsp/effects/Reverb2Effect.h index d1bba166480..ff8f9553c9d 100644 --- a/src/common/dsp/effects/Reverb2Effect.h +++ b/src/common/dsp/effects/Reverb2Effect.h @@ -33,14 +33,9 @@ #include -class Reverb2Effect : public surge::sstfx::SurgeSSTFXBase< - sst::effects::reverb2::Reverb2> +struct Reverb2Effect : public surge::sstfx::SurgeSSTFXBase< + sst::effects::reverb2::Reverb2> { - // These are set to make sure we have delay lengths up to 384k - - lipol_ps_blocksz mix alignas(16), width alignas(16); - - public: Reverb2Effect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd); virtual ~Reverb2Effect(); diff --git a/src/common/dsp/effects/SurgeSSTFXAdapter.h b/src/common/dsp/effects/SurgeSSTFXAdapter.h index a6ed5c1743c..c3017c467cc 100644 --- a/src/common/dsp/effects/SurgeSSTFXAdapter.h +++ b/src/common/dsp/effects/SurgeSSTFXAdapter.h @@ -200,6 +200,7 @@ template struct SurgeSSTFXBase : T // 2: make it throw a logic_error for really miscofingured cases for (int i = 0; i < T::numParams; ++i) { + bool started{false}; auto pmd = T::paramAt(i); if (this->fxdata->p[i].ctrltype == ct_none && @@ -208,13 +209,21 @@ template struct SurgeSSTFXBase : T if (pmd.name.empty()) { - std::cout << "\n\n----- " << i << " " << this->fxdata->p[i].get_name() << std::endl; + std::cout << "\n\n----- " << i << " [pmdname-missing] " + << this->fxdata->p[i].get_name() << std::endl; + started = true; } this->fxdata->p[i].set_name(pmd.name.c_str()); this->fxdata->p[i].basicBlocksParamMetaData = pmd; auto check = [&, i](auto a, auto b, auto msg) { if (a != b) { + if (!started) + { + std::cout << "\n\n----- " << i << " `" << pmd.name << "` `" + << this->fxdata->p[i].get_name() << "'" << std::endl; + started = true; + } // If you are sitting here it is because your ct_blah for p[i] is not // consistent with your sst-effects ParamMetaData. Go fix one of the other // and this message will vanish