Skip to content

Commit

Permalink
MOve to libsamplerate sinc fastest downsampling (#127)
Browse files Browse the repository at this point in the history
* MOve to libsamplerate sinc fastest downsampling

From the constant rates

* Runtime selectable resampler settings as well as internal SR
  • Loading branch information
baconpaul authored Jan 16, 2025
1 parent 1228fcc commit d7d4668
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@
[submodule "libs/sst/sst-plugininfra"]
path = libs/sst/sst-plugininfra
url = https://github.com/surge-synthesizer/sst-plugininfra
[submodule "libs/libsamplerate"]
path = libs/libsamplerate
url = https://github.com/libsndfile/libsamplerate.git
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ target_link_libraries(${PROJECT_NAME}-impl PRIVATE
sst-plugininfra sst-plugininfra::filesystem sst-plugininfra::tinyxml sst-plugininfra::strnatcmp
sst::clap_juce_shim sst::clap_juce_shim_headers
${PROJECT_NAME}-patches
samplerate
)

# Hmm - why do I need this?
Expand Down
2 changes: 2 additions & 0 deletions libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ if (APPLE)
endif()

add_subdirectory(clap-libs/clap-wrapper)

add_subdirectory(libsamplerate)
1 change: 1 addition & 0 deletions libs/libsamplerate
Submodule libsamplerate added at 4858fb
8 changes: 8 additions & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ enum SampleRateStrategy
SR_220240 = 3 // or 5x
};

enum ResamplerEngine
{
SRC_FAST,
SRC_MEDIUM,
SRC_BEST,
LANCZOS
};

} // namespace baconpaul::six_sines

inline std::string fileTrunc(const std::string &f)
Expand Down
17 changes: 15 additions & 2 deletions src/synth/patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,18 @@ struct Patch
{SampleRateStrategy::SR_176192, "176.4/192 kHz"},
{SampleRateStrategy::SR_220240, "220.5/240 kHz"},
})),
resampleEngine(intMd()
.withName(name() + " Resampler Engine")
.withGroupName(name())
.withDefault(ResamplerEngine::SRC_FAST)
.withRange(ResamplerEngine::SRC_FAST, ResamplerEngine::LANCZOS)
.withID(id(41))
.withUnorderedMapFormatting({
{ResamplerEngine::SRC_FAST, "SRC Fast (rec)"},
{ResamplerEngine::SRC_MEDIUM, "SRC Medium"},
{ResamplerEngine::SRC_BEST, "SRC Expensive"},
{ResamplerEngine::LANCZOS, "Lanczos A=4"},
})),
ModulationMixin(name(), id(120)),
modtarget(scpu::make_array_lambda<Param, numModsPer>(
[this](int i)
Expand Down Expand Up @@ -1177,7 +1189,7 @@ struct Patch
Param mpeActive, mpeBendRange;
Param octTranspose, fineTune, pan, lfoDepth;
Param attackFloorOnRetrig, rephaseOnRetrigger;
Param sampleRateStrategy;
Param sampleRateStrategy, resampleEngine;

std::array<Param, numModsPer> modtarget;

Expand All @@ -1203,7 +1215,8 @@ struct Patch
&lfoDepth,
&attackFloorOnRetrig,
&rephaseOnRetrigger,
&sampleRateStrategy};
&sampleRateStrategy,
&resampleEngine};
appendDAHDSRParams(res);

for (int i = 0; i < numModsPer; ++i)
Expand Down
103 changes: 92 additions & 11 deletions src/synth/synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,52 @@ void Synth::setSampleRate(double sampleRate)

lagHandler.setRate(60, blockSize, monoValues.sr.sampleRate);
vuPeak.setSampleRate(monoValues.sr.sampleRate);
sampleRateRatio = hostSampleRate / engineSampleRate;

resampler =
std::make_unique<resampler_t>((float)monoValues.sr.sampleRate, (float)hostSampleRate);
if (resamplerEngine == LANCZOS)
{
SXSNLOG("Setting Lanczos Resampler");
resampler =
std::make_unique<resampler_t>((float)monoValues.sr.sampleRate, (float)hostSampleRate);
}
else
{
if (lState)
{
src_delete(lState);
}
if (rState)
{
src_delete(rState);
}
int ec;
auto mode = SRC_SINC_FASTEST;
if (resamplerEngine == SRC_MEDIUM)
{
SXSNLOG("Setting SRC Resampler - SRC_SINC_MEDIUM_QUALITY");
mode = SRC_SINC_MEDIUM_QUALITY;
}
if (resamplerEngine == SRC_BEST)
{
SXSNLOG("Setting SRC Resampler - SRC_SINC_BEST_QUALITY");
mode = SRC_SINC_BEST_QUALITY;
}
else
{
SXSNLOG("Setting SRC Resampler - SRC_SINC_FASTEST");
}
lState = src_new(mode, 1, &ec);
rState = src_new(mode, 1, &ec);
src_set_ratio(lState, sampleRateRatio);
src_set_ratio(rState, sampleRateRatio);
}
}

void Synth::process(const clap_output_events_t *outq)
{
if (!SinTable::staticsInitialized)
SinTable::initializeStatics();

assert(resampler);

processUIQueue(outq);

if (!audioRunning)
Expand All @@ -119,8 +153,18 @@ void Synth::process(const clap_output_events_t *outq)

monoValues.attackFloorOnRetrig = patch.output.attackFloorOnRetrig > 0.5;

while (resampler->inputsRequiredToGenerateOutputs(blockSize) > 0)
int loops{0};

SRC_DATA d;

int generated{0};

if (resamplerEngine == LANCZOS)
generated = (resampler->inputsRequiredToGenerateOutputs(blockSize) > 0 ? 0 : blockSize);

while (generated < blockSize)
{
loops++;
lagHandler.process();

float lOutput alignas(16)[2][blockSize];
Expand Down Expand Up @@ -159,9 +203,40 @@ void Synth::process(const clap_output_events_t *outq)
assert(!v->next && !v->prior);
}

for (int i = 0; i < blockSize; ++i)
if (resamplerEngine == LANCZOS)
{
for (int i = 0; i < blockSize; ++i)
{
resampler->push(lOutput[0][i], lOutput[1][i]);
}
generated = (resampler->inputsRequiredToGenerateOutputs(blockSize) > 0 ? 0 : blockSize);
}
else
{
resampler->push(lOutput[0][i], lOutput[1][i]);
d.data_in = lOutput[0];
d.data_out = output[0] + generated;
d.input_frames = blockSize;
d.output_frames = blockSize - generated;
d.end_of_input = 0;
d.src_ratio = sampleRateRatio;

assert(d.input_frames_used == blockSize);
src_process(lState, &d);
auto lgen = d.output_frames_gen;

d.data_in = lOutput[1];
d.data_out = output[1] + generated;
d.input_frames = blockSize;
d.output_frames = blockSize - generated;
d.end_of_input = 0;
d.src_ratio = sampleRateRatio;

assert(d.input_frames_used == blockSize);
src_process(rState, &d);
auto rgen = d.output_frames_gen;

assert(lgen == rgen);
generated += lgen;
}

if (isEditorAttached)
Expand All @@ -187,8 +262,11 @@ void Synth::process(const clap_output_events_t *outq)
}
}

resampler->populateNextBlockSize(output[0], output[1]);
resampler->renormalizePhases();
if (resamplerEngine == LANCZOS)
{
resampler->populateNextBlockSize(output[0], output[1]);
resampler->renormalizePhases();
}
}

void Synth::addToVoiceList(Voice *v)
Expand Down Expand Up @@ -295,7 +373,8 @@ void Synth::processUIQueue(const clap_output_events_t *outq)
dest->meta.id == patch.output.polyLimit.meta.id ||
dest->meta.id == patch.output.pianoModeActive.meta.id ||
dest->meta.id == patch.output.mpeActive.meta.id ||
dest->meta.id == patch.output.sampleRateStrategy.meta.id)
dest->meta.id == patch.output.sampleRateStrategy.meta.id ||
dest->meta.id == patch.output.resampleEngine.meta.id)
{
reapplyControlSettings();
}
Expand Down Expand Up @@ -364,9 +443,11 @@ void Synth::processUIQueue(const clap_output_events_t *outq)

void Synth::reapplyControlSettings()
{
if (sampleRateStrategy != (SampleRateStrategy)patch.output.sampleRateStrategy.value)
if (sampleRateStrategy != (SampleRateStrategy)patch.output.sampleRateStrategy.value ||
resamplerEngine != (ResamplerEngine)patch.output.resampleEngine.value)
{
sampleRateStrategy = (SampleRateStrategy)patch.output.sampleRateStrategy.value;
resamplerEngine = (ResamplerEngine)patch.output.resampleEngine.value;

if (hostSampleRate > 0)
{
Expand Down
10 changes: 8 additions & 2 deletions src/synth/synth.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
#include <memory>
#include <array>

#include <clap/clap.h>
#include "sst/basic-blocks/dsp/LanczosResampler.h"
#include "samplerate.h"

#include <clap/clap.h>
#include "sst/basic-blocks/dsp/Lag.h"
#include "sst/basic-blocks/dsp/VUPeak.h"
#include "sst/basic-blocks/tables/EqualTuningProvider.h"
Expand All @@ -45,9 +47,13 @@ struct Synth
float output alignas(16)[2][blockSize];

SampleRateStrategy sampleRateStrategy{SampleRateStrategy::SR_110120};
ResamplerEngine resamplerEngine{ResamplerEngine::SRC_FAST};

using resampler_t = sst::basic_blocks::dsp::LanczosResampler<blockSize>;
std::unique_ptr<resampler_t> resampler;

SRC_STATE *lState{nullptr}, *rState{nullptr};

Patch patch;
MonoValues monoValues;

Expand Down Expand Up @@ -233,7 +239,7 @@ struct Synth

bool audioRunning{true};

double hostSampleRate{0}, engineSampleRate{0};
double hostSampleRate{0}, engineSampleRate{0}, sampleRateRatio{0};
void setSampleRate(double sampleRate);

void process(const clap_output_events_t *);
Expand Down
4 changes: 4 additions & 0 deletions src/ui/playmode-sub-panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ PlayModeSubPanel::PlayModeSubPanel(SixSinesEditor &e) : HasEditor(e)

createComponent(editor, *this, editor.patchCopy.output.sampleRateStrategy, srStrat, srStratD);
addAndMakeVisible(*srStrat);
createComponent(editor, *this, editor.patchCopy.output.resampleEngine, rsEng, rsEngD);
addAndMakeVisible(*rsEng);
srStratLab = std::make_unique<jcmp::RuledLabel>();
srStratLab->setText("Oversampling");
addAndMakeVisible(*srStratLab);
Expand Down Expand Up @@ -240,6 +242,8 @@ void PlayModeSubPanel::resized()
positionTitleLabelAt(depx, depy, bbx.getWidth(), srStratLab);
bbx = juce::Rectangle<int>(depx, depy + uicTitleLabelHeight, bbx.getWidth(), uicLabelHeight);
srStrat->setBounds(bbx);
bbx = bbx.translated(0, uicMargin + uicLabelHeight);
rsEng->setBounds(bbx);
}

void PlayModeSubPanel::setTriggerButtonLabel()
Expand Down
2 changes: 2 additions & 0 deletions src/ui/playmode-sub-panel.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ struct PlayModeSubPanel : juce::Component, HasEditor
std::unique_ptr<jcmp::RuledLabel> srStratLab;
std::unique_ptr<jcmp::JogUpDownButton> srStrat;
std::unique_ptr<PatchDiscrete> srStratD;
std::unique_ptr<jcmp::JogUpDownButton> rsEng;
std::unique_ptr<PatchDiscrete> rsEngD;

void showPolyLimitMenu();
int getPolyLimit();
Expand Down

0 comments on commit d7d4668

Please sign in to comment.