Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rev20 #91

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.10)
project(sst-effects VERSION 0.5 LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 17)

add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE include)
Expand Down
4 changes: 0 additions & 4 deletions include/sst/effects/ConcreteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ struct ConcreteConfig
// It is painful that sst-filters makes us over-adapt
// this class
GS(double sr) : sampleRate(sr) {}

float noteToPitch(float f) { return 0; }
float dbToLinear(float f) { return 1.f; }
float getSampleRateInv() { return 1.0 / sampleRate; }
};
struct ES
{
Expand Down
3 changes: 2 additions & 1 deletion include/sst/effects/EffectCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ template <typename FXConfig> struct EffectTemplateBase : public FXConfig::BaseCl
static constexpr float blockSize_quad{FXConfig::blockSize >> 2};

using BiquadFilterType =
sst::filters::Biquad::BiquadFilter<typename FXConfig::GlobalStorage, FXConfig::blockSize>;
sst::filters::Biquad::BiquadFilter<typename FXConfig::GlobalStorage, FXConfig::blockSize,
typename FXConfig::BiquadAdapter>;

inline typename FXConfig::BaseClass *asBase()
{
Expand Down
166 changes: 82 additions & 84 deletions include/sst/voice-effects/VoiceEffectCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,86 +26,23 @@
*
*/

#include <type_traits>
#include <concepts>

// For shared width calculations
#include "sst/basic-blocks/dsp/MidSide.h"
#include "sst/basic-blocks/dsp/BlockInterpolators.h"

#include "sst/basic-blocks/concepts/concepts.h"

#include "sst/filters/BiquadFilter.h"

#include <type_traits>

namespace sst::voice_effects::core
{

template <typename VFXConfig>
concept baseClassAPI =
requires(typename VFXConfig::BaseClass *b, size_t st, float f, int i, uint8_t *u8) {
{
VFXConfig::setFloatParam(b, st, f)
} -> std::convertible_to<void>;
{
VFXConfig::getFloatParam(b, st)
} -> std::floating_point;

{
VFXConfig::setIntParam(b, st, i)
} -> std::convertible_to<void>;
{
VFXConfig::getIntParam(b, st)
} -> std::integral;

{
VFXConfig::dbToLinear(b, f)
} -> std::floating_point;

{
VFXConfig::equalNoteToPitch(b, f)
} -> std::floating_point;

{
VFXConfig::getSampleRate(b)
} -> std::floating_point;
{
VFXConfig::getSampleRateInv(b)
} -> std::floating_point;

{
VFXConfig::preReservePool(b, st)
} -> std::convertible_to<void>;
{
VFXConfig::checkoutBlock(b, st)
} -> std::same_as<uint8_t *>;
{
VFXConfig::returnBlock(b, u8, st)
} -> std::convertible_to<void>;
};

template <typename VFXConfig>
concept optionalOversampling = std::is_integral_v<typename VFXConfig::oversamplingRatio>;

template <typename VFXConfig>
concept optionalEnvelopeTime = requires(typename VFXConfig::BaseClass *b, float f) {
{
VFXConfig::envelope_rate_linear_nowrap(b, f)
} -> std::convertible_to<float>;
};

template <typename VFXConfig>
concept supportsVoiceConfig =
std::is_class_v<typename VFXConfig::BaseClass> &&
sst::basic_blocks::concepts::is_power_of_two_ge(VFXConfig::blockSize, (size_t)4) &&
baseClassAPI<VFXConfig>;

// Todo: as we port consider this FXConfig::BaseClass being a bit more configurable.
template <typename VFXConfig>
requires(supportsVoiceConfig<VFXConfig>)
struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
template <typename VFXConfig> struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
{
static_assert(std::is_integral<decltype(VFXConfig::blockSize)>::value);
static_assert(!(VFXConfig::blockSize & (VFXConfig::blockSize - 1))); // 2^n
static_assert(VFXConfig::blockSize >= 4); // > simd register length
static_assert(std::is_class<typename VFXConfig::BaseClass>::value);

typename VFXConfig::BaseClass *asBase()
{
return static_cast<typename VFXConfig::BaseClass *>(this);
Expand All @@ -116,21 +53,58 @@ struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
return static_cast<const typename VFXConfig::BaseClass *>(this);
}

/*
* Params
*/
static_assert(std::is_same<decltype(VFXConfig::setFloatParam(
std::declval<typename VFXConfig::BaseClass *>(),
std::declval<size_t>(), std::declval<float>())),
void>::value,
"Implement setFloatParam");

static_assert(
std::is_same<decltype(VFXConfig::getFloatParam(
std::declval<typename VFXConfig::BaseClass *>(), std::declval<size_t>())),
float>::value,
"Implement getFloatParam");

void setFloatParam(int i, float f) { VFXConfig::setFloatParam(asBase(), i, f); }
float getFloatParam(int i) const { return VFXConfig::getFloatParam(asBase(), i); }

static_assert(std::is_same<decltype(VFXConfig::setIntParam(
std::declval<typename VFXConfig::BaseClass *>(),
std::declval<size_t>(), std::declval<int>())),
void>::value,
"Implement setIntParam");

static_assert(
std::is_same<decltype(VFXConfig::getIntParam(
std::declval<typename VFXConfig::BaseClass *>(), std::declval<size_t>())),
int>::value,
"Implement getIntParam");

void setIntParam(int i, int f) { VFXConfig::setIntParam(asBase(), i, f); }
int getIntParam(int i) const { return VFXConfig::getIntParam(asBase(), i); }

/*
* Conversions
*/
static_assert(
std::is_same<decltype(VFXConfig::dbToLinear(std::declval<typename VFXConfig::BaseClass *>(),
std::declval<float>())),
float>::value,
"Implement dbToLinear");
float dbToLinear(float f) { return VFXConfig::dbToLinear(asBase(), f); }
static float dbToLinear(typename VFXConfig::BaseClass *b, float f)
{
return VFXConfig::dbToLinear(b, f);
}

static_assert(
std::is_same<decltype(VFXConfig::equalNoteToPitch(
std::declval<typename VFXConfig::BaseClass *>(), std::declval<float>())),
float>::value,
"Implement getEqualNoteToPitch");
float equalNoteToPitch(float f) { return VFXConfig::equalNoteToPitch(asBase(), f); }
float note_to_pitch_ignoring_tuning(float f) { return equalNoteToPitch(f); }
static float noteToPitchIgnoringTuning(VoiceEffectTemplateBase<VFXConfig> *that, float f)
Expand All @@ -142,12 +116,38 @@ struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
return that->getSampleRateInv();
}

static_assert(std::is_same<decltype(VFXConfig::getSampleRate(
std::declval<typename VFXConfig::BaseClass *>())),
float>::value,
"Implement getSampleRate");
float getSampleRate() { return VFXConfig::getSampleRate(asBase()); }
static_assert(std::is_same<decltype(VFXConfig::getSampleRateInv(
std::declval<typename VFXConfig::BaseClass *>())),
float>::value,
"Implement getSampleRateInv");
float getSampleRateInv() { return VFXConfig::getSampleRateInv(asBase()); }

/*
* We have to provide a memory pool
*/
static_assert(
std::is_same<decltype(VFXConfig::preReservePool(
std::declval<typename VFXConfig::BaseClass *>(), std::declval<size_t>())),
void>::value,
"void preReservePool(base*, size_t) not defined");

static_assert(
std::is_same<decltype(VFXConfig::checkoutBlock(
std::declval<typename VFXConfig::BaseClass *>(), std::declval<size_t>())),
uint8_t *>::value,
"uint8_t* checkoutBlock(base *,size_t) not defined");

static_assert(std::is_same<decltype(VFXConfig::returnBlock(
std::declval<typename VFXConfig::BaseClass *>(),
std::declval<uint8_t *>(), std::declval<size_t>())),
void>::value,
"void returnBlock(base *, uint8_t *, size_t) not defined");

void preReservePool(size_t s) { VFXConfig::preReservePool(asBase(), s); }
uint8_t *checkoutBlock(size_t s) { return VFXConfig::checkoutBlock(asBase(), s); }
void returnBlock(uint8_t *d, size_t s) { VFXConfig::returnBlock(asBase(), d, s); }
Expand All @@ -167,9 +167,18 @@ struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
}
}

template <typename T, typename = void> struct has_oversampling : std::false_type
{
};

template <typename T>
struct has_oversampling<T, std::void_t<decltype(&T::oversamplingRatio)>> : std::true_type
{
};

constexpr int16_t getOversamplingRatio()
{
if constexpr (optionalOversampling<VFXConfig>)
if constexpr (has_oversampling<VFXConfig>::value)
{
return VFXConfig::oversamplingRatio;
}
Expand All @@ -179,20 +188,9 @@ struct VoiceEffectTemplateBase : public VFXConfig::BaseClass
}
}

float envelope_rate_linear_nowrap(float f)
{
if constexpr (optionalEnvelopeTime<VFXConfig>)
{
return VFXConfig::envelope_rate_linear_nowrap(this, f);
}
else
{
return VFXConfig::blockSize * VFXConfig::getSampleRateInv(this) * std::pow(2, -f);
}
}

using BiquadFilterType = sst::filters::Biquad::BiquadFilter<VoiceEffectTemplateBase<VFXConfig>,
VFXConfig::blockSize>;
using BiquadFilterType =
sst::filters::Biquad::BiquadFilter<VoiceEffectTemplateBase<VFXConfig>, VFXConfig::blockSize,
VoiceEffectTemplateBase<VFXConfig>>;
};
} // namespace sst::voice_effects::core

Expand Down
4 changes: 1 addition & 3 deletions include/sst/voice-effects/modulation/Phaser.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ namespace sst::voice_effects::modulation
{
template <typename VFXConfig> struct Phaser : core::VoiceEffectTemplateBase<VFXConfig>
{
using base_t = core::VoiceEffectTemplateBase<VFXConfig>;

static constexpr const char *effectName{"Phaser"};

static constexpr int numFloatParams{6};
Expand Down Expand Up @@ -143,7 +141,7 @@ template <typename VFXConfig> struct Phaser : core::VoiceEffectTemplateBase<VFXC
return VFXConfig::blockSize * VFXConfig::getSampleRateInv(this) * std::pow(2, -f);
}

using lfo_t = sst::basic_blocks::modulators::SimpleLFO<base_t, VFXConfig::blockSize>;
using lfo_t = sst::basic_blocks::modulators::SimpleLFO<Phaser, VFXConfig::blockSize>;
lfo_t actualLFO{this, 1};
typename lfo_t::Shape lfoShape = lfo_t::Shape::SINE;

Expand Down
9 changes: 7 additions & 2 deletions include/sst/voice-effects/modulation/Tremolo.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,14 @@ template <typename VFXConfig> struct Tremolo : core::VoiceEffectTemplateBase<VFX

void initVoiceEffectParams() { this->initToParamMetadataDefault(this); }

// This ain't in VFXConfig so put it here (the simpleLFO needs it):
float envelope_rate_linear_nowrap(float f)
{
return VFXConfig::blockSize * VFXConfig::getSampleRateInv(this) * std::pow(2, -f);
}

// Ok, so let's introduce the simpleLFO with an alias.
using lfo_t = sst::basic_blocks::modulators::SimpleLFO<core::VoiceEffectTemplateBase<VFXConfig>,
VFXConfig::blockSize>;
using lfo_t = sst::basic_blocks::modulators::SimpleLFO<Tremolo, VFXConfig::blockSize>;
// create one...
lfo_t actualLFO{this, 1};
// ...set up a variable for lfo shape.
Expand Down
3 changes: 0 additions & 3 deletions tests/create-effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ struct TestConfig

struct GS
{
float noteToPitch(float f) { return 0; }
float dbToLinear(float f) { return 1.f; }
float getSampleRateInv() { return 1.0 / 48000; }
};
struct ES
{
Expand Down
12 changes: 9 additions & 3 deletions tests/create-voice-effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct VTestConfig
std::array<float, 256> fb{};
std::array<int, 256> ib{};
};
static constexpr size_t blockSize{16};
static constexpr int blockSize{16};
static void setFloatParam(BaseClass *b, int i, float f) { b->fb[i] = f; }
static float getFloatParam(const BaseClass *b, int i) { return b->fb[i]; }

Expand Down Expand Up @@ -159,6 +159,12 @@ TEST_CASE("Can Create Voice FX")
{
VTester<sst::voice_effects::filter::StaticPhaser<VTestConfig>>::TestVFX();
}
SECTION("Tremolo") { VTester<sst::voice_effects::modulation::Tremolo<VTestConfig>>::TestVFX(); }
SECTION("Phaser") { VTester<sst::voice_effects::modulation::Phaser<VTestConfig>>::TestVFX(); }
SECTION("Tremolo")
{
VTester<sst::voice_effects::modulation::Tremolo<VTestConfig>>::TestVFX();
}
SECTION("Phaser")
{
VTester<sst::voice_effects::modulation::Phaser<VTestConfig>>::TestVFX();
}
}
3 changes: 0 additions & 3 deletions tests/sfinae-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ struct NoExtraConfig

struct GS
{
float noteToPitch(float f) { return 0; }
float dbToLinear(float f) { return 1.f; }
float getSampleRateInv() { return 1.0 / 48000; }
};
struct ES
{
Expand Down
Loading