commit
d12aaa9f48
12 changed files with 338 additions and 5 deletions
|
|
@ -1,5 +1,5 @@
|
|||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used")
|
||||
set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used")
|
||||
|
||||
# Export the compile_commands.json file
|
||||
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ set (SFIZZ_SOURCES
|
|||
sfizz/effects/Nothing.cpp
|
||||
sfizz/effects/Filter.cpp
|
||||
sfizz/effects/Eq.cpp
|
||||
sfizz/effects/Apan.cpp
|
||||
sfizz/effects/Lofi.cpp
|
||||
)
|
||||
include (SfizzSIMDSourceFiles)
|
||||
|
|
|
|||
4
src/external/atomic_queue/atomic_queue.h
vendored
4
src/external/atomic_queue/atomic_queue.h
vendored
|
|
@ -150,7 +150,7 @@ protected:
|
|||
|
||||
// The special member functions are not thread-safe.
|
||||
|
||||
AtomicQueueCommon() noexcept = default;
|
||||
AtomicQueueCommon() = default;
|
||||
|
||||
AtomicQueueCommon(AtomicQueueCommon const& b) noexcept
|
||||
: head_(b.head_.load(X))
|
||||
|
|
@ -417,7 +417,7 @@ class AtomicQueue2 : public AtomicQueueCommon<AtomicQueue2<T, SIZE, MINIMIZE_CON
|
|||
public:
|
||||
using value_type = T;
|
||||
|
||||
AtomicQueue2() noexcept = default;
|
||||
AtomicQueue2() = default;
|
||||
AtomicQueue2(AtomicQueue2 const&) = delete;
|
||||
AtomicQueue2& operator=(AtomicQueue2 const&) = delete;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -206,5 +206,10 @@ namespace Default
|
|||
constexpr bool checkSostenuto { true }; // sostenuto_sw
|
||||
constexpr Range<int> octaveOffsetRange { -10, 10 }; // octave_offset
|
||||
constexpr Range<int> noteOffsetRange { -127, 127 }; // note_offset
|
||||
|
||||
constexpr Range<int> apanWaveformRange { 0, std::numeric_limits<int>::max() };
|
||||
constexpr Range<float> apanFrequencyRange { 0, std::numeric_limits<float>::max() };
|
||||
constexpr Range<float> apanPhaseRange { 0.0, 360.0 };
|
||||
constexpr Range<float> apanLevelRange { 0.0, 100.0 };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "effects/Nothing.h"
|
||||
#include "effects/Filter.h"
|
||||
#include "effects/Eq.h"
|
||||
#include "effects/Apan.h"
|
||||
#include "effects/Lofi.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ void EffectFactory::registerStandardEffectTypes()
|
|||
// TODO
|
||||
registerEffectType("filter", fx::Filter::makeInstance);
|
||||
registerEffectType("eq", fx::Eq::makeInstance);
|
||||
registerEffectType("apan", fx::Apan::makeInstance);
|
||||
registerEffectType("lofi", fx::Lofi::makeInstance);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
LeakDetector& operator=(const LeakDetector&) = default;
|
||||
|
||||
private:
|
||||
struct ObjectCounter {
|
||||
ObjectCounter() = default;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#if __cplusplus > 201103L
|
||||
#define CXX14_CONSTEXPR constexpr
|
||||
#define CXX11_MOVE(x) x
|
||||
#else
|
||||
#define CXX14_CONSTEXPR
|
||||
#define CXX11_MOVE(x) std::move(x)
|
||||
#endif
|
||||
|
||||
|
|
|
|||
155
src/sfizz/effects/Apan.cpp
Normal file
155
src/sfizz/effects/Apan.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
/*
|
||||
Note(jpc): implementation status
|
||||
|
||||
- [x] apan_waveform
|
||||
- [x] apan_freq
|
||||
- [ ] apan_freq_oncc
|
||||
- [x] apan_phase
|
||||
- [ ] apan_phase_oncc
|
||||
- [x] apan_dry
|
||||
- [ ] apan_dry_oncc
|
||||
- [x] apan_wet
|
||||
- [ ] apan_wet_oncc
|
||||
- [x] apan_depth
|
||||
- [ ] apan_depth_oncc
|
||||
*/
|
||||
|
||||
#include "Apan.h"
|
||||
#include "Macros.h"
|
||||
#include "CommonLFO.h"
|
||||
#include "Opcode.h"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
namespace sfz {
|
||||
namespace fx {
|
||||
|
||||
void Apan::setSampleRate(double sampleRate)
|
||||
{
|
||||
_samplePeriod = 1.0 / sampleRate;
|
||||
}
|
||||
|
||||
void Apan::setSamplesPerBlock(int samplesPerBlock)
|
||||
{
|
||||
_lfoOutLeft.resize(samplesPerBlock);
|
||||
_lfoOutRight.resize(samplesPerBlock);
|
||||
}
|
||||
|
||||
void Apan::clear()
|
||||
{
|
||||
_lfoPhase = 0.0;
|
||||
}
|
||||
|
||||
void Apan::process(const float* const inputs[], float* const outputs[], unsigned nframes)
|
||||
{
|
||||
float dry = _dry;
|
||||
float wet = _wet;
|
||||
float depth = _depth;
|
||||
float* modL = _lfoOutLeft.data();
|
||||
float* modR = _lfoOutRight.data();
|
||||
|
||||
computeLfos(modL, modR, nframes);
|
||||
|
||||
const float* inL = inputs[0];
|
||||
const float* inR = inputs[1];
|
||||
float* outL = outputs[0];
|
||||
float* outR = outputs[1];
|
||||
|
||||
for (unsigned i = 0; i < nframes; ++i) {
|
||||
float modDD = depth * 0.5f * (modL[i] - modR[i]); // LFO in ±depth
|
||||
|
||||
// uses a linear pan law
|
||||
float gainL = 1 - modDD;
|
||||
float gainR = 1 + modDD;
|
||||
|
||||
outL[i] = inL[i] * (gainL * wet + dry);
|
||||
outR[i] = inR[i] * (gainR * wet + dry);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Effect> Apan::makeInstance(absl::Span<const Opcode> members)
|
||||
{
|
||||
std::unique_ptr<Apan> fx { new Apan };
|
||||
|
||||
for (const Opcode& opc : members) {
|
||||
switch (opc.lettersOnlyHash) {
|
||||
case hash("apan_waveform"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanWaveformRange))
|
||||
fx->_lfoWave = *value;
|
||||
break;
|
||||
case hash("apan_freq"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanFrequencyRange))
|
||||
fx->_lfoFrequency = *value;
|
||||
break;
|
||||
case hash("apan_phase"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanPhaseRange)) {
|
||||
float phase = *value / 360.0f;
|
||||
phase -= static_cast<int>(phase);
|
||||
fx->_lfoPhaseOffset = phase;
|
||||
}
|
||||
break;
|
||||
case hash("apan_dry"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanLevelRange))
|
||||
fx->_dry = *value / 100.0f;
|
||||
break;
|
||||
case hash("apan_wet"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanLevelRange))
|
||||
fx->_wet = *value / 100.0f;
|
||||
break;
|
||||
case hash("apan_depth"):
|
||||
if (auto value = readOpcode(opc.value, Default::apanLevelRange))
|
||||
fx->_depth = *value / 100.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CXX11_MOVE(fx);
|
||||
}
|
||||
|
||||
void Apan::computeLfos(float* left, float* right, unsigned nframes)
|
||||
{
|
||||
switch (_lfoWave) {
|
||||
#define CASE(X) case lfo::X: \
|
||||
computeLfos<lfo::X>(left, right, nframes); break;
|
||||
default:
|
||||
CASE(kTriangle)
|
||||
CASE(kSine)
|
||||
CASE(kPulse75)
|
||||
CASE(kSquare)
|
||||
CASE(kPulse25)
|
||||
CASE(kPulse12_5)
|
||||
CASE(kRamp)
|
||||
CASE(kSaw)
|
||||
#undef CASE
|
||||
}
|
||||
}
|
||||
|
||||
template <int Wave> void Apan::computeLfos(float* left, float* right, unsigned nframes)
|
||||
{
|
||||
float samplePeriod = _samplePeriod;
|
||||
float frequency = _lfoFrequency;
|
||||
float offset = _lfoPhaseOffset;
|
||||
float phaseLeft = _lfoPhase;
|
||||
|
||||
for (unsigned i = 0; i < nframes; ++i) {
|
||||
float phaseRight = phaseLeft + offset;
|
||||
phaseRight -= static_cast<int>(phaseRight);
|
||||
|
||||
left[i] = lfo::evaluateAtPhase<Wave>(phaseLeft);
|
||||
right[i] = lfo::evaluateAtPhase<Wave>(phaseRight);
|
||||
|
||||
phaseLeft += frequency * samplePeriod;
|
||||
phaseLeft -= static_cast<int>(phaseLeft);
|
||||
}
|
||||
|
||||
_lfoPhase = phaseLeft;
|
||||
}
|
||||
|
||||
} // namespace fx
|
||||
} // namespace sfz
|
||||
67
src/sfizz/effects/Apan.h
Normal file
67
src/sfizz/effects/Apan.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
#include "Effects.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
namespace sfz {
|
||||
namespace fx {
|
||||
|
||||
/**
|
||||
* @brief Effect which does nothing
|
||||
*/
|
||||
class Apan : public Effect {
|
||||
public:
|
||||
/**
|
||||
* @brief Initializes with the given sample rate.
|
||||
*/
|
||||
void setSampleRate(double sampleRate) override;
|
||||
|
||||
/**
|
||||
* @brief Sets the maximum number of frames to render at a time. The actual
|
||||
* value can be lower but should never be higher.
|
||||
*/
|
||||
void setSamplesPerBlock(int samplesPerBlock) override;
|
||||
|
||||
/**
|
||||
* @brief Reset the state to initial.
|
||||
*/
|
||||
void clear() override;
|
||||
|
||||
/**
|
||||
* @brief Copy the input signal to the output
|
||||
*/
|
||||
void process(const float* const inputs[], float* const outputs[], unsigned nframes) override;
|
||||
|
||||
/**
|
||||
* @brief Instantiates given the contents of the <effect> block.
|
||||
*/
|
||||
static std::unique_ptr<Effect> makeInstance(absl::Span<const Opcode> members);
|
||||
|
||||
private:
|
||||
void computeLfos(float* left, float* right, unsigned nframes);
|
||||
template <int Wave> void computeLfos(float* left, float* right, unsigned nframes);
|
||||
|
||||
private:
|
||||
float _samplePeriod = 0.0;
|
||||
sfz::Buffer<float> _lfoOutLeft { config::defaultSamplesPerBlock };
|
||||
sfz::Buffer<float> _lfoOutRight { config::defaultSamplesPerBlock };
|
||||
|
||||
// Controls
|
||||
float _dry = 0.0;
|
||||
float _wet = 0.0;
|
||||
float _depth = 0.0;
|
||||
int _lfoWave = 0;
|
||||
float _lfoFrequency = 0.0;
|
||||
float _lfoPhaseOffset = 0.5;
|
||||
|
||||
// State
|
||||
float _lfoPhase = 0.0;
|
||||
};
|
||||
|
||||
} // namespace fx
|
||||
} // namespace sfz
|
||||
30
src/sfizz/effects/CommonLFO.h
Normal file
30
src/sfizz/effects/CommonLFO.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sfz {
|
||||
namespace fx {
|
||||
namespace lfo {
|
||||
|
||||
enum Wave {
|
||||
kTriangle,
|
||||
kSine,
|
||||
kPulse75,
|
||||
kSquare,
|
||||
kPulse25,
|
||||
kPulse12_5,
|
||||
kRamp,
|
||||
kSaw,
|
||||
};
|
||||
|
||||
template <int Wave> float evaluateAtPhase(float phase);
|
||||
|
||||
} // namespace lfo
|
||||
} // namespace fx
|
||||
} // namespace sfz
|
||||
|
||||
#include "CommonLFO.hpp"
|
||||
68
src/sfizz/effects/CommonLFO.hpp
Normal file
68
src/sfizz/effects/CommonLFO.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "CommonLFO.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace sfz {
|
||||
namespace fx {
|
||||
namespace lfo {
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kTriangle>(float phase)
|
||||
{
|
||||
float y = -4 * phase + 2;
|
||||
y = (phase < 0.25f) ? (4 * phase) : y;
|
||||
y = (phase > 0.75f) ? (4 * phase - 4) : y;
|
||||
return y;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kSine>(float phase)
|
||||
{
|
||||
float x = phase + phase - 1;
|
||||
return 4 * x * (1 - std::fabs(x));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kPulse75>(float phase)
|
||||
{
|
||||
return (phase < 0.75f) ? +1.0f : -1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kSquare>(float phase)
|
||||
{
|
||||
return (phase < 0.5f) ? +1.0f : -1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kPulse25>(float phase)
|
||||
{
|
||||
return (phase < 0.25f) ? +1.0f : -1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kPulse12_5>(float phase)
|
||||
{
|
||||
return (phase < 0.125f) ? +1.0f : -1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kRamp>(float phase)
|
||||
{
|
||||
return 2 * phase - 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float evaluateAtPhase<kSaw>(float phase)
|
||||
{
|
||||
return 1 - 2 * phase;
|
||||
}
|
||||
|
||||
} // namespace lfo
|
||||
} // namespace fx
|
||||
} // namespace sfz
|
||||
|
|
@ -92,7 +92,7 @@ namespace fx {
|
|||
}
|
||||
}
|
||||
|
||||
return std::move(fx);
|
||||
return CXX11_MOVE(fx);
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue