Skip to content

Commit

Permalink
Move Nimbus from libsamplerate to our Lanczos downsampler
Browse files Browse the repository at this point in the history
1. Makes it ready to move to sst-effects
2. Makes it so we can almost remove libsamplerate (but some
   twist smidgeof work to do that)
3. Uses less CPU

Addresses surge-synthesizer#7359
  • Loading branch information
baconpaul committed Jul 25, 2024
1 parent c9181af commit 03729f1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 57 deletions.
94 changes: 39 additions & 55 deletions src/common/dsp/effects/NimbusEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/

#include "NimbusEffect.h"
#include "samplerate.h"
#include "DebugHelpers.h"
#include "fmt/core.h"

Expand Down Expand Up @@ -52,37 +51,24 @@ NimbusEffect::NimbusEffect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd)
processor->Init(block_mem, memLen, block_ccm, ccmLen);
mix.set_blocksize(BLOCK_SIZE);

int error;
surgeSR_to_euroSR = src_new(SRC_SINC_FASTEST, 2, &error);
if (error != 0)
{
surgeSR_to_euroSR = nullptr;
}

euroSR_to_surgeSR = src_new(SRC_SINC_FASTEST, 2, &error);
if (error != 0)
{
euroSR_to_surgeSR = nullptr;
}
sampleRateReset();
}

NimbusEffect::~NimbusEffect()
{
delete[] block_mem;
delete[] block_ccm;
delete processor;

if (surgeSR_to_euroSR)
surgeSR_to_euroSR = src_delete(surgeSR_to_euroSR);
if (euroSR_to_surgeSR)
euroSR_to_surgeSR = src_delete(euroSR_to_surgeSR);
}

void NimbusEffect::init()
{
mix.set_target(1.f);
mix.instantize();

surgeSR_to_euroSR = std::make_unique<resamp_t>(storage->samplerate, processor_sr);
euroSR_to_surgeSR = std::make_unique<resamp_t>(processor_sr, storage->samplerate);

memset(resampled_output, 0, raw_out_sz * 2 * sizeof(float));

consumed = 0;
Expand All @@ -102,31 +88,24 @@ void NimbusEffect::process(float *dataL, float *dataR)
return;

/* Resample Temp Buffers */
float resample_this[BLOCK_SIZE << 3][2];
float resample_into[BLOCK_SIZE << 3][2];
float resample_this[2][BLOCK_SIZE << 3];
float resample_into[2][BLOCK_SIZE << 3];

for (int i = 0; i < BLOCK_SIZE; ++i)
{
resample_this[i][0] = dataL[i];
resample_this[i][1] = dataR[i];
surgeSR_to_euroSR->push(dataL[i], dataR[i]);
}

SRC_DATA sdata;
sdata.end_of_input = 0;
sdata.src_ratio = processor_sr * storage->samplerate_inv;
sdata.data_in = &(resample_this[0][0]);
sdata.data_out = &(resample_into[0][0]);
sdata.input_frames = BLOCK_SIZE;
sdata.output_frames = (BLOCK_SIZE << 3);
auto res = src_process(surgeSR_to_euroSR, &sdata);
consumed += sdata.input_frames_used;

if (sdata.output_frames_gen)
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 = sdata.output_frames_gen;
int frames_to_go = outputFramesGen;
int outpos = 0;

auto modeInt = *pd_int[nmb_mode];
Expand All @@ -141,6 +120,7 @@ void NimbusEffect::process(float *dataL, float *dataR)
processor->set_quality(*pd_int[nmb_quality]);

int consume_ptr = 0;

while (frames_to_go + numStubs >= nimbusprocess_blocksize)
{
int sp = 0;
Expand All @@ -154,8 +134,8 @@ void NimbusEffect::process(float *dataL, float *dataR)

for (int i = sp; i < nimbusprocess_blocksize; ++i)
{
input[i].l = (short)(clamp1bp(resample_into[consume_ptr][0]) * 32767.0f);
input[i].r = (short)(clamp1bp(resample_into[consume_ptr][1]) * 32767.0f);
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++;
}

Expand Down Expand Up @@ -191,8 +171,8 @@ void NimbusEffect::process(float *dataL, float *dataR)

for (int i = 0; i < inputSz; ++i)
{
resample_this[outpos + i][0] = output[i].l / 32767.0f;
resample_this[outpos + i][1] = output[i].r / 32767.0f;
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);
Expand All @@ -206,30 +186,28 @@ void NimbusEffect::process(float *dataL, float *dataR)

for (int i = 0; i < addStub; ++i)
{
stub_input[0][i + startSub] = resample_into[consume_ptr][0];
stub_input[1][i + startSub] = resample_into[consume_ptr][1];
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)
{
SRC_DATA odata;
odata.end_of_input = 0;
odata.src_ratio = processor_sr_inv * storage->samplerate;
odata.data_in = &(resample_this[0][0]);
odata.data_out = &(resample_into[0][0]);
odata.input_frames = outpos;
odata.output_frames = BLOCK_SIZE << 3;
auto reso = src_process(euroSR_to_surgeSR, &odata);
if (!builtBuffer)
created += odata.output_frames_gen;
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 < odata.output_frames_gen; ++i)
for (int i = 0; i < dsoutputFramesGen; ++i)
{
resampled_output[w][0] = resample_into[i][0];
resampled_output[w][1] = resample_into[i][1];
resampled_output[0][w] = resample_into[0][i];
resampled_output[1][w] = resample_into[1][i];

w = (w + 1U) & (raw_out_sz - 1U);
}
Expand All @@ -247,8 +225,8 @@ void NimbusEffect::process(float *dataL, float *dataR)
size_t rp = resampReadPtr;
for (int i = 0; i < BLOCK_SIZE; ++i)
{
L[i] = resampled_output[rp][0];
R[i] = resampled_output[rp][1];
L[i] = resampled_output[0][rp];
R[i] = resampled_output[1][rp];
rp = (rp + rpi) & (raw_out_sz - 1);
}
resampReadPtr = rp;
Expand Down Expand Up @@ -454,3 +432,9 @@ void NimbusEffect::init_default_values()
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<resamp_t>(storage->samplerate, processor_sr);
euroSR_to_surgeSR = std::make_unique<resamp_t>(processor_sr, storage->samplerate);
}
8 changes: 6 additions & 2 deletions src/common/dsp/effects/NimbusEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <memory>
#include <vembertech/lipol.h>
#include "sst/basic-blocks/dsp/LanczosResampler.h"

namespace clouds
{
Expand Down Expand Up @@ -82,6 +83,8 @@ class NimbusEffect : public Effect
// Only used by rack
void setNimbusTrigger(bool b) { nimbusTrigger = b; }

void sampleRateReset() override;

private:
uint8_t *block_mem, *block_ccm;
clouds::GranularProcessor *processor;
Expand All @@ -90,10 +93,11 @@ class NimbusEffect : public Effect
int old_nmb_mode = 0;
bool nimbusTrigger{false};

SRC_STATE_tag *surgeSR_to_euroSR, *euroSR_to_surgeSR;
using resamp_t = sst::basic_blocks::dsp::LanczosResampler<BLOCK_SIZE>;
std::unique_ptr<resamp_t> surgeSR_to_euroSR, euroSR_to_surgeSR;

static constexpr int raw_out_sz = BLOCK_SIZE_OS << 5; // power of 2 pls
float resampled_output[raw_out_sz][2]; // at sr
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;
Expand Down

0 comments on commit 03729f1

Please sign in to comment.