Skip to content

Commit

Permalink
Processors get independent streaming versions (#1369)
Browse files Browse the repository at this point in the history
Processors and Bus FX get independent streaming versions which allow
them to add and remove parameters independently of parent SV.

Also add rotary speaker

Closes #958
  • Loading branch information
baconpaul authored Sep 22, 2024
1 parent e92b7ff commit 9d31d05
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 56 deletions.
2 changes: 1 addition & 1 deletion libs/sst/sst-basic-blocks
2 changes: 1 addition & 1 deletion libs/sst/sst-effects
Submodule sst-effects updated 49 files
+9 −0 include/sst/effects/Bonsai.h
+8 −0 include/sst/effects/Delay.h
+9 −0 include/sst/effects/EffectCore.h
+8 −0 include/sst/effects/Flanger.h
+18 −0 include/sst/effects/Nimbus.h
+1 −0 include/sst/effects/NimbusImpl.h
+9 −0 include/sst/effects/Phaser.h
+9 −0 include/sst/effects/Reverb1.h
+8 −0 include/sst/effects/Reverb2.h
+9 −0 include/sst/effects/RotarySpeaker.h
+9 −0 include/sst/effects/TreeMonster.h
+10 −0 include/sst/voice-effects/delay/Chorus.h
+10 −0 include/sst/voice-effects/delay/DelaySupport.h
+10 −0 include/sst/voice-effects/delay/Microgate.h
+10 −0 include/sst/voice-effects/delay/ShortDelay.h
+10 −0 include/sst/voice-effects/delay/StringResonator.h
+10 −0 include/sst/voice-effects/delay/Widener.h
+10 −0 include/sst/voice-effects/distortion/BitCrusher.h
+10 −0 include/sst/voice-effects/distortion/Slewer.h
+10 −0 include/sst/voice-effects/distortion/TreeMonster.h
+10 −0 include/sst/voice-effects/dynamics/AutoWah.h
+10 −0 include/sst/voice-effects/dynamics/Compressor.h
+10 −0 include/sst/voice-effects/eq/EqGraphic6Band.h
+10 −0 include/sst/voice-effects/eq/EqNBandParametric.h
+10 −0 include/sst/voice-effects/eq/MorphEQ.h
+10 −0 include/sst/voice-effects/eq/TiltEQ.h
+10 −0 include/sst/voice-effects/filter/CytomicSVF.h
+10 −0 include/sst/voice-effects/filter/SSTFilters.h
+10 −0 include/sst/voice-effects/filter/StaticPhaser.h
+10 −0 include/sst/voice-effects/filter/SurgeBiquads.h
+10 −0 include/sst/voice-effects/generator/GenCorrelatedNoise.h
+10 −0 include/sst/voice-effects/generator/GenVA.h
+10 −0 include/sst/voice-effects/generator/TiltNoise.h
+10 −0 include/sst/voice-effects/lifted_bus_effects/LiftedDelay.h
+10 −0 include/sst/voice-effects/lifted_bus_effects/LiftedFlanger.h
+10 −0 include/sst/voice-effects/lifted_bus_effects/LiftedReverb1.h
+10 −0 include/sst/voice-effects/lifted_bus_effects/LiftedReverb2.h
+10 −0 include/sst/voice-effects/modulation/FMFilter.h
+10 −0 include/sst/voice-effects/modulation/FreqShiftMod.h
+10 −0 include/sst/voice-effects/modulation/NoiseAM.h
+10 −0 include/sst/voice-effects/modulation/PhaseMod.h
+10 −0 include/sst/voice-effects/modulation/Phaser.h
+10 −0 include/sst/voice-effects/modulation/RingMod.h
+10 −0 include/sst/voice-effects/modulation/ShepardPhaser.h
+10 −0 include/sst/voice-effects/modulation/Tremolo.h
+10 −0 include/sst/voice-effects/utilities/GainMatrix.h
+10 −0 include/sst/voice-effects/utilities/StereoTool.h
+12 −0 include/sst/voice-effects/utilities/VolumeAndPan.h
+10 −0 include/sst/voice-effects/waveshaper/WaveShaper.h
2 changes: 2 additions & 0 deletions src-ui/app/mixer-screen/MixerScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ std::string MixerScreen::effectDisplayName(engine::AvailableBusEffects t, bool f
return forMenu ? "TreeMonster" : "TREEMONSTER";
case engine::bonsai:
return forMenu ? "Bonsai" : "BONSAI";
case engine::rotaryspeaker:
return forMenu ? "Rotary Speaker" : "ROTARY";
}

return "GCC gives strictly correct, but not useful in this case, warnings";
Expand Down
1 change: 1 addition & 0 deletions src-ui/app/mixer-screen/components/PartEffectsPane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void PartEffectsPane::rebuild()
CS(nimbus);
CS(phaser);
CS(treemonster);
CS(rotaryspeaker);
CS(bonsai);

case engine::AvailableBusEffects::none:
Expand Down
42 changes: 42 additions & 0 deletions src/dsp/processor/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ namespace detail
using boolOp_t = bool (*)();
using constCharOp_t = const char *(*)();
using floatOp_t = float (*)();
using int16Op_t = int16_t (*)();
using reampFnOp_t = remapFn_t (*)();

template <size_t I> bool implIsProcessorImplemented()
{
Expand Down Expand Up @@ -126,6 +128,22 @@ template <size_t I> bool implGetForGroupOnly()
return ProcessorForGroupOnly<(ProcessorType)I>::isGroupOnly;
}

template <size_t I> int16_t implGetStreamingVersion()
{
if constexpr (std::is_same<typename ProcessorImplementor<(ProcessorType)I>::T, unimpl_t>::value)
return 0;
else
return ProcessorImplementor<(ProcessorType)I>::T::streamingVersion;
}

template <size_t I> remapFn_t implGetRemapFn()
{
if constexpr (std::is_same<typename ProcessorImplementor<(ProcessorType)I>::T, unimpl_t>::value)
return nullptr;
else
return ProcessorImplementor<(ProcessorType)I>::T::remapParametersForStreamingVersion;
}

template <size_t... Is> auto getProcessorDisplayGroup(size_t ft, std::index_sequence<Is...>)
{
constexpr constCharOp_t fnc[] = {detail::implGetProcessorDisplayGroup<Is>...};
Expand All @@ -138,6 +156,18 @@ template <size_t... Is> auto getProcessorDefaultMix(size_t ft, std::index_sequen
return fnc[ft]();
}

template <size_t... Is> auto getProcessorStreamingVersion(size_t ft, std::index_sequence<Is...>)
{
constexpr int16Op_t fnc[] = {detail::implGetStreamingVersion<Is>...};
return fnc[ft]();
}

template <size_t... Is> auto getProcessorRemapFn(size_t ft, std::index_sequence<Is...>)
{
constexpr reampFnOp_t fnc[] = {detail::implGetRemapFn<Is>...};
return fnc[ft]();
}

template <size_t... Is> auto getForGroupOnly(size_t ft, std::index_sequence<Is...>)
{
constexpr boolOp_t fnc[] = {detail::implGetForGroupOnly<Is>...};
Expand Down Expand Up @@ -222,6 +252,12 @@ const char *getProcessorStreamingName(ProcessorType id)
id, std::make_index_sequence<(size_t)ProcessorType::proct_num_types>());
}

remapFn_t getProcessorRemapParametersFromStreamingVersion(ProcessorType id)
{
return detail::getProcessorRemapFn(
id, std::make_index_sequence<(size_t)ProcessorType::proct_num_types>());
}

const char *getProcessorDisplayGroup(ProcessorType id)
{
return detail::getProcessorDisplayGroup(
Expand All @@ -240,6 +276,12 @@ bool getProcessorGroupOnly(ProcessorType id)
id, std::make_index_sequence<(size_t)ProcessorType::proct_num_types>());
}

int16_t getProcessorStreamingVersion(ProcessorType id)
{
return detail::getProcessorStreamingVersion(
id, std::make_index_sequence<(size_t)ProcessorType::proct_num_types>());
}

std::optional<ProcessorType> fromProcessorStreamingName(const std::string &s)
{
// A bit gross but hey
Expand Down
10 changes: 10 additions & 0 deletions src/dsp/processor/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ const char *getProcessorStreamingName(ProcessorType id);
const char *getProcessorDisplayGroup(ProcessorType id);
float getProcessorDefaultMix(ProcessorType id);
bool getProcessorGroupOnly(ProcessorType id);
int16_t getProcessorStreamingVersion(ProcessorType id);
using remapFn_t = void (*)(int16_t, float *const, int *const);
remapFn_t getProcessorRemapParametersFromStreamingVersion(ProcessorType id);
std::optional<ProcessorType> fromProcessorStreamingName(const std::string &s);

struct ProcessorDescription
Expand Down Expand Up @@ -206,6 +209,7 @@ struct ProcessorStorage
bool isKeytracked{false};
int previousIsKeytracked{-1}; // make this an int and -1 means don't know previous
bool isTemposynced{false};
int16_t streamingVersion{-1};

bool operator==(const ProcessorStorage &other) const
{
Expand Down Expand Up @@ -283,6 +287,12 @@ struct Processor : MoveableOnly<Processor>, SampleRateSupport
virtual void setTempoPointer(double *t) { tempoPointer = t; }
virtual double *getTempoPointer() const { return tempoPointer; }

virtual int16_t getStreamingVersion() const
{
assert(false);
return -1;
}

/*
* The default behavior of a processor is stereo -> stereo and all
* processors must implement process_stereo.
Expand Down
12 changes: 11 additions & 1 deletion src/dsp/processor/processor_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#ifndef SCXT_SRC_DSP_PROCESSOR_PROCESSOR_IMPL_H
#define SCXT_SRC_DSP_PROCESSOR_PROCESSOR_IMPL_H

#include <functional>

#include "configuration.h"
#include "processor.h"
#include "engine/memory_pool.h"
Expand Down Expand Up @@ -158,7 +160,8 @@ HAS_MEMFN(enableKeytrack);
HAS_MEMFN(getKeytrackDefault);
HAS_MEMFN(getKeytrack);
HAS_MEMFN(checkParameterConsistency);
HAS_MEMFN(getMonoToStereoSetting)
HAS_MEMFN(getMonoToStereoSetting);
HAS_MEMFN(remapParametersForStreamingVersion);

#undef HAS_MEMFN

Expand All @@ -175,6 +178,12 @@ template <typename T> struct SSTVoiceEffectShim : T
<< " mono->stereo=" << HasMemFn_processMonoToStereo<T>::value
<< " stereo->stereo=" << HasMemFn_processStereo<T>::value);
#endif

static_assert(T::streamingVersion > 0,
"All template processors need independent streaming version");
static_assert(HasMemFn_remapParametersForStreamingVersion<T>::value,
"All template processors need a stream change handler");

static_assert(std::is_same_v<decltype(&T::processStereo),
void (T::*)(const float *const, const float *const, float *,
float *, float)>);
Expand Down Expand Up @@ -260,6 +269,7 @@ template <typename T> struct SSTVoiceEffectShim : T
}
}

int16_t getStreamingVersion() const override { return T::streamingVersion; }
void onSampleRateChanged() override
{
if (mInitCalledOnce)
Expand Down
68 changes: 66 additions & 2 deletions src/engine/bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "sst/effects/Bonsai.h"
#include "sst/effects/TreeMonster.h"
#include "sst/effects/NimbusImpl.h"
#include "sst/effects/RotarySpeaker.h"
#include "sst/effects/EffectCoreDetails.h"

#include "sst/basic-blocks/mechanics/block-ops.h"
Expand Down Expand Up @@ -126,15 +127,41 @@ struct Config
static inline float dbToLinear(GlobalStorage *s, float f) { return dsp::dbTable.dbToLinear(f); }
};

#define HAS_MEMFN(M) \
template <typename T> class HasMemFn_##M \
{ \
using No = uint8_t; \
using Yes = uint64_t; \
static_assert(sizeof(No) != sizeof(Yes)); \
template <typename C> static Yes test(decltype(&C::M) *); \
template <typename C> static No test(...); \
\
public: \
enum \
{ \
value = sizeof(test<T>(nullptr)) == sizeof(Yes) \
}; \
};

HAS_MEMFN(remapParametersForStreamingVersion);
#undef HAS_MEMFN

template <typename T> struct Impl : T
{
static_assert(T::numParams <= BusEffectStorage::maxBusEffectParams);
Engine *engine{nullptr};
BusEffectStorage *pes{nullptr};
float *values{nullptr};
Impl(Engine *e, BusEffectStorage *f, float *v) : engine(e), pes(f), values(v), T(e, f, v) {}
Impl(Engine *e, BusEffectStorage *f, float *v) : engine(e), pes(f), values(v), T(e, f, v)
{
f->streamingVersion = T::streamingVersion;
}
void init(bool defaultsOverride) override
{
static_assert(T::streamingVersion > 0,
"All template bus fx need independent streaming version");
static_assert(HasMemFn_remapParametersForStreamingVersion<T>::value,
"All template bus fx need streaming version support");
if (defaultsOverride)
{
for (int i = 0; i < T::numParams && i < BusEffectStorage::maxBusEffectParams; ++i)
Expand All @@ -156,7 +183,6 @@ template <typename T> struct Impl : T

} // namespace dtl

// TODO consider the enum to type trick so these can skip the switch
std::unique_ptr<BusEffect> createEffect(AvailableBusEffects p, Engine *e, BusEffectStorage *s)
{
namespace sfx = sst::effects;
Expand Down Expand Up @@ -189,13 +215,51 @@ std::unique_ptr<BusEffect> createEffect(AvailableBusEffects p, Engine *e, BusEff
case nimbus:
return std::make_unique<dtl::Impl<sfx::nimbus::Nimbus<dtl::Config>>>(e, s,
s->params.data());
case rotaryspeaker:
return std::make_unique<dtl::Impl<sfx::rotaryspeaker::RotarySpeaker<dtl::Config>>>(
e, s, s->params.data());
case bonsai:
return std::make_unique<dtl::Impl<sfx::bonsai::Bonsai<dtl::Config>>>(e, s,
s->params.data());
}
return nullptr;
}

std::pair<int16_t, busRemapFn_t> getBusEffectRemapStreamingFunction(AvailableBusEffects p)
{
namespace sfx = sst::effects;

#define RETVAL(x) \
{ \
sfx::x<dtl::Config>::streamingVersion, \
&sfx::x<dtl::Config>::remapParametersForStreamingVersion \
}
switch (p)
{
case none:
return {0, nullptr};
case reverb1:
return RETVAL(reverb1::Reverb1);
case reverb2:
return RETVAL(reverb2::Reverb2);
case flanger:
return RETVAL(flanger::Flanger);
case phaser:
return RETVAL(phaser::Phaser);
case treemonster:
return RETVAL(treemonster::TreeMonster);
case delay:
return RETVAL(delay::Delay);
case nimbus:
return RETVAL(nimbus::Nimbus);
case rotaryspeaker:
return RETVAL(rotaryspeaker::RotarySpeaker);
case bonsai:
return RETVAL(bonsai::Bonsai);
}
return {0, nullptr};
}

void Bus::setBusEffectType(Engine &e, int idx, scxt::engine::AvailableBusEffects t)
{
assert(idx >= 0 && idx < maxEffectsPerBus);
Expand Down
6 changes: 6 additions & 0 deletions src/engine/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ enum AvailableBusEffects
delay,
treemonster,
nimbus,
rotaryspeaker,
bonsai // if you make bonsai not last, make sure to update the fromString range
};

Expand All @@ -104,6 +105,7 @@ struct BusEffectStorage
bool isTemposync{false};
std::array<float, maxBusEffectParams> params{};
std::array<bool, maxBusEffectParams> deact{};
int16_t streamingVersion;

inline bool isDeactivated(int idx) { return deact[idx]; }
inline bool isExtended(int idx) { return false; }
Expand All @@ -121,6 +123,8 @@ struct BusEffect
};

std::unique_ptr<BusEffect> createEffect(AvailableBusEffects p, Engine *e, BusEffectStorage *s);
using busRemapFn_t = void (*)(int16_t, float *const);
std::pair<int16_t, busRemapFn_t> getBusEffectRemapStreamingFunction(AvailableBusEffects);

struct Bus : MoveableOnly<Bus>, SampleRateSupport
{
Expand Down Expand Up @@ -248,6 +252,8 @@ inline std::string toStringAvailableBusEffects(const AvailableBusEffects &p)
return "delay";
case nimbus:
return "nimbus";
case rotaryspeaker:
return "rotaryspeaker";
case bonsai:
return "bonsai";
}
Expand Down
6 changes: 6 additions & 0 deletions src/engine/group_and_zone_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,15 @@ void HasGroupZoneProcessors<T>::setProcessorType(int whichProcessor,

if (tmpProcessor)
{
ps.streamingVersion = tmpProcessor->getStreamingVersion();
dsp::processor::unspawnProcessor(tmpProcessor);
}
else
{
ps.streamingVersion = 0;
}

SCLOG("STREAMING VERSION IS " << ps.streamingVersion);
asT()->onProcessorTypeChanged(whichProcessor, type);
}

Expand Down
Loading

0 comments on commit 9d31d05

Please sign in to comment.