From afee12344c580618cb109ac7b8ca4b35991562a9 Mon Sep 17 00:00:00 2001 From: Segfault1602 Date: Wed, 8 Nov 2023 22:27:24 -0800 Subject: [PATCH] Rename dsp namespace to sfdsp --- .vscode/launch.json | 5 +- include/basic_oscillators.h | 4 +- include/bow_table.h | 6 +- include/bowed_string.h | 12 +- include/chorus.h | 4 +- include/circular_buffer.h | 4 +- include/delayline.h | 7 +- include/delayline_linear.h | 4 +- include/dsp_base.h | 4 +- include/filter.h | 4 +- include/interpolation_strategy.h | 4 +- include/junction.h | 4 +- include/line.h | 4 +- include/phaseshapers.h | 4 +- include/rms.h | 4 +- include/sin_table.h | 4 +- include/sinc_resampler.h | 4 +- include/string_ensemble.h | 11 +- include/termination.h | 4 +- include/waveguide.h | 24 ++-- include/waveguide_gate.h | 7 +- include/window_functions.h | 4 +- scripts/make_sine_lut.py | 2 +- src/basic_oscillators.cpp | 5 +- src/bow_table.cpp | 2 +- src/bowed_string.cpp | 34 +++-- src/chorus.cpp | 4 +- src/delayline.cpp | 9 +- src/dsp_base.cpp | 4 +- src/filter.cpp | 5 +- src/interpolation_strategy.cpp | 4 +- src/junction.cpp | 4 +- src/line.cpp | 4 +- src/phaseshapers.cpp | 14 +- src/rms.cpp | 4 +- src/sinc_resampler.cpp | 4 +- src/string_ensemble.cpp | 19 ++- src/termination.cpp | 4 +- src/waveguide.cpp | 41 +++--- src/waveguide_gate.cpp | 39 +++-- tests/CMakeLists.txt | 2 +- tests/basic_oscillators_tests.cpp | 4 +- tests/circular_buffer_tests.cpp | 10 +- tests/delayline_tests.cpp | 54 +++---- tests/rms_tests.cpp | 2 +- tests/sinc_resampler_tests.cpp | 6 +- tests/test_utils.cpp | 8 +- tests/test_utils.h | 6 +- tests/waveguide_gates_tests.cpp | 227 ++++++++++++++++++++++++++++-- tests/waveguide_tests.cpp | 78 +++------- tools/CMakeLists.txt | 3 +- tools/bowedstring_tests.cpp | 79 ++++++++--- tools/bowedstring_tests.h | 39 +++-- tools/dsp_tester.h | 2 +- tools/effect_player.cpp | 3 +- tools/phaseshapers_tests.cpp | 2 +- tools/phaseshapers_tests.h | 4 +- tools/player/player.cpp | 14 +- tools/resampler.cpp | 2 +- tools/stringensemble_tests.cpp | 2 +- tools/stringensemble_tests.h | 2 +- tools/test_utils.cpp | 12 +- tools/tests_list.h | 5 +- tools/violonist/violonist.cpp | 2 +- tools/waveguide_tests.cpp | 47 +++++++ tools/waveguide_tests.h | 25 ++++ 66 files changed, 654 insertions(+), 320 deletions(-) create mode 100644 tools/waveguide_tests.cpp create mode 100644 tools/waveguide_tests.h diff --git a/.vscode/launch.json b/.vscode/launch.json index f337642..671c675 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -84,7 +84,7 @@ "request": "launch", "program": "${workspaceFolder}/build/tests/libdsp_tests.exe", "args": [ - "--gtest_filter=WaveguideGatesTest.ClosedGates" + "--gtest_filter=WaveguideGatesTest.SineWave" ], "stopAtEntry": false, "cwd": "${fileDirname}", @@ -115,9 +115,8 @@ "request": "launch", "program": "${workspaceFolder}/build/tools/effect_player.exe", "args": [ - "-r", "-t", - "8" + "10" ], "stopAtEntry": false, "cwd": "${fileDirname}", diff --git a/include/basic_oscillators.h b/include/basic_oscillators.h index 3fcf0be..43b6121 100644 --- a/include/basic_oscillators.h +++ b/include/basic_oscillators.h @@ -1,6 +1,6 @@ #pragma once -namespace dsp +namespace sfdsp { /// @brief Simple sine wave /// @param phase Phase of the sine wave @@ -25,4 +25,4 @@ float Square(float phase); /// @brief Simple noise generator /// @return float Noise(); -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/bow_table.h b/include/bow_table.h index 0be0fc7..29f636a 100644 --- a/include/bow_table.h +++ b/include/bow_table.h @@ -1,6 +1,6 @@ #pragma once -namespace dsp +namespace sfdsp { /// @brief Simple bowed string non-linear function taken from the STK. /// https://github.com/thestk/stk/blob/master/include/BowTable.h @@ -14,7 +14,7 @@ class BowTable /// @param f Force of the bow void SetForce(float f) { - force_ = 5.f - (4.5f * f); + force_ = 5.f - (4.f * f); } /// @brief Returns the force of the bow @@ -43,4 +43,4 @@ class BowTable float force_ = 3.f; float offset_ = 0.001f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/bowed_string.h b/include/bowed_string.h index 7030bc5..4fa05a4 100644 --- a/include/bowed_string.h +++ b/include/bowed_string.h @@ -6,10 +6,11 @@ #include "rms.h" #include "termination.h" #include "waveguide.h" +#include "waveguide_gate.h" #include -namespace dsp +namespace sfdsp { /// @brief Implements a bowed string model using a waveguide composed of a right traveling wave and a left traveling @@ -84,11 +85,16 @@ class BowedString /// @return The output sample at the bridge. float Tick(float input = 0.f); + /// @brief Set the finger pressure. + /// @param pressure 0 is no pressure, 1 is full pressure. + void SetFingerPressure(float pressure); + private: Waveguide waveguide_; + WaveguideGate gate_; float bow_position_ = 0.f; - float relative_bow_position_ = 0.2f; + float relative_bow_position_ = 0.15f; Termination nut_; Termination bridge_; @@ -107,4 +113,4 @@ class BowedString OnePoleFilter decay_filter_; OnePoleFilter noise_lp_filter_; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/chorus.h b/include/chorus.h index 12574b2..6a7d4d5 100644 --- a/include/chorus.h +++ b/include/chorus.h @@ -14,7 +14,7 @@ #include "dsp_base.h" #include -namespace dsp +namespace sfdsp { /// @brief Simple chorus effect. class Chorus : public DspBase @@ -79,4 +79,4 @@ class Chorus : public DspBase float chorus_mix_ = 0.5f; float input_mix_ = 0.5f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/circular_buffer.h b/include/circular_buffer.h index e71a514..a5c349b 100644 --- a/include/circular_buffer.h +++ b/include/circular_buffer.h @@ -7,7 +7,7 @@ #include "dsp_base.h" -namespace dsp +namespace sfdsp { /// @brief Simple circular buffer. /// @tparam CONTAINER_SIZE @@ -141,4 +141,4 @@ const float& CircularBuffer::operator[](size_t idx) const auto real_idx = (read_ + idx) % CONTAINER_SIZE; return buffer_[real_idx]; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/delayline.h b/include/delayline.h index cf7d245..ce7570e 100644 --- a/include/delayline.h +++ b/include/delayline.h @@ -7,7 +7,7 @@ #include "dsp_base.h" #include "interpolation_strategy.h" -namespace dsp +namespace sfdsp { /// @brief Simple delayline. @@ -69,9 +69,6 @@ class Delayline /// @param input Input sample void SetIn(float delay, float input); - /// @brief Move the write pointer of the delayline back one sample. - void Rewind(); - float& operator[](size_t index) const; float& operator[](size_t index); @@ -89,4 +86,4 @@ class Delayline std::unique_ptr interpolation_strategy_; std::unique_ptr line_; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/delayline_linear.h b/include/delayline_linear.h index 2441ae6..40c4ff6 100644 --- a/include/delayline_linear.h +++ b/include/delayline_linear.h @@ -7,7 +7,7 @@ #include "delayline.h" #include "dsp_base.h" -namespace dsp +namespace sfdsp { /// @brief Implements a linear delayline with a maximum delay of MAX_DELAY @@ -34,4 +34,4 @@ class LinearDelayline : public Delayline float next_out_ = 0.f; float last_out_ = 0.f; }; -} // namespace dsp +} // namespace sfdsp diff --git a/include/dsp_base.h b/include/dsp_base.h index ca9f33f..0a82ce5 100644 --- a/include/dsp_base.h +++ b/include/dsp_base.h @@ -9,7 +9,7 @@ #define TWO_PI (2.0f * PI_F) -namespace dsp +namespace sfdsp { class DspBase { @@ -66,4 +66,4 @@ constexpr float midi_to_freq[128] = { 7902.1328201f, 8372.01808962f, 8869.84419126f, 9397.27257336f, 9956.06347911f, 10548.0818212f, 11175.3034059f, 11839.8215268f, }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/filter.h b/include/filter.h index 9be1a9e..46e70a9 100644 --- a/include/filter.h +++ b/include/filter.h @@ -13,7 +13,7 @@ #include #include -namespace dsp +namespace sfdsp { /// @brief Base class for filters class Filter @@ -112,4 +112,4 @@ class Biquad : public Filter float Tick(float in) override; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/interpolation_strategy.h b/include/interpolation_strategy.h index 6bd4328..91980bc 100644 --- a/include/interpolation_strategy.h +++ b/include/interpolation_strategy.h @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { enum class InterpolationType @@ -60,4 +60,4 @@ class AllpassInterpolation : public InterpolationStrategy float last_out_; float allpass_input_; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/junction.h b/include/junction.h index 0229fe7..d6345ae 100644 --- a/include/junction.h +++ b/include/junction.h @@ -5,7 +5,7 @@ #include "delayline.h" #include -namespace dsp +namespace sfdsp { /// @brief Implements a junction point between two delaylines @@ -24,4 +24,4 @@ class Junction float delay_ = 0; // float gain_ = 1.f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/line.h b/include/line.h index 91b35d3..b400f0a 100644 --- a/include/line.h +++ b/include/line.h @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { /// @brief Simple ramp generator. class Line @@ -20,4 +20,4 @@ class Line float output_ = 0.f; float increment_ = 0.f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/phaseshapers.h b/include/phaseshapers.h index bcd7088..4033139 100644 --- a/include/phaseshapers.h +++ b/include/phaseshapers.h @@ -14,7 +14,7 @@ #include "dsp_base.h" -namespace dsp +namespace sfdsp { /// @brief Phaseshaper oscillator that can morph between different waveforms @@ -99,4 +99,4 @@ class Phaseshaper float m_mod = 0.f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/rms.h b/include/rms.h index 7671394..c3fe5be 100644 --- a/include/rms.h +++ b/include/rms.h @@ -2,7 +2,7 @@ #include "delayline.h" -namespace dsp +namespace sfdsp { /// @brief Root Mean Square calculator @@ -30,4 +30,4 @@ class RMS float last_out_ = 0.f; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/sin_table.h b/include/sin_table.h index e41dec9..2ea6b2e 100644 --- a/include/sin_table.h +++ b/include/sin_table.h @@ -1,7 +1,7 @@ // Auto-generated file from make_sine_table.py #pragma once -namespace dsp +namespace sfdsp { constexpr size_t SIN_LUT_SIZE = 512; const float sin_lut[SIN_LUT_SIZE + 1] = { @@ -72,4 +72,4 @@ const float sin_lut[SIN_LUT_SIZE + 1] = { -0.09801714f, -0.08579731f, -0.07356456f, -0.06132074f, -0.04906767f, -0.03680722f, -0.02454123f, -0.01227154f, -0.00000000f, }; -} // namespace dsp +} // namespace sfdsp diff --git a/include/sinc_resampler.h b/include/sinc_resampler.h index af0e60a..698a0dd 100644 --- a/include/sinc_resampler.h +++ b/include/sinc_resampler.h @@ -7,7 +7,7 @@ #include -namespace dsp +namespace sfdsp { /// @brief Resamples the input signal by the given ratio using a windowed sinc filter /// @param in Input signal @@ -16,4 +16,4 @@ namespace dsp /// @param out Output signal /// @param[in, out] out_size Size of the output signal void sinc_resample(const float* in, size_t input_size, float ratio, float* out, size_t& out_size); -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/string_ensemble.h b/include/string_ensemble.h index 4c70426..a912a4a 100644 --- a/include/string_ensemble.h +++ b/include/string_ensemble.h @@ -5,7 +5,7 @@ #include "bowed_string.h" #include "dsp_base.h" -namespace dsp +namespace sfdsp { constexpr size_t kStringCount = 4; @@ -57,13 +57,18 @@ class StringEnsemble /// @param string_number void FingerOff(uint8_t string_number); + /// @brief Set the amount of energy transmitted from one string to the others + /// @param t + void SetBridgeTransmission(float t); + float Tick(); private: - std::array strings_; + std::array strings_; std::array openTuning_; + float bridgeTransmission_ = 0.1f; OnePoleFilter transmission_filter_; Biquad body_filters_[6]; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/termination.h b/include/termination.h index 46c3c7f..7be864e 100644 --- a/include/termination.h +++ b/include/termination.h @@ -5,7 +5,7 @@ #include "delayline.h" #include "filter.h" -namespace dsp +namespace sfdsp { /// @brief Base class for termination points between two delaylines /// @note For now, a termination is simply a gain and a filter and the class mostly exists for readability. @@ -35,4 +35,4 @@ class Termination float gain_ = -1.f; Filter* filter_ = nullptr; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/waveguide.h b/include/waveguide.h index 699eb6b..773bdfa 100644 --- a/include/waveguide.h +++ b/include/waveguide.h @@ -6,9 +6,8 @@ #include "dsp_base.h" #include "interpolation_strategy.h" #include "junction.h" -#include "waveguide_gate.h" -namespace dsp +namespace sfdsp { /// @brief Simple waveguide model composed of a right traveling wave and a left traveling wave. @@ -29,16 +28,6 @@ class Waveguide /// @return float GetDelay() const; - /// @brief Set the junction position. - /// @param pos position of the junction in sample - /// @note Junction isn't the right name for this, at least for now. This is basically a sliding nut and is used to - /// change the length of the waveguide in a physically sensible way. - void SetJunctionDelay(float pos); - - /// @brief Returns the junction position. - /// @return The junction position. - float GetJunctionDelay() const; - /// @brief Returns the output sample of the right traveling wave and left traveling wave. /// @param right Output sample of the right traveling wave. /// @param left Output sample of the left traveling wave. @@ -85,14 +74,19 @@ class Waveguide /// @param interpolation_strategy void TapOut(float delay, float& right_out, float& left_out, InterpolationStrategy* interpolation_strategy); + /// @brief Subscript operator to access the delaylines. + /// @param index 0 is the right traveling wave, 1 is the left traveling wave. + /// @return + const Delayline& operator[](size_t index) const; + Delayline& operator[](size_t index); + private: const size_t max_size_ = 0; float current_delay_ = 0.f; Delayline right_traveling_line_; Delayline left_traveling_line_; - Junction junction_; - WaveguideGate gate_; + friend class WaveguideGate; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/waveguide_gate.h b/include/waveguide_gate.h index 4d43d47..051bdf4 100644 --- a/include/waveguide_gate.h +++ b/include/waveguide_gate.h @@ -3,8 +3,9 @@ #include "dsp_base.h" #include "delayline.h" +#include "waveguide.h" -namespace dsp +namespace sfdsp { /// @brief Implements a "reflection" point in a waveguide. @@ -24,6 +25,8 @@ class WaveguideGate void Process(Delayline& left_traveling_line, Delayline& right_traveling_line); + void Process(Waveguide& wave); + private: float coeff_ = 0.f; float delay_ = 0.f; @@ -37,4 +40,4 @@ class WaveguideGate bool delay_decreased_ = false; bool delay_increased_ = false; }; -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/include/window_functions.h b/include/window_functions.h index 19cdb4f..784533e 100644 --- a/include/window_functions.h +++ b/include/window_functions.h @@ -4,7 +4,7 @@ #include "dsp_base.h" -namespace dsp +namespace sfdsp { /// @brief Returns the value of a Hann window of size L at index x. /// @param i Index of the Hann window. @@ -14,4 +14,4 @@ float Hann(float x, float L) { return 0.5f * (1.f - std::cos((TWO_PI * x) / L)); } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/scripts/make_sine_lut.py b/scripts/make_sine_lut.py index 9b58d56..4e33c0b 100644 --- a/scripts/make_sine_lut.py +++ b/scripts/make_sine_lut.py @@ -8,7 +8,7 @@ print(f"// Auto-generated file from make_sine_table.py") print("#pragma once") print("") -print("namespace dsp") +print("namespace sfdsp") print("{") print(f"constexpr size_t SIN_LUT_SIZE = {TABLE_SIZE};") print(f"const float sin_lut[TABLE_SIZE+1] = {{") diff --git a/src/basic_oscillators.cpp b/src/basic_oscillators.cpp index bd12f4f..cfaca1a 100644 --- a/src/basic_oscillators.cpp +++ b/src/basic_oscillators.cpp @@ -5,7 +5,7 @@ #include "dsp_base.h" #include "sin_table.h" -namespace dsp +namespace sfdsp { float Sine(float phase) @@ -19,6 +19,7 @@ float Sine(float phase) float Tri(float phase) { + phase = std::fmod(phase, 1.f); if (phase < 0.5f) { return 2.f * phase - 1.f; @@ -45,4 +46,4 @@ float Noise() return 2.f * rand() * kOneOverRandMax - 1.f; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/bow_table.cpp b/src/bow_table.cpp index ba822d2..743abc2 100644 --- a/src/bow_table.cpp +++ b/src/bow_table.cpp @@ -6,7 +6,7 @@ /// @brief Simple bowed string non-linear function taken from the STK. /// https://github.com/thestk/stk/blob/master/include/BowTable.cpp -using namespace dsp; +using namespace sfdsp; float BowTable::Tick(float in) const { diff --git a/src/bowed_string.cpp b/src/bowed_string.cpp index e50a47f..fd46bb1 100644 --- a/src/bowed_string.cpp +++ b/src/bowed_string.cpp @@ -6,10 +6,10 @@ #include "basic_oscillators.h" #include "window_functions.h" -namespace dsp +namespace sfdsp { -BowedString::BowedString(size_t max_size) : waveguide_(max_size, InterpolationType::Linear) +BowedString::BowedString(size_t max_size) : waveguide_(max_size, InterpolationType::Linear), gate_(true, 0.f, 1.f) { } @@ -27,6 +27,7 @@ void BowedString::Init(float samplerate, float tuning) waveguide_.SetDelay(string_length - 1.f); bridge_.SetFilter(&reflection_filter_); + nut_.SetGain(-0.98f); // Decay filter for add. noise constexpr float decayDb = -12.f; @@ -42,13 +43,14 @@ void BowedString::SetFrequency(float f) freq_ = f; float delay = (samplerate_ / freq_) * 0.5f; delay -= 1.f; // delay compensation, tuned by ear - waveguide_.SetJunctionDelay(delay); + + gate_.SetDelay(delay); SetBowPosition(relative_bow_position_); } void BowedString::SetDelay(float delay) { - waveguide_.SetJunctionDelay(delay); + gate_.SetDelay(delay); SetBowPosition(relative_bow_position_); freq_ = samplerate_ / (delay * 2); @@ -84,18 +86,21 @@ void BowedString::SetBowPosition(float pos) { relative_bow_position_ = pos; - bow_position_ = waveguide_.GetJunctionDelay() * relative_bow_position_; + // The gate delay is where the 'finger' is. We want the bow position to be relative to that. + bow_position_ = gate_.GetDelay() * relative_bow_position_; if (bow_position_ <= 1.f) { bow_position_ += 1.f; } - else if (bow_position_ > waveguide_.GetJunctionDelay() - 2.f) + else if (bow_position_ > gate_.GetDelay() - 2.f) { - bow_position_ = waveguide_.GetJunctionDelay() - 2.f; + bow_position_ = gate_.GetDelay() - 2.f; } bow_position_ = std::ceil(bow_position_); + + assert(bow_position_ > 0 && bow_position_ < gate_.GetDelay()); } float BowedString::GetBowPosition() const @@ -115,7 +120,7 @@ bool BowedString::GetNoteOn() const void BowedString::Pluck() { - float L = waveguide_.GetJunctionDelay(); + float L = gate_.GetDelay(); for (float i = 1; i < static_cast(L); ++i) { waveguide_.TapIn(i, Hann(i - 1, L)); @@ -151,8 +156,17 @@ float BowedString::Tick(float input) } waveguide_.TapIn(bow_position_, bow_output); - waveguide_.Tick(bridge_.Tick(-bridge), nut_.Tick(nut)); + + gate_.Process(waveguide_); + waveguide_.Tick(bridge_.Tick(-input), nut_.Tick(nut)); return bridge; } -} // namespace dsp \ No newline at end of file + +void BowedString::SetFingerPressure(float pressure) +{ + pressure = std::clamp(pressure, 0.f, 1.f); + gate_.SetCoeff(pressure); +} + +} // namespace sfdsp \ No newline at end of file diff --git a/src/chorus.cpp b/src/chorus.cpp index b7d73f7..74f100f 100644 --- a/src/chorus.cpp +++ b/src/chorus.cpp @@ -2,7 +2,7 @@ #include "basic_oscillators.h" -namespace dsp +namespace sfdsp { Chorus::Chorus(size_t max_delay_size) : delay_(max_delay_size) { @@ -81,4 +81,4 @@ float Chorus::Tick(float in) return delay_.Tick(xn) * FF + BL * xn; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/delayline.cpp b/src/delayline.cpp index 751d86c..6412576 100644 --- a/src/delayline.cpp +++ b/src/delayline.cpp @@ -4,7 +4,7 @@ #include #include -namespace dsp +namespace sfdsp { Delayline::Delayline(size_t max_size, bool reverse, InterpolationType interpolation_type) : max_size_(max_size), reverse_(reverse) @@ -123,11 +123,6 @@ void Delayline::SetIn(float delay, float input) } } -void Delayline::Rewind() -{ - write_ptr_ = (write_ptr_ + 1) % max_size_; -} - float& Delayline::operator[](size_t index) const { if (reverse_) @@ -148,4 +143,4 @@ float& Delayline::operator[](size_t index) return line_[read_ptr]; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/dsp_base.cpp b/src/dsp_base.cpp index 3c6963c..4c7cc4e 100644 --- a/src/dsp_base.cpp +++ b/src/dsp_base.cpp @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { float MidiToFreq(float midi_note) @@ -45,4 +45,4 @@ float FreqToMidi(float freq) return (17.3123405046f * logf(.12231220585f * freq)); } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/filter.cpp b/src/filter.cpp index 1460d40..21de846 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { void Filter::SetGain(float gain) { @@ -38,6 +38,7 @@ void OnePoleFilter::SetPole(float pole) void OnePoleFilter::SetDecayFilter(float decayDb, float timeMs, float samplerate) { + assert(decayDb < 0.f); const float lambda = std::log(std::pow(10.f, (decayDb / 20.f))); const float pole = std::exp(lambda / (timeMs / 1000.f) / samplerate); SetPole(pole); @@ -93,4 +94,4 @@ float Biquad::Tick(float in) outputs_[1] = outputs_[0]; return outputs_[0]; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/interpolation_strategy.cpp b/src/interpolation_strategy.cpp index c245882..49cc72d 100644 --- a/src/interpolation_strategy.cpp +++ b/src/interpolation_strategy.cpp @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { float NoInterpolation::TapOut(float* buffer, size_t max_size, size_t write_ptr, float delay) @@ -75,4 +75,4 @@ void AllpassInterpolation::CalculateCoeff(float delay) } } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/junction.cpp b/src/junction.cpp index b376c90..e008066 100644 --- a/src/junction.cpp +++ b/src/junction.cpp @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { void Junction::SetDelay(float delay) { @@ -89,4 +89,4 @@ void Junction::Tick(Delayline& left_traveling_line, Delayline& right_traveling_l right_traveling_line.SetIn(read_ptr + 1, 0.f); } } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/line.cpp b/src/line.cpp index 62f8c2d..269580d 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -1,6 +1,6 @@ #include "line.h" -namespace dsp +namespace sfdsp { Line::Line(float start, float end, uint32_t time_samples) : start_(start), end_(end), output_(start) { @@ -28,4 +28,4 @@ float Line::Tick() } } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/phaseshapers.cpp b/src/phaseshapers.cpp index 68ac20e..287bdf3 100644 --- a/src/phaseshapers.cpp +++ b/src/phaseshapers.cpp @@ -116,7 +116,7 @@ float polyBLEP(float x, float phase, float T, float h = -1.f) return s; } -namespace dsp +namespace sfdsp { void Phaseshaper::Init(float sampleRate) @@ -160,7 +160,7 @@ float Phaseshaper::ProcessWaveSlice() const // a1 vary from 0.25 to 0.40 float a1 = 0.25f + (m_mod * 0.15f); float slicePhase = g_lin(m_phase, a1); - float trivial = G_B(dsp::Sine(slicePhase)); + float trivial = G_B(sfdsp::Sine(slicePhase)); float blep = polyBLEP(trivial, m_phase, m_phaseIncrement, -2); return blep; @@ -199,10 +199,10 @@ float Phaseshaper::ProcessSupersaw() const float supersawPhase = MODM(xs, m1) + MODM(xs, m2); - // Original equation was sin(supersawPhase) but since dsp::Sine expects a value between 0 and 1 + // Original equation was sin(supersawPhase) but since sfdsp::Sine expects a value between 0 and 1 // we need to remove the implied 2pi factor. constexpr float one_over_2pi = 1.f / TWO_PI; - return G_B(dsp::Sine(supersawPhase * one_over_2pi)); + return G_B(sfdsp::Sine(supersawPhase * one_over_2pi)); } float Phaseshaper::ProcessVarSlope() const @@ -212,7 +212,7 @@ float Phaseshaper::ProcessVarSlope() const float pulse = g_pulse(m_phase, m_phaseIncrement, width, m_period); float vslope = 0.5f * m_phase * (1.0f - pulse) / width + pulse * (m_phase - width) / (1 - width); - return dsp::Sine(vslope); + return sfdsp::Sine(vslope); } float Phaseshaper::ProcessVarTri() const @@ -221,7 +221,7 @@ float Phaseshaper::ProcessVarTri() const float a1 = 1.25 + (m_mod * 0.5f); float w3 = 0.50; float vtri = g_vtri(m_phase, m_phaseIncrement, w3, a1, 0, m_period); - return dsp::Sine(vtri); + return sfdsp::Sine(vtri); } float Phaseshaper::ProcessRipple() const @@ -266,4 +266,4 @@ float Phaseshaper::ProcessWave(Waveform wave) const return out; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/rms.cpp b/src/rms.cpp index 0888b00..f043570 100644 --- a/src/rms.cpp +++ b/src/rms.cpp @@ -2,7 +2,7 @@ #include -namespace dsp +namespace sfdsp { RMS::RMS(size_t size) : buffer_(size, false, InterpolationType::None), factor_(1.f / size) { @@ -23,4 +23,4 @@ float RMS::GetRMS() const return last_out_; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/sinc_resampler.cpp b/src/sinc_resampler.cpp index 1978312..7bb0c89 100644 --- a/src/sinc_resampler.cpp +++ b/src/sinc_resampler.cpp @@ -4,7 +4,7 @@ #include "sinc_table.h" -namespace dsp +namespace sfdsp { void sinc_resample(const float* in, size_t input_size, float ratio, float* out, size_t& out_size) @@ -69,4 +69,4 @@ void sinc_resample(const float* in, size_t input_size, float ratio, float* out, out_size = out_idx; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/string_ensemble.cpp b/src/string_ensemble.cpp index 02e3271..39a4d52 100644 --- a/src/string_ensemble.cpp +++ b/src/string_ensemble.cpp @@ -2,7 +2,7 @@ #include -using namespace dsp; +using namespace sfdsp; void StringEnsemble::Init(float samplerate, const std::array& frequencies) { @@ -35,6 +35,7 @@ void StringEnsemble::TuneStrings(uint8_t string_number, float frequencies) void StringEnsemble::SetFrequency(uint8_t string_number, float f) { assert(string_number < kStringCount); + assert(f > 0.f); strings_[string_number].SetFrequency(f); } @@ -89,27 +90,33 @@ void StringEnsemble::FingerOff(uint8_t string_number) strings_[string_number].SetFrequency(openTuning_[string_number]); } +void StringEnsemble::SetBridgeTransmission(float t) +{ + assert(t >= 0.f && t <= 1.f); + + bridgeTransmission_ = t; +} + float StringEnsemble::Tick() { std::array string_outs; - constexpr float kTransmissionRatio = 0.10f; float transmission = 0.f; float output = 0.f; for (auto i = 0; i < kStringCount; ++i) { string_outs[i] = strings_[i].NextOut(); output += string_outs[i]; - transmission += string_outs[i] * kTransmissionRatio; - string_outs[i] *= (1.f - kTransmissionRatio); + transmission += string_outs[i] * bridgeTransmission_; + string_outs[i] *= (1.f - bridgeTransmission_); } // filter the bridge output - transmission = transmission_filter_.Tick(transmission); + transmission = transmission_filter_.Tick(transmission) * 0.25f; for (size_t i = 0; i < kStringCount; ++i) { - strings_[i].Tick(string_outs[i] + transmission * 0.25f); + strings_[i].Tick(string_outs[i] + transmission); } float out = 0.1248f * body_filters_[5].Tick(body_filters_[4].Tick(body_filters_[3].Tick( diff --git a/src/termination.cpp b/src/termination.cpp index b53b5db..37d6ddf 100644 --- a/src/termination.cpp +++ b/src/termination.cpp @@ -1,6 +1,6 @@ #include "termination.h" -namespace dsp +namespace sfdsp { Termination::Termination(float gain) : gain_(gain) { @@ -25,4 +25,4 @@ float Termination::Tick(float in) return in * gain_; } -} // namespace dsp \ No newline at end of file +} // namespace sfdsp \ No newline at end of file diff --git a/src/waveguide.cpp b/src/waveguide.cpp index 38e6df8..a562a4a 100644 --- a/src/waveguide.cpp +++ b/src/waveguide.cpp @@ -2,15 +2,14 @@ #include -namespace dsp +namespace sfdsp { Waveguide::Waveguide(size_t max_size, InterpolationType interpolation_type) : max_size_(max_size), right_traveling_line_(max_size, false, interpolation_type), - left_traveling_line_(max_size, true, interpolation_type), gate_(true, 0.f, 0.9f) + left_traveling_line_(max_size, true, interpolation_type) { SetDelay(static_cast(max_size - 1)); - SetJunctionDelay(0); } void Waveguide::SetDelay(float delay) @@ -30,16 +29,6 @@ float Waveguide::GetDelay() const return current_delay_; } -void Waveguide::SetJunctionDelay(float pos) -{ - gate_.SetDelay(pos); -} - -float Waveguide::GetJunctionDelay() const -{ - return gate_.GetDelay(); -} - void Waveguide::NextOut(float& right, float& left) { right = right_traveling_line_.NextOut(); @@ -48,9 +37,6 @@ void Waveguide::NextOut(float& right, float& left) void Waveguide::Tick(float right, float left) { - // Always tick the junction(s) first - gate_.Process(left_traveling_line_, right_traveling_line_); - right_traveling_line_.Tick(right); left_traveling_line_.Tick(left); } @@ -117,4 +103,25 @@ void Waveguide::TapOut(float delay, float& right_out, float& left_out, Interpola left_out = left_traveling_line_.TapOut(delay, interpolation_strategy); } -} // namespace dsp \ No newline at end of file +const Delayline& Waveguide::operator[](size_t index) const +{ + if (index == 0) + { + return right_traveling_line_; + } + + assert(index == 1); + return left_traveling_line_; +} + +Delayline& Waveguide::operator[](size_t index) +{ + if (index == 0) + { + return right_traveling_line_; + } + + assert(index == 1); + return left_traveling_line_; +} +} // namespace sfdsp \ No newline at end of file diff --git a/src/waveguide_gate.cpp b/src/waveguide_gate.cpp index 1951024..4704f09 100644 --- a/src/waveguide_gate.cpp +++ b/src/waveguide_gate.cpp @@ -1,10 +1,10 @@ #include "waveguide_gate.h" -namespace dsp +namespace sfdsp { WaveguideGate::WaveguideGate(bool flip, float delay, float coeff) - : coeff_(coeff), flip_(flip ? -1.f : 1.f), delay_left_(8), delay_right_(8) + : coeff_(coeff), flip_(flip ? -1.f : 1.f), delay_left_(4), delay_right_(4) { SetDelay(delay); } @@ -14,6 +14,11 @@ void WaveguideGate::SetDelay(float delay) delay_ = delay; size_t new_delay_int = static_cast(delay); + // When the delay crosses an integer boundary, it can cause a discontinuity in the waveguide that + // is particularly audible during glissando and vibrato. + // If the delay increase or decrease is less than 1 sample, we can smooth out the discontinuity + // by using values that are already in a the delay lines. + // For greater changes in delay, it is probably best to use a second gate and crossfade between them. if (new_delay_int == (delay_integer_ - 1)) { delay_decreased_ = true; @@ -41,6 +46,16 @@ void WaveguideGate::SetCoeff(float c) coeff_ = c; } +void PrintDelayline(const sfdsp::Delayline& line) +{ + printf(" "); + for (auto i = 0; i < 4; ++i) + { + printf("%5.2f ", line[i + 1]); + } + printf("\n"); +} + void WaveguideGate::Process(Delayline& left_traveling_line, Delayline& right_traveling_line) { if (delay_ == 0 || delay_ >= left_traveling_line.GetDelay() - 2) @@ -48,18 +63,18 @@ void WaveguideGate::Process(Delayline& left_traveling_line, Delayline& right_tra return; } + // When the delay crosses an integer boundary, it can cause a discontinuity in the waveguide that + // is particularly audible during glissando and vibrato. + // If the delay increase or decrease is less than 1 sample, we can smooth out the discontinuity + // by using values that are already in a the delay lines. if (delay_decreased_) { - delay_left_.Tick(right_traveling_line[delay_integer_]); - delay_right_.Rewind(); - + right_traveling_line[delay_integer_ + 2] = delay_right_[1] * flip_; delay_decreased_ = false; } else if (delay_increased_) { - delay_right_.Tick(left_traveling_line[delay_integer_]); - delay_left_.Rewind(); - + left_traveling_line[delay_integer_] = delay_left_[1] * flip_; delay_increased_ = false; } @@ -73,6 +88,7 @@ void WaveguideGate::Process(Delayline& left_traveling_line, Delayline& right_tra float left_input = right_traveling_line[kLeftGate]; float left_interpolated = delay_left_.Tick(left_input); float left_gate_sample = left_traveling_line[kGate]; + left_traveling_line[kGate] = left_gate_sample * (1 - coeff_) + left_interpolated * (coeff_)*flip_; float right_input = left_traveling_line[kRightGate]; @@ -81,4 +97,9 @@ void WaveguideGate::Process(Delayline& left_traveling_line, Delayline& right_tra right_traveling_line[kGate] = right_gate_sample * (1 - coeff_) + right_interpolated * (coeff_)*flip_; } -} // namespace dsp \ No newline at end of file +void WaveguideGate::Process(Waveguide& wave) +{ + return Process(wave.left_traveling_line_, wave.right_traveling_line_); +} + +} // namespace sfdsp \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1555dcf..9df2a3b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,4 +21,4 @@ endif() add_test(NAME libdsp_tests COMMAND libdsp_tests) -target_link_libraries(libdsp_tests PUBLIC dsp PRIVATE GTest::gtest_main GTest::gmock_main) +target_link_libraries(libdsp_tests PUBLIC dsp PRIVATE sndfile GTest::gtest_main GTest::gmock_main) diff --git a/tests/basic_oscillators_tests.cpp b/tests/basic_oscillators_tests.cpp index 3ffa9ea..6cb304f 100644 --- a/tests/basic_oscillators_tests.cpp +++ b/tests/basic_oscillators_tests.cpp @@ -13,7 +13,7 @@ TEST(BasicOscillatorsTest, Sine) float inc = 1.f / 1024; for (auto i = 0.f; i < TWO_PI; i += inc) { - auto s = dsp::Sine(i); + auto s = sfdsp::Sine(i); auto t = std::sin(i * TWO_PI); ASSERT_NEAR(s, t, 0.0001f); } @@ -23,7 +23,7 @@ TEST(BasicOscillatorsTests, Noise) { for (auto i = 0; i < 1000; ++i) { - auto n = dsp::Noise(); + auto n = sfdsp::Noise(); ASSERT_THAT(n, ::testing::Le(1.f)); ASSERT_THAT(n, ::testing::Ge(-1.f)); } diff --git a/tests/circular_buffer_tests.cpp b/tests/circular_buffer_tests.cpp index c896b87..0152981 100644 --- a/tests/circular_buffer_tests.cpp +++ b/tests/circular_buffer_tests.cpp @@ -5,7 +5,7 @@ TEST(CircularBufferTests, Init) { const size_t max_size = 10; - dsp::CircularBuffer buf; + sfdsp::CircularBuffer buf; ASSERT_TRUE(buf.IsEmpty()); ASSERT_EQ(buf.Count(), 0); @@ -16,7 +16,7 @@ TEST(CircularBufferTests, Init) TEST(CircularBufferTests, CheckCount) { const size_t max_size = 10; - dsp::CircularBuffer buf; + sfdsp::CircularBuffer buf; for (size_t i = 0; i < buf.Size() - 1; ++i) { @@ -34,7 +34,7 @@ TEST(CircularBufferTests, CheckCount) TEST(CircularBufferTests, CheckWrite) { const size_t max_size = 10; - dsp::CircularBuffer buf; + sfdsp::CircularBuffer buf; float test_values[max_size] = {0}; for (size_t i = 0; i < max_size; ++i) @@ -58,7 +58,7 @@ TEST(CircularBufferTests, CheckWrite) TEST(CircularBufferTests, CheckRead) { const size_t max_size = 10; - dsp::CircularBuffer buf; + sfdsp::CircularBuffer buf; float test_values[max_size] = {0}; for (size_t i = 0; i < max_size; ++i) @@ -84,7 +84,7 @@ TEST(CircularBufferTests, CheckRead) TEST(CircularBufferTests, CheckOverwrite) { const size_t max_size = 10; - dsp::CircularBuffer buf; + sfdsp::CircularBuffer buf; float test_values[max_size] = {0}; for (size_t i = 0; i < max_size; ++i) diff --git a/tests/delayline_tests.cpp b/tests/delayline_tests.cpp index e735af2..1bd0c59 100644 --- a/tests/delayline_tests.cpp +++ b/tests/delayline_tests.cpp @@ -7,19 +7,19 @@ #include "test_resources.h" #include "test_utils.h" -namespace dsp +namespace sfdsp { -std::ostream& operator<<(std::ostream& os, const dsp::InterpolationType& t) +std::ostream& operator<<(std::ostream& os, const sfdsp::InterpolationType& t) { switch (t) { - case dsp::InterpolationType::None: + case sfdsp::InterpolationType::None: os << "None"; break; - case dsp::InterpolationType::Linear: + case sfdsp::InterpolationType::Linear: os << "Linear"; break; - case dsp::InterpolationType::Allpass: + case sfdsp::InterpolationType::Allpass: os << "Allpass"; break; default: @@ -28,15 +28,15 @@ std::ostream& operator<<(std::ostream& os, const dsp::InterpolationType& t) return os; } -} // namespace dsp +} // namespace sfdsp -class DelayInterpolationTest : public ::testing::TestWithParam +class DelayInterpolationTest : public ::testing::TestWithParam { public: DelayInterpolationTest() = default; }; -class DelayNotFractionalTest : public ::testing::TestWithParam +class DelayNotFractionalTest : public ::testing::TestWithParam { public: DelayNotFractionalTest() = default; @@ -47,8 +47,8 @@ TEST_P(DelayInterpolationTest, NoInterpolation) constexpr size_t max_delay_size = 100; constexpr size_t delay = 10; - dsp::InterpolationType interpolation_type = GetParam(); - dsp::Delayline line(max_delay_size, false, interpolation_type); + sfdsp::InterpolationType interpolation_type = GetParam(); + sfdsp::Delayline line(max_delay_size, false, interpolation_type); line.SetDelay(delay); @@ -77,8 +77,8 @@ TEST_P(DelayInterpolationTest, WithInterpolation) constexpr size_t max_delay_size = 100; constexpr float delay = 10.5f; - dsp::InterpolationType interpolation_type = GetParam(); - dsp::Delayline line(max_delay_size, false, interpolation_type); + sfdsp::InterpolationType interpolation_type = GetParam(); + sfdsp::Delayline line(max_delay_size, false, interpolation_type); line.SetDelay(delay); @@ -94,11 +94,11 @@ TEST_P(DelayInterpolationTest, WithInterpolation) size_t expected_result_size = 0; switch (interpolation_type) { - case dsp::InterpolationType::Linear: + case sfdsp::InterpolationType::Linear: expected_result = stkLinearInterpolationResult1.data(); expected_result_size = stkLinearInterpolationResult1.size(); break; - case dsp::InterpolationType::Allpass: + case sfdsp::InterpolationType::Allpass: expected_result = stkAllpassInterpolationResult.data(); expected_result_size = stkAllpassInterpolationResult.size(); break; @@ -117,7 +117,7 @@ TEST_P(DelayInterpolationTest, WithInterpolation) TEST(LinearDelaylineTests, WithInterpolation2) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = 10.75f; line.SetDelay(delay); @@ -141,7 +141,7 @@ TEST(LinearDelaylineTests, WithInterpolation2) TEST_P(DelayNotFractionalTest, TapOut) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size, false); + sfdsp::Delayline line(max_delay_size, false); constexpr float delay = 10; line.SetDelay(delay); @@ -171,7 +171,7 @@ TEST_P(DelayNotFractionalTest, TapOut) TEST_P(DelayNotFractionalTest, TapOutReverse) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size, true); + sfdsp::Delayline line(max_delay_size, true); constexpr float delay = 10; line.SetDelay(delay); @@ -198,7 +198,7 @@ TEST_P(DelayNotFractionalTest, TapOutReverse) TEST(LinearDelaylineTests, TapOutInterpolation) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = 10; line.SetDelay(delay); @@ -227,7 +227,7 @@ TEST(LinearDelaylineTests, TapOutInterpolation) TEST_P(DelayNotFractionalTest, TapIn) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = 10; line.SetDelay(delay); @@ -248,7 +248,7 @@ TEST_P(DelayNotFractionalTest, TapIn2) { constexpr size_t max_delay_size = 7; constexpr float delay = max_delay_size - 1; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); line.SetDelay(delay); constexpr float input[max_delay_size] = {1, 2, 3, 4, 5, 6}; @@ -263,7 +263,7 @@ TEST_P(DelayNotFractionalTest, TapIn2) TEST_P(DelayNotFractionalTest, TapInTick) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = max_delay_size - 1; line.SetDelay(delay); @@ -284,7 +284,7 @@ TEST_P(DelayNotFractionalTest, TapInTick) TEST_P(DelayNotFractionalTest, SubscriptOperator) { constexpr size_t max_delay_size = 11; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = max_delay_size - 1; line.SetDelay(delay); @@ -299,7 +299,7 @@ TEST_P(DelayNotFractionalTest, SubscriptOperator) ASSERT_EQ(i, out); } - dsp::Delayline line2(max_delay_size); + sfdsp::Delayline line2(max_delay_size); line2.SetDelay(delay); // This will give us a delay line that looks like @@ -319,7 +319,7 @@ TEST_P(DelayNotFractionalTest, SubscriptOperator) TEST(LinearDelaylineTests, TapInFrac) { constexpr size_t max_delay_size = 100; - dsp::Delayline line(max_delay_size); + sfdsp::Delayline line(max_delay_size); constexpr float delay = max_delay_size - 1; line.SetDelay(delay); @@ -330,9 +330,9 @@ TEST(LinearDelaylineTests, TapInFrac) } INSTANTIATE_TEST_SUITE_P(InterpolationTest, DelayInterpolationTest, - ::testing::Values(dsp::InterpolationType::Linear, dsp::InterpolationType::Allpass)); + ::testing::Values(sfdsp::InterpolationType::Linear, sfdsp::InterpolationType::Allpass)); INSTANTIATE_TEST_SUITE_P(DelaylineParamTest, DelayNotFractionalTest, - ::testing::Values(dsp::InterpolationType::None, dsp::InterpolationType::Linear, - dsp::InterpolationType::Allpass), + ::testing::Values(sfdsp::InterpolationType::None, sfdsp::InterpolationType::Linear, + sfdsp::InterpolationType::Allpass), ::testing::PrintToStringParamName()); \ No newline at end of file diff --git a/tests/rms_tests.cpp b/tests/rms_tests.cpp index 2d9c2d5..bda32ef 100644 --- a/tests/rms_tests.cpp +++ b/tests/rms_tests.cpp @@ -14,7 +14,7 @@ class RMSTest : public ::testing::TestWithParam TEST_P(RMSTest, PureSine) { - dsp::RMS rms(4096); + sfdsp::RMS rms(4096); const float kAmplitude = GetParam(); constexpr float kFreq = 440.f; diff --git a/tests/sinc_resampler_tests.cpp b/tests/sinc_resampler_tests.cpp index 783967d..6677fd0 100644 --- a/tests/sinc_resampler_tests.cpp +++ b/tests/sinc_resampler_tests.cpp @@ -16,7 +16,7 @@ TEST(SincInterpolateTest, NoOp) std::array output{0}; size_t out_size = output.max_size(); - dsp::sinc_resample(input.data(), array_size, 1, output.data(), out_size); + sfdsp::sinc_resample(input.data(), array_size, 1, output.data(), out_size); ASSERT_EQ(out_size, array_size); @@ -47,7 +47,7 @@ TEST(SincInterpolateTest, Upsample2X) std::array output{0}; size_t out_size = output.max_size(); - dsp::sinc_resample(input.data(), array_size, sample_ratio, output.data(), out_size); + sfdsp::sinc_resample(input.data(), array_size, sample_ratio, output.data(), out_size); for (auto& val : output) { @@ -67,5 +67,5 @@ TEST(SincInterpolateTest, Downsample2X) std::array output{0}; size_t out_size = output.max_size(); - dsp::sinc_resample(input.data(), array_size, sample_ratio, output.data(), out_size); + sfdsp::sinc_resample(input.data(), array_size, sample_ratio, output.data(), out_size); } \ No newline at end of file diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 86f1a07..6e30cd5 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -1,6 +1,6 @@ #include "test_utils.h" -void PrintWaveguide(dsp::Waveguide& wave, size_t delay_size) +void PrintWaveguide(sfdsp::Waveguide& wave, size_t delay_size) { std::vector right_samples, left_samples; for (size_t i = 1; i <= delay_size; ++i) @@ -24,16 +24,16 @@ void PrintWaveguide(dsp::Waveguide& wave, size_t delay_size) printf("\n"); } -void PrintDelayline(const dsp::Delayline& line) +void PrintDelayline(const sfdsp::Delayline& line) { for (auto i = 0; i < line.GetDelay(); ++i) { - printf("%5.1f ", line[i + 1]); + printf("%5.2f ", line[i + 1]); } printf("\n"); } -float GetWaveguideTotalEnergy(dsp::Waveguide& wave, size_t delay_size) +float GetWaveguideTotalEnergy(sfdsp::Waveguide& wave, size_t delay_size) { float total_energy = 0.f; for (size_t i = 1; i <= delay_size; ++i) diff --git a/tests/test_utils.h b/tests/test_utils.h index dda7db3..4e2cb47 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -4,8 +4,8 @@ #include "waveguide.h" -void PrintWaveguide(dsp::Waveguide& wave, size_t delay_size); +void PrintWaveguide(sfdsp::Waveguide& wave, size_t delay_size); -void PrintDelayline(const dsp::Delayline& line); +void PrintDelayline(const sfdsp::Delayline& line); -float GetWaveguideTotalEnergy(dsp::Waveguide& wave, size_t delay_size); \ No newline at end of file +float GetWaveguideTotalEnergy(sfdsp::Waveguide& wave, size_t delay_size); \ No newline at end of file diff --git a/tests/waveguide_gates_tests.cpp b/tests/waveguide_gates_tests.cpp index d9171db..65cc1bb 100644 --- a/tests/waveguide_gates_tests.cpp +++ b/tests/waveguide_gates_tests.cpp @@ -1,6 +1,9 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include + +#include "basic_oscillators.h" #include "delayline.h" #include "test_utils.h" #include "waveguide_gate.h" @@ -12,8 +15,8 @@ TEST(WaveguideGatesTest, OpenGates) constexpr float kGatePos = 5; constexpr float kCoeff = 0.0f; - dsp::Delayline right_traveling_line(kDelaySize, false, dsp::InterpolationType::Linear); - dsp::Delayline left_traveling_line(kDelaySize, true, dsp::InterpolationType::Linear); + sfdsp::Delayline right_traveling_line(kDelaySize, false, sfdsp::InterpolationType::Linear); + sfdsp::Delayline left_traveling_line(kDelaySize, true, sfdsp::InterpolationType::Linear); left_traveling_line.SetDelay(kDelay); right_traveling_line.SetDelay(kDelay); @@ -22,7 +25,7 @@ TEST(WaveguideGatesTest, OpenGates) left_traveling_line.TapIn(2, 1.f); right_traveling_line.TapIn(2, 1.f); - dsp::WaveguideGate gate(true, kGatePos, kCoeff); + sfdsp::WaveguideGate gate(true, kGatePos, kCoeff); // Looping for 2 * kDelay should bring us back to initial state for (auto i = 0; i < kDelay * 2; ++i) @@ -58,8 +61,8 @@ TEST(WaveguideGatesTest, HalfOpenGates) constexpr float kGatePos = 5; constexpr float kCoeff = 0.5f; - dsp::Delayline right_traveling_line(kDelaySize, false); - dsp::Delayline left_traveling_line(kDelaySize, true); + sfdsp::Delayline right_traveling_line(kDelaySize, false); + sfdsp::Delayline left_traveling_line(kDelaySize, true); left_traveling_line.SetDelay(kDelay); right_traveling_line.SetDelay(kDelay); @@ -71,7 +74,7 @@ TEST(WaveguideGatesTest, HalfOpenGates) PrintDelayline(right_traveling_line); PrintDelayline(left_traveling_line); - dsp::WaveguideGate gate(true, kGatePos, kCoeff); + sfdsp::WaveguideGate gate(true, kGatePos, kCoeff); // Looping for 2 * kDelay should bring us back to initial state for (auto i = 0; i < kDelay * 2; ++i) @@ -111,8 +114,8 @@ TEST(WaveguideGatesTest, ClosedGates) constexpr float kGatePos = 5; constexpr float kCoeff = 1.0f; - dsp::Delayline right_traveling_line(kDelaySize, false, dsp::InterpolationType::Linear); - dsp::Delayline left_traveling_line(kDelaySize, true, dsp::InterpolationType::Linear); + sfdsp::Delayline right_traveling_line(kDelaySize, false, sfdsp::InterpolationType::Linear); + sfdsp::Delayline left_traveling_line(kDelaySize, true, sfdsp::InterpolationType::Linear); right_traveling_line.SetDelay(kDelay); left_traveling_line.SetDelay(kDelay); @@ -127,7 +130,7 @@ TEST(WaveguideGatesTest, ClosedGates) PrintDelayline(right_traveling_line); PrintDelayline(left_traveling_line); - dsp::WaveguideGate gate(true, kGatePos, kCoeff); + sfdsp::WaveguideGate gate(true, kGatePos, kCoeff); // Looping for kDelay should bring us back to initial state for (auto i = 0; i < kDelay; ++i) @@ -167,8 +170,8 @@ TEST(WaveguideGatesTest, FractionalGates) constexpr float kGatePos = 4.5; constexpr float kCoeff = 1.0f; - dsp::Delayline right_traveling_line(kDelaySize, false, dsp::InterpolationType::Linear); - dsp::Delayline left_traveling_line(kDelaySize, true, dsp::InterpolationType::Linear); + sfdsp::Delayline right_traveling_line(kDelaySize, false, sfdsp::InterpolationType::Linear); + sfdsp::Delayline left_traveling_line(kDelaySize, true, sfdsp::InterpolationType::Linear); right_traveling_line.SetDelay(kDelay); left_traveling_line.SetDelay(kDelay); @@ -183,7 +186,7 @@ TEST(WaveguideGatesTest, FractionalGates) PrintDelayline(right_traveling_line); PrintDelayline(left_traveling_line); - dsp::WaveguideGate gate(true, kGatePos, kCoeff); + sfdsp::WaveguideGate gate(true, kGatePos, kCoeff); // Looping for kGatePos*2 should bring us back to initial state for (auto i = 0; i < kGatePos * 2; ++i) @@ -203,4 +206,202 @@ TEST(WaveguideGatesTest, FractionalGates) ASSERT_EQ(left_traveling_line[2], 1); ASSERT_EQ(right_traveling_line[2], 1); -} \ No newline at end of file +} + +TEST(WaveguideGatesTest, MovingGate) +{ + constexpr size_t kDelaySize = 11; + constexpr float kDelay = 10; + constexpr float kGatePos = 5; + constexpr float kCoeff = 1.0f; + + sfdsp::Delayline right_traveling_line(kDelaySize, false, sfdsp::InterpolationType::Linear); + sfdsp::Delayline left_traveling_line(kDelaySize, true, sfdsp::InterpolationType::Linear); + + right_traveling_line.SetDelay(kDelay); + left_traveling_line.SetDelay(kDelay); + + right_traveling_line.TapIn(1, 1); + left_traveling_line.TapIn(1, 1); + right_traveling_line.TapIn(2, 2); + left_traveling_line.TapIn(2, 2); + right_traveling_line.TapIn(3, 3); + left_traveling_line.TapIn(3, 3); + right_traveling_line.TapIn(4, 4); + left_traveling_line.TapIn(4, 4); + right_traveling_line.TapIn(5, 5); + left_traveling_line.TapIn(5, 5); + + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + + sfdsp::WaveguideGate gate(false, kGatePos, kCoeff); + for (auto i = 0; i < 2; ++i) + { + gate.Process(left_traveling_line, right_traveling_line); + + float left_sample = left_traveling_line.NextOut(); + float right_sample = right_traveling_line.NextOut(); + + left_traveling_line.Tick(right_sample); + right_traveling_line.Tick(left_sample); + + printf("Iteration %d\n", i); + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + } + + // Move the gate to the right + gate.SetDelay(kGatePos + 0.25f); + printf("\nMoving the delay\n"); + + for (auto i = 0; i < 1; ++i) + { + gate.Process(left_traveling_line, right_traveling_line); + + float left_sample = left_traveling_line.NextOut(); + float right_sample = right_traveling_line.NextOut(); + + left_traveling_line.Tick(right_sample); + right_traveling_line.Tick(left_sample); + + printf("Iteration %d\n", i); + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + } + + gate.SetDelay(kGatePos + 0.5f); + printf("\nMoving the delay\n"); + for (auto i = 0; i < 1; ++i) + { + gate.Process(left_traveling_line, right_traveling_line); + + float left_sample = left_traveling_line.NextOut(); + float right_sample = right_traveling_line.NextOut(); + + left_traveling_line.Tick(right_sample); + right_traveling_line.Tick(left_sample); + + printf("Iteration %d\n", i); + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + } + + gate.SetDelay(kGatePos + 0.75f); + printf("\nMoving the delay\n"); + for (auto i = 0; i < 1; ++i) + { + gate.Process(left_traveling_line, right_traveling_line); + + float left_sample = left_traveling_line.NextOut(); + float right_sample = right_traveling_line.NextOut(); + + left_traveling_line.Tick(right_sample); + right_traveling_line.Tick(left_sample); + + printf("Iteration %d\n", i); + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + } + + gate.SetDelay(kGatePos + 1.f); + printf("\nMoving the delay\n"); + for (auto i = 0; i < 10; ++i) + { + gate.Process(left_traveling_line, right_traveling_line); + + float left_sample = left_traveling_line.NextOut(); + float right_sample = right_traveling_line.NextOut(); + + left_traveling_line.Tick(right_sample); + right_traveling_line.Tick(left_sample); + + printf("Iteration %d\n", i); + PrintDelayline(right_traveling_line); + PrintDelayline(left_traveling_line); + } +} + +bool WriteWavFile(std::string filename, const float* buffer, SF_INFO sf_info, size_t frames) +{ + SNDFILE* out_file = sf_open(filename.c_str(), SFM_WRITE, &sf_info); + if (out_file == nullptr) + { + printf("Error: %s\n", sf_strerror(out_file)); + return false; + } + + sf_writef_float(out_file, buffer, static_cast(frames)); + sf_write_sync(out_file); // Is this needed? + sf_close(out_file); + return true; +} + +TEST(DISABLED_WaveguideGatesTest, SineWave) +{ + constexpr size_t kDelaySize = 21; + constexpr float kDelay = 20; + constexpr float kGatePos = 10; + constexpr float kCoeff = 1.0f; + constexpr size_t outSize = 600; + float gatePosDt = 0.1f; + constexpr size_t samplerate = 50000.f; + constexpr float kFreq = 1000; + + sfdsp::Delayline right_traveling_line(kDelaySize, false, sfdsp::InterpolationType::Linear); + sfdsp::Delayline left_traveling_line(kDelaySize, true, sfdsp::InterpolationType::Linear); + + right_traveling_line.SetDelay(kDelay); + left_traveling_line.SetDelay(kDelay); + + float phase = 0.f; + float phase_dt = kFreq / samplerate; + + sfdsp::WaveguideGate gate(true, kGatePos, kCoeff); + + std::array output; + + float currentGatePos = kGatePos; + for (auto i = 0; i < outSize; ++i) + { + if (currentGatePos >= 12.f) + { + gatePosDt *= -1; + } + else if (currentGatePos <= 8.f) + { + gatePosDt *= -1; + } + + currentGatePos += gatePosDt; + gate.SetDelay(currentGatePos); + + gate.Process(left_traveling_line, right_traveling_line); + + float x = sfdsp::Sine(phase); + phase += phase_dt; + + // This block tests the "left" side of the gate + // float right_sample = right_traveling_line.NextOut(); + // output[i] = left_traveling_line.NextOut(); + // right_traveling_line.Tick(x); + // left_traveling_line.Tick(right_sample); + + // Comment out the above block and uncomment the below block to test the "right" side of the gate + float left_sample = left_traveling_line.NextOut(); + right_traveling_line.Tick(left_sample); + left_traveling_line.Tick(x); + output[i] = right_traveling_line.NextOut(); + + // printf("Iteration %d, gatePos: %f\n", i, currentGatePos); + // PrintDelayline(right_traveling_line); + // PrintDelayline(left_traveling_line); + } + + SF_INFO info; + info.samplerate = static_cast(samplerate); + info.channels = 1; + info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; + + WriteWavFile("SineWaveTest.wav", output.data(), info, output.size()); +} diff --git a/tests/waveguide_tests.cpp b/tests/waveguide_tests.cpp index 90a2f5a..6600d3c 100644 --- a/tests/waveguide_tests.cpp +++ b/tests/waveguide_tests.cpp @@ -10,12 +10,12 @@ TEST(WaveguideTests, EmptyWaveguide) { // Check that energy is not magically introduce into the waveguide constexpr size_t WAVEGUIDE_SIZE = 128; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t LOOP_SIZE = WAVEGUIDE_SIZE * 10; - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); + sfdsp::Termination left_termination(-1.f); + sfdsp::Termination right_termination(-1.f); for (size_t i = 0; i < LOOP_SIZE; ++i) { @@ -31,15 +31,15 @@ TEST(WaveguideTests, Dirac) { // Check that energy is not magically introduce into the waveguide constexpr size_t WAVEGUIDE_SIZE = 10; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t LOOP_SIZE = 16; constexpr float DELAY_SIZE = 6.25; wave.SetDelay(DELAY_SIZE); wave.TapIn(3, 1); - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); + sfdsp::Termination left_termination(-1.f); + sfdsp::Termination right_termination(-1.f); PrintWaveguide(wave, DELAY_SIZE); @@ -56,10 +56,10 @@ TEST(WaveguideTests, Dirac) TEST(WaveguideTests, StabilityTestInteger) { constexpr size_t WAVEGUIDE_SIZE = 128; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); + sfdsp::Termination left_termination(-1.f); + sfdsp::Termination right_termination(-1.f); constexpr size_t LOOP_SIZE = WAVEGUIDE_SIZE * 100; constexpr size_t tap_in_pos = WAVEGUIDE_SIZE / 3; @@ -79,13 +79,13 @@ TEST(WaveguideTests, StabilityTestInteger) TEST(WaveguideTests, StabilityTestFrac) { constexpr size_t WAVEGUIDE_SIZE = 7; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t DELAY_SIZE = WAVEGUIDE_SIZE - 1; wave.SetDelay(DELAY_SIZE); - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); + sfdsp::Termination left_termination(-1.f); + sfdsp::Termination right_termination(-1.f); constexpr size_t LOOP_SIZE = DELAY_SIZE * 2; @@ -112,7 +112,7 @@ TEST(WaveguideTests, TapInTapOut) { // Check that energy is not magically introduce into the waveguide constexpr size_t WAVEGUIDE_SIZE = 128; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t DELAY_SIZE = WAVEGUIDE_SIZE - 1; wave.SetDelay(DELAY_SIZE); @@ -131,7 +131,7 @@ TEST(WaveguideTests, TapInTapOut) TEST(WaveguideTests, TapInTapOut2) { constexpr size_t WAVEGUIDE_SIZE = 7; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t DELAY_SIZE = WAVEGUIDE_SIZE - 1; wave.SetDelay(DELAY_SIZE); @@ -162,14 +162,14 @@ TEST(WaveguideTests, TapInTapOut2) TEST(WaveguideTests, GainTest) { constexpr size_t WAVEGUIDE_SIZE = 70; - dsp::Waveguide wave(WAVEGUIDE_SIZE); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE); constexpr size_t DELAY_SIZE = 6; wave.SetDelay(DELAY_SIZE); // Set the gain to -1 so we can check that no energy is lost. - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); + sfdsp::Termination left_termination(-1.f); + sfdsp::Termination right_termination(-1.f); constexpr float input[DELAY_SIZE] = {1, 2, 3, 4, 5, 6}; for (size_t i = 1; i <= DELAY_SIZE; ++i) @@ -228,57 +228,17 @@ TEST(WaveguideTests, GainTest) } } -TEST(WaveguideTests, JunctionTest) -{ - constexpr size_t WAVEGUIDE_SIZE = 9; - dsp::Waveguide wave(WAVEGUIDE_SIZE, dsp::InterpolationType::Linear); - - constexpr size_t DELAY_SIZE = 8; - wave.SetDelay(DELAY_SIZE); - - // Set the gain to -1 so we can check that no energy is lost. - dsp::Termination left_termination(-1.f); - dsp::Termination right_termination(-1.f); - - constexpr float input[DELAY_SIZE] = {0, 1, 0, 0, 0, 0, 0, 0}; - for (size_t i = 1; i < DELAY_SIZE; ++i) - { - wave.TapIn(i, input[i - 1]); - float out = wave.TapOut(i); - ASSERT_THAT(input[i - 1] * 2, ::testing::Eq(out)); - } - - // Waveguide should now look like this: - // ▶ 1 2 3 4 5 6 ▼ - // Left Right - // ▲ 1 2 3 4 5 6 ◀ - - PrintWaveguide(wave, DELAY_SIZE); - - wave.SetJunctionDelay(3.75f); - - for (size_t i = 0; i < DELAY_SIZE * 2; ++i) - { - float right, left; - wave.NextOut(right, left); - wave.Tick(left_termination.Tick(left), right_termination.Tick(right)); - printf("iter #%zu\n", i); - PrintWaveguide(wave, DELAY_SIZE); - printf("Next out: %f %f\n", left, right); - } -} - TEST(WaveguideTests, DISABLED_Pluck) { constexpr size_t WAVEGUIDE_SIZE = 501; - dsp::Waveguide wave(WAVEGUIDE_SIZE, dsp::InterpolationType::Allpass); + sfdsp::Waveguide wave(WAVEGUIDE_SIZE, sfdsp::InterpolationType::Allpass); constexpr size_t DELAY_SIZE = 500; wave.SetDelay(DELAY_SIZE); for (size_t i = 1; i <= DELAY_SIZE; ++i) { - wave.TapIn(i, dsp::Hann(i - 1, DELAY_SIZE)); + wave.TapIn(i, sfdsp::Hann(i - 1, DELAY_SIZE)); } PrintWaveguide(wave, DELAY_SIZE); diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 60c9f13..ac1eec5 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -16,7 +16,8 @@ add_executable(effect_player dsp_tester.cpp phaseshapers_tests.cpp stringensemble_tests.cpp - test_utils.cpp) + test_utils.cpp + waveguide_tests.cpp) target_link_libraries(effect_player PUBLIC dsp sndfile rtaudio) diff --git a/tools/bowedstring_tests.cpp b/tools/bowedstring_tests.cpp index bdef1be..dbb01b2 100644 --- a/tools/bowedstring_tests.cpp +++ b/tools/bowedstring_tests.cpp @@ -7,8 +7,8 @@ void SimpleBowedString::Init(size_t samplerate) samplerate_ = samplerate; string_.Init(static_cast(samplerate)); string_.SetFrequency(392.f); - string_.SetForce(0.01f); - string_.SetVelocity(0.5f); + string_.SetForce(0.5f); + string_.SetVelocity(1.f); string_.SetNoteOn(true); name_ = "bowedstring.wav"; @@ -35,10 +35,10 @@ void CrescendoBowedStringTester::Init(size_t samplerate) current_velocity_ = 0.f; current_force_ = 0.f; param_delta_ = 1.f / static_cast(midway_frame_); - param_value_ = dsp::Line(0.f, 1.f, midway_frame_); + param_value_ = sfdsp::Line(0.f, 1.f, midway_frame_); string_.Init(static_cast(samplerate)); - string_.SetFrequency(220.f); + string_.SetFrequency(440.f); string_.SetForce(0.f); string_.SetVelocity(0.f); string_.SetNoteOn(true); @@ -51,7 +51,7 @@ float CrescendoBowedStringTester::Tick() { if (current_frame_ == midway_frame_) { - param_value_ = dsp::Line(1.f, 0.f, midway_frame_); + param_value_ = sfdsp::Line(1.f, 0.f, midway_frame_); } current_velocity_ = param_value_.Tick(); @@ -83,7 +83,7 @@ void OscVelocityBowedStringTester::Init(size_t samplerate) float OscVelocityBowedStringTester::Tick() { - float param = (dsp::Sine(phase_) + 1) * 2.f; + float param = (sfdsp::Sine(phase_) + 1) * 2.f; param = std::clamp(param, 0.f, 1.f); phase_ += phase_dt_; if (phase_ >= 1.f) @@ -106,12 +106,12 @@ void PitchSlideBowedStringTester::Init(size_t samplerate) samplerate_ = samplerate; frame_count_ = samplerate * 4; - constexpr float kStartNote = 69; - constexpr float kEndNote = 76; - param_value_ = dsp::Line(kStartNote, kEndNote, samplerate / 2); + constexpr float kStartNote = 76; + constexpr float kEndNote = 69; + param_value_ = sfdsp::Line(kStartNote, kEndNote, samplerate / 2); string_.Init(static_cast(samplerate)); - string_.SetFrequency(dsp::FastMidiToFreq(kStartNote)); + string_.SetFrequency(sfdsp::FastMidiToFreq(kStartNote)); string_.SetForce(0.5f); string_.SetVelocity(0.5f); string_.SetNoteOn(true); @@ -126,7 +126,7 @@ float PitchSlideBowedStringTester::Tick() // Stay on the first note for one second before the glissando if (current_frame_ > samplerate_) { - string_.SetFrequency(dsp::FastMidiToFreq(param_value_.Tick())); + string_.SetFrequency(sfdsp::FastMidiToFreq(param_value_.Tick())); } ++current_frame_; @@ -157,12 +157,8 @@ void VibratoBowedStringTester::Init(size_t samplerate) // Velocity and Force will gradually increase over the first 3 seconds and then decrease until the end. float VibratoBowedStringTester::Tick() { - float freq = kFrequency + (dsp::Sine(phase_) * kVibratoDepth); + float freq = kFrequency + (sfdsp::Sine(phase_) * kVibratoDepth); phase_ += phase_dt_; - if (phase_ >= 1.f) - { - phase_ -= 1.f; - } string_.SetFrequency(freq); return string_.Tick(); @@ -187,7 +183,7 @@ void ScaleBowedStringTester::Init(size_t samplerate) arp_.SetNotes({60, 62, 64, 65, 67, 69, 71, 72, 71, 69, 67, 65, 64, 62}); string_.Init(static_cast(samplerate)); - string_.SetFrequency(dsp::midi_to_freq[static_cast(arp_.Next())]); + string_.SetFrequency(sfdsp::midi_to_freq[static_cast(arp_.Next())]); string_.SetForce(0.5f); string_.SetVelocity(0.5f); string_.SetNoteOn(true); @@ -198,7 +194,7 @@ void ScaleBowedStringTester::Init(size_t samplerate) // Velocity and Force will gradually increase over the first 3 seconds and then decrease until the end. float ScaleBowedStringTester::Tick() { - float vel_param = (dsp::Tri(vel_phase_) + 1) * 2.f; + float vel_param = (sfdsp::Tri(vel_phase_) + 1) * 2.f; vel_param = std::clamp(vel_param, 0.f, 1.f); vel_phase_ += vel_phase_dt_; if (vel_phase_ >= 1.f) @@ -208,7 +204,7 @@ float ScaleBowedStringTester::Tick() string_.SetVelocity(vel_param); - float vibrato = (dsp::Sine(vib_phase_) * kVibratoDepth); + float vibrato = (sfdsp::Sine(vib_phase_) * kVibratoDepth); vib_phase_ += vib_phase_dt_; if (vib_phase_ >= 1.f) { @@ -219,7 +215,7 @@ float ScaleBowedStringTester::Tick() if (current_frame_ >= frame_per_note_) { current_frame_ -= frame_per_note_; - float freq = dsp::FastMidiToFreq(arp_.Next()); + float freq = sfdsp::FastMidiToFreq(arp_.Next()); string_.SetFrequency(freq); } @@ -228,6 +224,49 @@ float ScaleBowedStringTester::Tick() } float ScaleBowedStringTester::Tick(float) +{ + return Tick(); +} + +void FingerPressBowedStringTester::Init(size_t samplerate) +{ + samplerate_ = samplerate; + frame_count_ = samplerate * 4; + string_.Init(static_cast(samplerate), 220.f); + string_.SetFrequency(440.f); + string_.SetForce(0.8f); + string_.SetVelocity(0.7f); + string_.SetNoteOn(true); + string_.SetFingerPressure(0.f); + + constexpr size_t press_time_ms = 10; + const size_t press_time_sample = press_time_ms * samplerate / 1000; + + pressure_ = sfdsp::Line(0.f, 0.2f, press_time_sample); + + name_ = "fingerpress.wav"; +} + +float FingerPressBowedStringTester::Tick() +{ + ++current_frame_; + + if (current_frame_ > samplerate_) + { + string_.SetFingerPressure(pressure_.Tick()); + } + + if (current_frame_ == samplerate_ * 2) + { + constexpr size_t depress_time = 1; + pressure_ = sfdsp::Line(0.2f, 0.f, depress_time); + string_.SetBowPosition(0.30f); + } + + return string_.Tick(); +} + +float FingerPressBowedStringTester::Tick(float) { return Tick(); } \ No newline at end of file diff --git a/tools/bowedstring_tests.h b/tools/bowedstring_tests.h index b72eba3..07bc287 100644 --- a/tools/bowedstring_tests.h +++ b/tools/bowedstring_tests.h @@ -14,7 +14,7 @@ class SimpleBowedString : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; + sfdsp::BowedString string_; }; class CrescendoBowedStringTester : public DspTester @@ -28,7 +28,7 @@ class CrescendoBowedStringTester : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; + sfdsp::BowedString string_; size_t midway_frame_ = 0; size_t current_frame_ = 0; @@ -36,7 +36,7 @@ class CrescendoBowedStringTester : public DspTester float current_velocity_ = 0.f; float current_force_ = 0.f; float param_delta_ = 0.f; - dsp::Line param_value_; + sfdsp::Line param_value_; }; class PitchSlideBowedStringTester : public DspTester @@ -50,8 +50,8 @@ class PitchSlideBowedStringTester : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; - dsp::Line param_value_; + sfdsp::BowedString string_; + sfdsp::Line param_value_; size_t current_frame_; }; @@ -66,7 +66,7 @@ class OscVelocityBowedStringTester : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; + sfdsp::BowedString string_; const float kFrequency = 7.f; float phase_dt_ = 0.f; float phase_ = 0.f; @@ -83,10 +83,10 @@ class VibratoBowedStringTester : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; - const float kFrequency = 440.f; - const float kVibratoFrequency = 5.f; - const float kVibratoDepth = 0.7f; + sfdsp::BowedString string_; + const float kFrequency = 400.f; + const float kVibratoFrequency = 4.f; + const float kVibratoDepth = 40.f; float phase_dt_ = 0.f; float phase_ = 0.f; }; @@ -102,7 +102,7 @@ class ScaleBowedStringTester : public DspTester float Tick(float input) override; private: - dsp::BowedString string_; + sfdsp::BowedString string_; const float kVelSpeed = 7.f; float vel_phase_dt_ = 0.f; float vel_phase_ = 0.f; @@ -115,4 +115,21 @@ class ScaleBowedStringTester : public DspTester const float kVibratoDepth = 1.2f; float vib_phase_dt_ = 0.f; float vib_phase_ = 0.f; +}; + +class FingerPressBowedStringTester : public DspTester +{ + public: + FingerPressBowedStringTester() = default; + ~FingerPressBowedStringTester() override = default; + + void Init(size_t samplerate) override; + float Tick() override; + float Tick(float input) override; + + private: + sfdsp::BowedString string_; + sfdsp::Line pressure_; + + size_t current_frame_ = 0; }; \ No newline at end of file diff --git a/tools/dsp_tester.h b/tools/dsp_tester.h index 9df718b..bcbce81 100644 --- a/tools/dsp_tester.h +++ b/tools/dsp_tester.h @@ -59,5 +59,5 @@ class ChorusTester : public DspTester float Tick(float input) override; private: - dsp::Chorus chorus_; + sfdsp::Chorus chorus_; }; diff --git a/tools/effect_player.cpp b/tools/effect_player.cpp index 5b34e07..230fade 100644 --- a/tools/effect_player.cpp +++ b/tools/effect_player.cpp @@ -85,7 +85,7 @@ int main(int argc, char** argv) } } - uint32_t samplerate = 48000; + uint32_t samplerate = 44100; uint32_t frame_count = 0; if (!input_file.empty()) @@ -139,7 +139,6 @@ int RtOutputCallback(void* outputBuffer, void* /*inputBuffer*/, unsigned int nBu size_t frameToRead = std::min(static_cast(nBufferFrames), context->numFrames - context->readPtr); auto* output = static_cast(outputBuffer); - // Write interleaved audio data. for (size_t i = 0; i < frameToRead; i++) { diff --git a/tools/phaseshapers_tests.cpp b/tools/phaseshapers_tests.cpp index d9c933a..9f9fe3f 100644 --- a/tools/phaseshapers_tests.cpp +++ b/tools/phaseshapers_tests.cpp @@ -10,7 +10,7 @@ void PhaseShaperTest::Init(size_t samplerate) frame_per_wave_ = (samplerate / 220) * 8; // 4 periods per waveform - frame_count_ = frame_per_wave_ * static_cast(dsp::Phaseshaper::Waveform::NUM_WAVES); + frame_count_ = frame_per_wave_ * static_cast(sfdsp::Phaseshaper::Waveform::NUM_WAVES); name_ = "phaseshaper.wav"; } diff --git a/tools/phaseshapers_tests.h b/tools/phaseshapers_tests.h index 77008cc..b6d7683 100644 --- a/tools/phaseshapers_tests.h +++ b/tools/phaseshapers_tests.h @@ -16,8 +16,8 @@ class PhaseShaperTest : public DspTester float Tick(float input) override; private: - dsp::Phaseshaper phaseshaper_; + sfdsp::Phaseshaper phaseshaper_; size_t current_frame_ = 0; size_t frame_per_wave_ = 0; - float current_waveform_ = static_cast(dsp::Phaseshaper::Waveform::VARIABLE_SLOPE); + float current_waveform_ = static_cast(sfdsp::Phaseshaper::Waveform::VARIABLE_SLOPE); }; \ No newline at end of file diff --git a/tools/player/player.cpp b/tools/player/player.cpp index 2ec5879..a36d39c 100644 --- a/tools/player/player.cpp +++ b/tools/player/player.cpp @@ -20,8 +20,8 @@ size_t g_period_microseconds = DEFAULT_BUFFER_FRAMES * 1000000 / DEFAULT_SAMPLE_ std::atomic_bool g_exit = false; std::unique_ptr g_gamepad; -std::unique_ptr g_bowed_string; -std::unique_ptr g_bow_table; +std::unique_ptr g_bowed_string; +std::unique_ptr g_bow_table; MidiController g_midi_controller; bool g_save_wav = false; @@ -90,7 +90,7 @@ int main(int argc, char** argv) } g_gamepad = std::make_unique(); - g_bowed_string = std::make_unique(); + g_bowed_string = std::make_unique(); g_bowed_string->Init(DEFAULT_SAMPLE_RATE); AudioContext audio_context; @@ -157,7 +157,7 @@ int RtOutputCallback(void* outputBuffer, void* /*inputBuffer*/, unsigned int nBu MidiMessage message; bool more_messages = true; size_t midi_poll = 0; - dsp::Line pitch_bend(0.f, 1.f, 1.f); + sfdsp::Line pitch_bend(0.f, 1.f, 1.f); while (more_messages && midi_poll < MAX_MIDI_POLL) { @@ -174,7 +174,7 @@ int RtOutputCallback(void* outputBuffer, void* /*inputBuffer*/, unsigned int nBu case MidiType::NoteOn: { audio_context->current_playing_midi_note = message.byte1; - g_bowed_string->SetFrequency(dsp::midi_to_freq[message.byte1]); + g_bowed_string->SetFrequency(sfdsp::midi_to_freq[message.byte1]); audio_context->note_on = true; float velocity = static_cast(message.byte2) / 127.f; @@ -212,9 +212,9 @@ int RtOutputCallback(void* outputBuffer, void* /*inputBuffer*/, unsigned int nBu float normalized_value = (pitchbend_value - 8192.f) / 8192.f * PITCHBEND_RANGE; float new_midi_pitch = static_cast(audio_context->current_playing_midi_note) + normalized_value; - float new_freq = dsp::MidiToFreq(new_midi_pitch); + float new_freq = sfdsp::MidiToFreq(new_midi_pitch); float old_freq = g_bowed_string->GetFrequency(); - pitch_bend = dsp::Line(old_freq, new_freq, nBufferFrames); + pitch_bend = sfdsp::Line(old_freq, new_freq, nBufferFrames); audio_context->do_pitch_bend = true; break; } diff --git a/tools/resampler.cpp b/tools/resampler.cpp index ddad121..30df09a 100644 --- a/tools/resampler.cpp +++ b/tools/resampler.cpp @@ -97,7 +97,7 @@ int main(int argc, char** argv) void UseSincResample(const float* buffer, size_t input_size, float resampling_ratio, float* out, size_t& out_size) { - dsp::sinc_resample(buffer, input_size, resampling_ratio, out, out_size); + sfdsp::sinc_resample(buffer, input_size, resampling_ratio, out, out_size); } void UseLibSamplerate(const float* buffer, size_t input_size, double resampling_ratio, float* out, size_t& out_size) diff --git a/tools/stringensemble_tests.cpp b/tools/stringensemble_tests.cpp index 5d50de9..920443b 100644 --- a/tools/stringensemble_tests.cpp +++ b/tools/stringensemble_tests.cpp @@ -2,7 +2,7 @@ void StringEnsembleTest::Init(size_t samplerate) { - ensemble_.Init(static_cast(samplerate), dsp::kDefaultFrequencies); + ensemble_.Init(static_cast(samplerate), sfdsp::kDefaultFrequencies); ensemble_.SetForce(2, 0.05f); ensemble_.SetVelocity(2, 0.5f); diff --git a/tools/stringensemble_tests.h b/tools/stringensemble_tests.h index ec028fb..4fc1eed 100644 --- a/tools/stringensemble_tests.h +++ b/tools/stringensemble_tests.h @@ -15,5 +15,5 @@ class StringEnsembleTest : public DspTester float Tick(float input) override; private: - dsp::StringEnsemble ensemble_; + sfdsp::StringEnsemble ensemble_; }; \ No newline at end of file diff --git a/tools/test_utils.cpp b/tools/test_utils.cpp index 725ca9a..5a2fb9c 100644 --- a/tools/test_utils.cpp +++ b/tools/test_utils.cpp @@ -2,14 +2,6 @@ #include -#ifdef DSP_USE_DOUBLE -#define sf_readf_dspfloat sf_readf_double -#define sf_writef_dspfloat sf_writef_double -#else -#define sf_readf_dspfloat sf_readf_float -#define sf_writef_dspfloat sf_writef_float -#endif - bool LoadWavFile(const std::string& filename, std::unique_ptr& buffer, size_t& buffer_size, SF_INFO& sf_info) { SNDFILE* file = sf_open(filename.c_str(), SFM_READ, &sf_info); @@ -22,7 +14,7 @@ bool LoadWavFile(const std::string& filename, std::unique_ptr& buffer, buffer = std::make_unique(sf_info.frames); - sf_count_t count = sf_readf_dspfloat(file, buffer.get(), sf_info.frames); + sf_count_t count = sf_readf_float(file, buffer.get(), sf_info.frames); assert(count == sf_info.frames); buffer_size = count; @@ -40,7 +32,7 @@ bool WriteWavFile(std::string filename, const float* buffer, SF_INFO sf_info, si return false; } - sf_writef_dspfloat(out_file, buffer, static_cast(frames)); + sf_writef_float(out_file, buffer, static_cast(frames)); sf_write_sync(out_file); // Is this needed? sf_close(out_file); return true; diff --git a/tools/tests_list.h b/tools/tests_list.h index 953733f..617d2f3 100644 --- a/tools/tests_list.h +++ b/tools/tests_list.h @@ -6,6 +6,7 @@ #include "dsp_tester.h" #include "phaseshapers_tests.h" #include "stringensemble_tests.h" +#include "waveguide_tests.h" #define FOREACH_TESTS(TEST) \ TEST(ChorusTester) \ @@ -16,7 +17,9 @@ TEST(VibratoBowedStringTester) \ TEST(ScaleBowedStringTester) \ TEST(PhaseShaperTest) \ - TEST(StringEnsembleTest) + TEST(StringEnsembleTest) \ + TEST(WaveguideTest) \ + TEST(FingerPressBowedStringTester) #define GENERATE_ENUM(ENUM) ENUM, #define GENERATE_STRING(STRING) #STRING, diff --git a/tools/violonist/violonist.cpp b/tools/violonist/violonist.cpp index 6c22f21..8486efe 100644 --- a/tools/violonist/violonist.cpp +++ b/tools/violonist/violonist.cpp @@ -47,7 +47,7 @@ int main(int argc, char** argv) bool Run(TestConfig config) { - dsp::BowedString string; + sfdsp::BowedString string; string.Init(static_cast(kSampleRate)); string.SetFrequency(config.frequency); diff --git a/tools/waveguide_tests.cpp b/tools/waveguide_tests.cpp new file mode 100644 index 0000000..dd7e9ce --- /dev/null +++ b/tools/waveguide_tests.cpp @@ -0,0 +1,47 @@ +#include "waveguide_tests.h" + +#include + +WaveguideTest::WaveguideTest() : waveguide_(21), gate_(false, 0.f, 1.f) +{ +} + +void WaveguideTest::Init(size_t samplerate) +{ + samplerate_ = samplerate; + waveguide_.SetDelay(20); + + gate_pos_ = 10.f; + gate_.SetDelay(gate_pos_); + gate_dt_ = 0.001f; + + constexpr float freq = 220.f; + phase_dt_ = freq / static_cast(samplerate); + + name_ = "waveguidetest.wav"; +} + +float WaveguideTest::Tick() +{ + float right; + float left; + waveguide_.NextOut(right, left); + + float x = sfdsp::Sine(phase_); + phase_ += phase_dt_; + + waveguide_.Tick(x, right * -1); + + if (gate_pos_ < 17.f) + { + gate_pos_ += gate_dt_; + gate_.SetDelay(gate_pos_); + } + + return left; +} + +float WaveguideTest::Tick(float input) +{ + return Tick(); +} \ No newline at end of file diff --git a/tools/waveguide_tests.h b/tools/waveguide_tests.h new file mode 100644 index 0000000..79ea0eb --- /dev/null +++ b/tools/waveguide_tests.h @@ -0,0 +1,25 @@ +#pragma once + +#include "dsp_tester.h" +#include "waveguide.h" +#include "waveguide_gate.h" + +class WaveguideTest : public DspTester +{ + public: + WaveguideTest(); + ~WaveguideTest() override = default; + + void Init(size_t samplerate) override; + float Tick() override; + float Tick(float input) override; + + private: + sfdsp::Waveguide waveguide_; + sfdsp::WaveguideGate gate_; + float gate_pos_ = 5.f; + float gate_dt_ = 0.f; + + float phase_dt_ = 0.f; + float phase_ = 0.f; +}; \ No newline at end of file