From ffac04090c10e9be1075bcbe1935428995f293eb Mon Sep 17 00:00:00 2001 From: monkey-w1n5t0n Date: Tue, 21 Jul 2026 12:49:25 +0200 Subject: [PATCH] refactor(firmware): delete vendored daisysp and the input_router layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 group 8 (S8, ST2, L14). - S8: the vendored src/daisysp tree (96 files, 41 .cpp compiled into every firmware build) and its sketch-tree symlink. Zero consumers — nisps replaced daisysp's PitchShifter with a custom granular implementation. Corrected firmware/README.md and setup-firmware-toolchain.sh, which called it a live submodule. The attribution comment in nisps/dsp/pitch_shift.hpp stays: it is an honest provenance note about a port, not a dependency. Noted while verifying: src/memllib/examples/KassiaAudioApp includes ../../daisysp/..., but examples/ is not symlinked into the sketch tree and is never compiled by the firmware build, so the deletion stands. - ST2: input_router.hpp was a zero-logic speculative layer with one consumer; the .ino now calls bind_peripherals directly. - L14: peripherals.hpp — deleted kAnalogInputCount, PeripheralBindings and the unused spread local, and extracted the duplicated commit-and-train block into one helper. The audit's suggested commit_and_train(mode, feedback) signature could NOT be behaviour-identical: repositioning() implies placing() (both live in ExploreState::Placing), so dispatching on feedback state inside the helper would silently reroute a TogB2 press mid-reposition from commit_place to commit_reposition, which differs (no snapshot restore, clears reposition_). Implemented as commit_and_train(mode, feedback, bool reposition) with the branch decided at the call site, preserving behaviour. Firmware is not compiled by any gate yet (that arrives with the PlatformIO migration, plan §5/S9), so this group is verified by reading and grep only. Gates: run-all-tests.sh ALL GREEN. --- firmware/MEMLNaut-NISPS/MEMLNaut-NISPS.ino | 6 +- firmware/MEMLNaut-NISPS/glue/input_router.hpp | 23 -- firmware/MEMLNaut-NISPS/glue/peripherals.hpp | 69 ++-- firmware/MEMLNaut-NISPS/src/daisysp | 1 - firmware/README.md | 3 +- scripts/setup-firmware-toolchain.sh | 4 +- src/daisysp/Control/adenv.cpp | 167 --------- src/daisysp/Control/adenv.h | 100 ----- src/daisysp/Control/adsr.cpp | 136 ------- src/daisysp/Control/adsr.h | 106 ------ src/daisysp/Control/phasor.cpp | 27 -- src/daisysp/Control/phasor.h | 71 ---- src/daisysp/Drums/analogbassdrum.cpp | 192 ---------- src/daisysp/Drums/analogbassdrum.h | 113 ------ src/daisysp/Drums/analogsnaredrum.cpp | 219 ----------- src/daisysp/Drums/analogsnaredrum.h | 106 ------ src/daisysp/Drums/hihat.cpp | 96 ----- src/daisysp/Drums/hihat.h | 277 -------------- src/daisysp/Drums/synthbassdrum.cpp | 231 ------------ src/daisysp/Drums/synthbassdrum.h | 187 ---------- src/daisysp/Drums/synthsnaredrum.cpp | 201 ---------- src/daisysp/Drums/synthsnaredrum.h | 105 ------ src/daisysp/Dynamics/crossfade.cpp | 37 -- src/daisysp/Dynamics/crossfade.h | 86 ----- src/daisysp/Dynamics/limiter.cpp | 29 -- src/daisysp/Dynamics/limiter.h | 41 -- src/daisysp/Effects/autowah.cpp | 65 ---- src/daisysp/Effects/autowah.h | 60 --- src/daisysp/Effects/chorus.cpp | 187 ---------- src/daisysp/Effects/chorus.h | 190 ---------- src/daisysp/Effects/decimator.cpp | 46 --- src/daisysp/Effects/decimator.h | 94 ----- src/daisysp/Effects/flanger.cpp | 83 ----- src/daisysp/Effects/flanger.h | 83 ----- src/daisysp/Effects/overdrive.cpp | 32 -- src/daisysp/Effects/overdrive.h | 54 --- src/daisysp/Effects/phaser.cpp | 138 ------- src/daisysp/Effects/phaser.h | 139 ------- src/daisysp/Effects/pitchshifter.h | 225 ----------- src/daisysp/Effects/sampleratereducer.cpp | 43 --- src/daisysp/Effects/sampleratereducer.h | 56 --- src/daisysp/Effects/tremolo.cpp | 36 -- src/daisysp/Effects/tremolo.h | 68 ---- src/daisysp/Effects/wavefolder.cpp | 20 - src/daisysp/Effects/wavefolder.h | 53 --- src/daisysp/Filters/fir.h | 351 ----------------- src/daisysp/Filters/ladder.cpp | 180 --------- src/daisysp/Filters/ladder.h | 144 ------- src/daisysp/Filters/onepole.h | 110 ------ src/daisysp/Filters/soap.cpp | 65 ---- src/daisysp/Filters/soap.h | 70 ---- src/daisysp/Filters/svf.cpp | 86 ----- src/daisysp/Filters/svf.h | 87 ----- src/daisysp/Noise/clockednoise.cpp | 59 --- src/daisysp/Noise/clockednoise.h | 66 ---- src/daisysp/Noise/dust.h | 62 --- src/daisysp/Noise/fractal_noise.h | 90 ----- src/daisysp/Noise/grainlet.cpp | 146 -------- src/daisysp/Noise/grainlet.h | 92 ----- src/daisysp/Noise/particle.cpp | 95 ----- src/daisysp/Noise/particle.h | 92 ----- src/daisysp/Noise/whitenoise.h | 54 --- .../PhysicalModeling/KarplusString.cpp | 197 ---------- src/daisysp/PhysicalModeling/KarplusString.h | 110 ------ src/daisysp/PhysicalModeling/drip.cpp | 213 ----------- src/daisysp/PhysicalModeling/drip.h | 61 --- src/daisysp/PhysicalModeling/modalvoice.cpp | 109 ------ src/daisysp/PhysicalModeling/modalvoice.h | 99 ----- src/daisysp/PhysicalModeling/resonator.cpp | 158 -------- src/daisysp/PhysicalModeling/resonator.h | 191 ---------- src/daisysp/PhysicalModeling/stringvoice.cpp | 124 ------ src/daisysp/PhysicalModeling/stringvoice.h | 102 ----- src/daisysp/Sampling/granularplayer.cpp | 79 ---- src/daisysp/Sampling/granularplayer.h | 96 ----- src/daisysp/Synthesis/fm2.cpp | 65 ---- src/daisysp/Synthesis/fm2.h | 73 ---- src/daisysp/Synthesis/formantosc.cpp | 96 ----- src/daisysp/Synthesis/formantosc.h | 81 ---- src/daisysp/Synthesis/harmonic_osc.h | 174 --------- src/daisysp/Synthesis/oscillator.cpp | 83 ----- src/daisysp/Synthesis/oscillator.h | 125 ------- src/daisysp/Synthesis/oscillatorbank.cpp | 147 -------- src/daisysp/Synthesis/oscillatorbank.h | 88 ----- src/daisysp/Synthesis/variablesawosc.cpp | 106 ------ src/daisysp/Synthesis/variablesawosc.h | 80 ---- src/daisysp/Synthesis/variableshapeosc.cpp | 182 --------- src/daisysp/Synthesis/variableshapeosc.h | 95 ----- src/daisysp/Synthesis/vosim.cpp | 81 ---- src/daisysp/Synthesis/vosim.h | 82 ---- src/daisysp/Synthesis/zoscillator.cpp | 159 -------- src/daisysp/Synthesis/zoscillator.h | 84 ----- src/daisysp/Utility/dcblock.cpp | 20 - src/daisysp/Utility/dcblock.h | 37 -- src/daisysp/Utility/delayline.h | 129 ------- src/daisysp/Utility/dsp.h | 352 ------------------ src/daisysp/Utility/looper.h | 299 --------------- src/daisysp/Utility/maytrig.h | 44 --- src/daisysp/Utility/metro.cpp | 30 -- src/daisysp/Utility/metro.h | 54 --- src/daisysp/Utility/samplehold.h | 69 ---- src/daisysp/Utility/smooth_random.h | 85 ----- src/daisysp/daisysp.h | 97 ----- 102 files changed, 36 insertions(+), 10674 deletions(-) delete mode 100644 firmware/MEMLNaut-NISPS/glue/input_router.hpp delete mode 120000 firmware/MEMLNaut-NISPS/src/daisysp delete mode 100644 src/daisysp/Control/adenv.cpp delete mode 100644 src/daisysp/Control/adenv.h delete mode 100644 src/daisysp/Control/adsr.cpp delete mode 100644 src/daisysp/Control/adsr.h delete mode 100644 src/daisysp/Control/phasor.cpp delete mode 100644 src/daisysp/Control/phasor.h delete mode 100644 src/daisysp/Drums/analogbassdrum.cpp delete mode 100644 src/daisysp/Drums/analogbassdrum.h delete mode 100644 src/daisysp/Drums/analogsnaredrum.cpp delete mode 100644 src/daisysp/Drums/analogsnaredrum.h delete mode 100644 src/daisysp/Drums/hihat.cpp delete mode 100644 src/daisysp/Drums/hihat.h delete mode 100644 src/daisysp/Drums/synthbassdrum.cpp delete mode 100644 src/daisysp/Drums/synthbassdrum.h delete mode 100644 src/daisysp/Drums/synthsnaredrum.cpp delete mode 100644 src/daisysp/Drums/synthsnaredrum.h delete mode 100644 src/daisysp/Dynamics/crossfade.cpp delete mode 100644 src/daisysp/Dynamics/crossfade.h delete mode 100644 src/daisysp/Dynamics/limiter.cpp delete mode 100644 src/daisysp/Dynamics/limiter.h delete mode 100644 src/daisysp/Effects/autowah.cpp delete mode 100644 src/daisysp/Effects/autowah.h delete mode 100644 src/daisysp/Effects/chorus.cpp delete mode 100644 src/daisysp/Effects/chorus.h delete mode 100644 src/daisysp/Effects/decimator.cpp delete mode 100644 src/daisysp/Effects/decimator.h delete mode 100644 src/daisysp/Effects/flanger.cpp delete mode 100644 src/daisysp/Effects/flanger.h delete mode 100644 src/daisysp/Effects/overdrive.cpp delete mode 100644 src/daisysp/Effects/overdrive.h delete mode 100644 src/daisysp/Effects/phaser.cpp delete mode 100644 src/daisysp/Effects/phaser.h delete mode 100644 src/daisysp/Effects/pitchshifter.h delete mode 100644 src/daisysp/Effects/sampleratereducer.cpp delete mode 100644 src/daisysp/Effects/sampleratereducer.h delete mode 100644 src/daisysp/Effects/tremolo.cpp delete mode 100644 src/daisysp/Effects/tremolo.h delete mode 100644 src/daisysp/Effects/wavefolder.cpp delete mode 100644 src/daisysp/Effects/wavefolder.h delete mode 100644 src/daisysp/Filters/fir.h delete mode 100644 src/daisysp/Filters/ladder.cpp delete mode 100644 src/daisysp/Filters/ladder.h delete mode 100644 src/daisysp/Filters/onepole.h delete mode 100644 src/daisysp/Filters/soap.cpp delete mode 100644 src/daisysp/Filters/soap.h delete mode 100644 src/daisysp/Filters/svf.cpp delete mode 100644 src/daisysp/Filters/svf.h delete mode 100644 src/daisysp/Noise/clockednoise.cpp delete mode 100644 src/daisysp/Noise/clockednoise.h delete mode 100644 src/daisysp/Noise/dust.h delete mode 100644 src/daisysp/Noise/fractal_noise.h delete mode 100644 src/daisysp/Noise/grainlet.cpp delete mode 100644 src/daisysp/Noise/grainlet.h delete mode 100644 src/daisysp/Noise/particle.cpp delete mode 100644 src/daisysp/Noise/particle.h delete mode 100644 src/daisysp/Noise/whitenoise.h delete mode 100644 src/daisysp/PhysicalModeling/KarplusString.cpp delete mode 100644 src/daisysp/PhysicalModeling/KarplusString.h delete mode 100644 src/daisysp/PhysicalModeling/drip.cpp delete mode 100644 src/daisysp/PhysicalModeling/drip.h delete mode 100644 src/daisysp/PhysicalModeling/modalvoice.cpp delete mode 100644 src/daisysp/PhysicalModeling/modalvoice.h delete mode 100644 src/daisysp/PhysicalModeling/resonator.cpp delete mode 100644 src/daisysp/PhysicalModeling/resonator.h delete mode 100644 src/daisysp/PhysicalModeling/stringvoice.cpp delete mode 100644 src/daisysp/PhysicalModeling/stringvoice.h delete mode 100644 src/daisysp/Sampling/granularplayer.cpp delete mode 100644 src/daisysp/Sampling/granularplayer.h delete mode 100644 src/daisysp/Synthesis/fm2.cpp delete mode 100644 src/daisysp/Synthesis/fm2.h delete mode 100644 src/daisysp/Synthesis/formantosc.cpp delete mode 100644 src/daisysp/Synthesis/formantosc.h delete mode 100644 src/daisysp/Synthesis/harmonic_osc.h delete mode 100644 src/daisysp/Synthesis/oscillator.cpp delete mode 100644 src/daisysp/Synthesis/oscillator.h delete mode 100644 src/daisysp/Synthesis/oscillatorbank.cpp delete mode 100644 src/daisysp/Synthesis/oscillatorbank.h delete mode 100644 src/daisysp/Synthesis/variablesawosc.cpp delete mode 100644 src/daisysp/Synthesis/variablesawosc.h delete mode 100644 src/daisysp/Synthesis/variableshapeosc.cpp delete mode 100644 src/daisysp/Synthesis/variableshapeosc.h delete mode 100644 src/daisysp/Synthesis/vosim.cpp delete mode 100644 src/daisysp/Synthesis/vosim.h delete mode 100644 src/daisysp/Synthesis/zoscillator.cpp delete mode 100644 src/daisysp/Synthesis/zoscillator.h delete mode 100644 src/daisysp/Utility/dcblock.cpp delete mode 100644 src/daisysp/Utility/dcblock.h delete mode 100644 src/daisysp/Utility/delayline.h delete mode 100644 src/daisysp/Utility/dsp.h delete mode 100644 src/daisysp/Utility/looper.h delete mode 100644 src/daisysp/Utility/maytrig.h delete mode 100644 src/daisysp/Utility/metro.cpp delete mode 100644 src/daisysp/Utility/metro.h delete mode 100644 src/daisysp/Utility/samplehold.h delete mode 100644 src/daisysp/Utility/smooth_random.h delete mode 100644 src/daisysp/daisysp.h diff --git a/firmware/MEMLNaut-NISPS/MEMLNaut-NISPS.ino b/firmware/MEMLNaut-NISPS/MEMLNaut-NISPS.ino index 9b5a548..042f444 100644 --- a/firmware/MEMLNaut-NISPS/MEMLNaut-NISPS.ino +++ b/firmware/MEMLNaut-NISPS/MEMLNaut-NISPS.ino @@ -3,7 +3,7 @@ // The heavy lifting now lives under: // - nisps/... — platform-agnostic ML, DSP, engines, modes // - firmware/glue/... — hardware bindings (audio driver, MIDI, -// peripherals, input/output routers) +// peripherals, output router) // // This file does only: // 1. Pick a mode at compile time (`MEMLNAUT_MODE_TYPE`). @@ -27,10 +27,10 @@ // ---- Glue ---- #include "glue/audio_driver.hpp" -#include "glue/input_router.hpp" #include "glue/midi_io.hpp" #include "glue/mode_select.hpp" #include "glue/output_router.hpp" +#include "glue/peripherals.hpp" #include "glue/settings_view.hpp" // ---- Mode selection ---- @@ -131,7 +131,7 @@ void setup() { pinMode(33, OUTPUT); // Wire hardware → mode I/O channels. - nisps_firmware::wire_inputs(g_mode); + nisps_firmware::bind_peripherals(g_mode); WRITE_VOLATILE(g_iface_ready, true); Serial.println("Bound peripherals to mode."); diff --git a/firmware/MEMLNaut-NISPS/glue/input_router.hpp b/firmware/MEMLNaut-NISPS/glue/input_router.hpp deleted file mode 100644 index dccdc38..0000000 --- a/firmware/MEMLNaut-NISPS/glue/input_router.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// firmware/glue/input_router.hpp — High-level input wiring entry point. -// -// Currently a thin re-export over `peripherals.hpp`. The intent is for this -// to grow into a schema-aware router (read mode.param_schema().input_channels -// names, look up matching hardware sources by name, attach callbacks). For -// now the trivial positional mapping in `bind_peripherals()` is sufficient -// since every existing mode's first N channels are joystick X/Y/Z(/W). -// -// Kept as its own header so growth of routing logic doesn't bloat -// peripherals.hpp. - -#pragma once - -#include "peripherals.hpp" - -namespace nisps_firmware { - -template -inline void wire_inputs(Mode& mode) { - bind_peripherals(mode); -} - -} // namespace nisps_firmware diff --git a/firmware/MEMLNaut-NISPS/glue/peripherals.hpp b/firmware/MEMLNaut-NISPS/glue/peripherals.hpp index 1dabe82..739814f 100644 --- a/firmware/MEMLNaut-NISPS/glue/peripherals.hpp +++ b/firmware/MEMLNaut-NISPS/glue/peripherals.hpp @@ -61,16 +61,34 @@ inline constexpr std::uint64_t kFeedbackSalt = 0xFEEDBACC0DEull; // D=4, firmware D=2 — SRAM budget). inline constexpr std::size_t kFirmwareUndoDepth = 2u; -// Number of analog input channels we forward to the mode. Modes with fewer -// inputs ignore the surplus (set_input(idx, ...) silently rejects out-of- -// range idx in ModeBase). -inline constexpr std::size_t kAnalogInputCount = 4u; // X, Y, Z, plus one pot - -// A small POD that the .ino owns. Captured by lambda below. -template -struct PeripheralBindings { - Mode* mode = nullptr; -}; +// Shared commit path for the two "commit the held output at the CURRENT +// joystick input" gestures (MomB2 drop-reposition, TogB2 commit-place). +// Captures the joystick input BEFORE the commit (commit_place restores the +// real net), runs the caller-named commit, then stores the +1 example +// (input → committed output) and warm-start trains — the CALLER owns +// training. The commit is picked by the call site, not by feedback state: +// dispatching on repositioning() here would change what TogB2 does when +// pressed mid-reposition (today it takes the commit_place path). +template +inline void commit_and_train(Mode& mode, FB& feedback, bool reposition) { + // Capture the current joystick input — the DESTINATION position. + const auto in = mode.input_channels(); + std::array features{}; + for (std::size_t i = 0; i < Mode::ML::kInput; ++i) { + features[i] = (i < in.size()) ? in[i] : 0.f; + } + if (reposition) { + feedback.commit_reposition(); // no weight restore (net never set aside) + } else { + feedback.commit_place(mode.ml()); // restores the real net + } + const auto label = feedback.committed_output(); // valid post-commit + if (!label.empty()) { + mode.ml().add_example( + std::span(features.data(), Mode::ML::kInput), label); + (void)mode.ml().train(); + } +} // Wire all hardware → mode bindings. Must be called *after* // MEMLNaut::Initialize() (so MEMLNaut::Instance() is valid). The Mode @@ -134,8 +152,6 @@ inline void bind_peripherals(Mode& mode) { static FB feedback(static_cast(0xC0FFEEu) ^ kFeedbackSalt); feedback.set_mode(nisps::ml::FeedbackMode::ExploreAndPlace, mode.ml()); - const float spread = mode.param_schema().default_spread; - // MomA1: enter/exit explore toggle. meml->setMomA1Callback([&mode]() { if (feedback.explore_state() == nisps::ml::ExploreState::Idle) { @@ -177,19 +193,7 @@ inline void bind_peripherals(Mode& mode) { return; } if (feedback.repositioning()) { - // Capture the current joystick input — the DESTINATION position. - const auto in = mode.input_channels(); - std::array features{}; - for (std::size_t i = 0; i < Mode::ML::kInput; ++i) { - features[i] = (i < in.size()) ? in[i] : 0.f; - } - feedback.commit_reposition(); // no weight restore (net never set aside) - const auto label = feedback.committed_output(); // the carried output - if (!label.empty()) { - mode.ml().add_example( - std::span(features.data(), Mode::ML::kInput), label); - (void)mode.ml().train(); - } + commit_and_train(mode, feedback, /*reposition=*/true); } }); @@ -216,20 +220,7 @@ inline void bind_peripherals(Mode& mode) { meml->setTogB2Callback([&mode](bool state) { if (!state) return; if (feedback.placing()) { - // Capture the current joystick input BEFORE the restore. - const auto in = mode.input_channels(); - std::array features{}; - for (std::size_t i = 0; i < Mode::ML::kInput; ++i) { - features[i] = (i < in.size()) ? in[i] : 0.f; - } - feedback.commit_place(mode.ml()); // restores the real net - // CALLER owns training: add the +1 example then warm-start train. - const auto label = feedback.committed_output(); // valid post-commit - if (!label.empty()) { - mode.ml().add_example( - std::span(features.data(), Mode::ML::kInput), label); - (void)mode.ml().train(); - } + commit_and_train(mode, feedback, /*reposition=*/false); } else { (void)mode.ml().train(); } diff --git a/firmware/MEMLNaut-NISPS/src/daisysp b/firmware/MEMLNaut-NISPS/src/daisysp deleted file mode 120000 index f0c1fd3..0000000 --- a/firmware/MEMLNaut-NISPS/src/daisysp +++ /dev/null @@ -1 +0,0 @@ -../../../src/daisysp \ No newline at end of file diff --git a/firmware/README.md b/firmware/README.md index baa8726..31cbbcb 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -6,7 +6,6 @@ Thin shell around `nisps/`. The platform-agnostic ML / DSP / engines / modes liv - `glue/audio_driver.hpp` — bridges memllib's `AudioDriver` block callback to `Mode::process(stereosample_t)`. Templated trampoline so no virtual dispatch in audio path. - `glue/peripherals.hpp` — wires MEMLNaut joystick / pots / buttons to `Mode::set_input(idx, value)` and the ML primitives (`draw_weights`, `move_weights`, `train`, `reset`). - `glue/midi_io.hpp` — binds incoming MIDI to `mode.note_on/note_off/update_bpm/set_playing` (where supported); drains outgoing `ControlEvent`s from the mode's ring buffer to the MIDI UART. -- `glue/input_router.hpp` — `wire_inputs()` entry point, currently a thin re-export over peripherals. Will grow into a schema-aware router. - `glue/output_router.hpp` — drains engine events + mode events; called from `loop1()`. - `glue/mode_select.hpp` — type aliases mapping `MEMLNautMode` identifiers to `nisps::modes::Mode` C++ types. Build script rewrites `MEMLNAUT_MODE_TYPE` between the alternatives. @@ -24,7 +23,7 @@ Target: `rp2040:rp2040:solderparty_rp2350_stamp_xl:opt=Optimize3` with `compiler Arduino-CLI compiles every `*.cpp` / `*.hpp` reachable from the sketch directory and from any submodule under `src/`. Headers under `nisps/` are included via relative path (`#include "../../nisps/..."`). No `-I` flag injection needed. -`src/memllib` and `src/daisysp` are git submodules; the `firmware-common.sh` wrapper rejects builds when submodules drift from the recorded revision. +`src/memllib` is the only git submodule; the `firmware-common.sh` wrapper rejects builds when it drifts from the recorded revision. ## Verification diff --git a/scripts/setup-firmware-toolchain.sh b/scripts/setup-firmware-toolchain.sh index 2fc7333..1599b15 100755 --- a/scripts/setup-firmware-toolchain.sh +++ b/scripts/setup-firmware-toolchain.sh @@ -4,7 +4,7 @@ # build environment. Idempotent: safe to re-run. # # It will: -# 1. Initialise the git submodules (memllib + daisysp). +# 1. Initialise the git submodule (memllib). # 2. Install arduino-cli (to ~/.local/bin) if it is not already on PATH. # 3. Install the earlephilhower rp2040 core (provides the # solderparty_rp2350_stamp_xl board + the ARM GCC toolchain). @@ -48,7 +48,7 @@ warn() { printf '\033[1;33mwarning: %s\033[0m\n' "$*" >&2; } die() { printf '\033[1;31merror: %s\033[0m\n' "$*" >&2; exit 1; } # ---- 1. submodules ------------------------------------------------------ -log "Initialising git submodules (memllib + daisysp)" +log "Initialising git submodule (memllib)" command -v git >/dev/null 2>&1 || die "git is not installed" git -C "$REPO_ROOT" submodule update --init --recursive diff --git a/src/daisysp/Control/adenv.cpp b/src/daisysp/Control/adenv.cpp deleted file mode 100644 index 4e9568b..0000000 --- a/src/daisysp/Control/adenv.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include "adenv.h" - -using namespace daisysp; - -//#define EXPF expf -// This causes with infinity with certain curves, -// which then causes NaN erros... -#define EXPF expf_fast - -// To resolve annoying bugs when using this you can: -// if (val != val) -// val = 0.0f; // This will un-NaN the value. - -// Fast Exp approximation -// 8x multiply version -//inline float expf_fast(float x) -//{ -// x = 1.0f + x / 256.0f; -// x *= x; -// x *= x; -// x *= x; -// x *= x; -// x *= x; -// x *= x; -// x *= x; -// x *= x; -// return x; -//} - -// 10x multiply version -inline float expf_fast(float x) -{ - x = 1.0f + x / 1024.0f; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - x *= x; - return x; -} - -// Private Functions -void AdEnv::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - current_segment_ = ADENV_SEG_IDLE; - curve_scalar_ = 0.0f; // full linear - phase_ = 0; - min_ = 0.0f; - max_ = 1.0f; - output_ = 0.0001f; - for(uint8_t i = 0; i < ADENV_SEG_LAST; i++) - { - segment_time_[i] = 0.05f; - } -} - -float AdEnv::Process() -{ - uint32_t time_samps; - float val, out, end, beg, inc; - - // Handle Retriggering - if(trigger_) - { - trigger_ = 0; - current_segment_ = ADENV_SEG_ATTACK; - phase_ = 0; - curve_x_ = 0.0f; - retrig_val_ = output_; - } - - time_samps = (uint32_t)(segment_time_[current_segment_] * sample_rate_); - - // Fixed for now, but we could always make this a more flexible multi-segment envelope - switch(current_segment_) - { - case ADENV_SEG_ATTACK: - beg = retrig_val_; - end = 1.0f; - break; - case ADENV_SEG_DECAY: - beg = 1.0f; - end = 0.0f; - break; - case ADENV_SEG_IDLE: - default: - beg = 0; - end = 0; - break; - } - - if(prev_segment_ != current_segment_) - { - //Reset at segment beginning - curve_x_ = 0; - phase_ = 0; - } - - //recalculate increment value - if(curve_scalar_ == 0.0f) - { - c_inc_ = (end - beg) / time_samps; - } - else - { - c_inc_ = (end - beg) / (1.0f - EXPF(curve_scalar_)); - } - - if(c_inc_ >= 0.0f) - { - c_inc_ = std::max(c_inc_, std::numeric_limits::epsilon()); - } - else - { - c_inc_ = std::min(c_inc_, -std::numeric_limits::epsilon()); - } - - // update output - val = output_; - inc = c_inc_; - out = val; - if(curve_scalar_ == 0.0f) - { - val += inc; - } - else - { - curve_x_ += (curve_scalar_ / time_samps); - val = beg + inc * (1.0f - EXPF(curve_x_)); - if(val != val) - val = 0.0f; // NaN check - } - - // Update Segment - phase_ += 1; - prev_segment_ = current_segment_; - if(current_segment_ != ADENV_SEG_IDLE) - { - if((out >= 1.f && current_segment_ == ADENV_SEG_ATTACK) - || (out <= 0.f && current_segment_ == ADENV_SEG_DECAY)) - { - // Advance segment - current_segment_++; - // TODO: Add Cycling feature here. - if(current_segment_ > ADENV_SEG_DECAY) - { - current_segment_ = ADENV_SEG_IDLE; - } - } - } - if(current_segment_ == ADENV_SEG_IDLE) - { - val = out = 0.0f; - } - output_ = val; - - return out * (max_ - min_) + min_; -} diff --git a/src/daisysp/Control/adenv.h b/src/daisysp/Control/adenv.h deleted file mode 100644 index fb115ae..0000000 --- a/src/daisysp/Control/adenv.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef ADENV_H -#define ADENV_H -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Distinct stages that the phase of the envelope can be located in. - @see AdEnv -*/ -enum AdEnvSegment -{ - /** located at phase location 0, and not currently running */ - ADENV_SEG_IDLE, - /** First segment of envelope where phase moves from MIN value to MAX value */ - ADENV_SEG_ATTACK, - /** Second segment of envelope where phase moves from MAX to MIN value */ - ADENV_SEG_DECAY, - /** The final segment of the envelope (currently decay) */ - ADENV_SEG_LAST, -}; - -/** Trigger-able envelope with adjustable min/max, and independent per-segment time control. - - \author shensley - \todo - Add Cycling - \todo - Implement Curve (its only linear for now). - \todo - Maybe make this an ADsr_ that has AD/AR/Asr_ modes. - */ -class AdEnv -{ - public: - AdEnv() {} - ~AdEnv() {} - /** Initializes the ad envelope. - - Defaults: - - current segment = idle - - curve = linear - - phase = 0 - - min = 0 - - max = 1 - - \param sample_rate sample rate of the audio engine being run - */ - void Init(float sample_rate); - - /** Processes the current sample of the envelope. This should be called once - per sample period. - \return the current envelope value. - */ - float Process(); - - /** Starts or retriggers the envelope.*/ - inline void Trigger() { trigger_ = 1; } - /** Sets the length of time (in seconds) for a specific segment. */ - inline void SetTime(uint8_t seg, float time) { segment_time_[seg] = time; } - /** Sets the amount of curve applied. A positve value will create a log - curve. Input range: -100 to 100. (or more) - */ - inline void SetCurve(float scalar) { curve_scalar_ = scalar; } - /** Sets the minimum value of the envelope output. - Input range: -FLTmax_, to FLTmax_ - */ - inline void SetMin(float min) { min_ = min; } - /** Sets the maximum value of the envelope output. - Input range: -FLTmax_, to FLTmax_ - */ - inline void SetMax(float max) { max_ = max; } - /** Returns the current output value without processing the next sample */ - inline float GetValue() const { return (output_ * (max_ - min_)) + min_; } - /** Returns the segment of the envelope that the phase is currently located - in. - */ - inline uint8_t GetCurrentSegment() { return current_segment_; } - /** Returns true if the envelope is currently in any stage apart from idle. - */ - inline bool IsRunning() const { return current_segment_ != ADENV_SEG_IDLE; } - - private: - uint8_t current_segment_, prev_segment_; - float segment_time_[ADENV_SEG_LAST]; - float sample_rate_, min_, max_, output_, curve_scalar_; - float c_inc_, curve_x_, retrig_val_; - uint32_t phase_; - uint8_t trigger_; -}; - -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Control/adsr.cpp b/src/daisysp/Control/adsr.cpp deleted file mode 100644 index cd62787..0000000 --- a/src/daisysp/Control/adsr.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "adsr.h" -#include - -using namespace daisysp; - - -void Adsr::Init(float sample_rate, int blockSize) -{ - sample_rate_ = sample_rate / blockSize; - attackShape_ = -1.f; - attackTarget_ = 0.0f; - attackTime_ = -1.f; - decayTime_ = -1.f; - releaseTime_ = -1.f; - sus_level_ = 0.7f; - x_ = 0.0f; - gate_ = false; - mode_ = ADSR_SEG_IDLE; - - SetTime(ADSR_SEG_ATTACK, 0.1f); - SetTime(ADSR_SEG_DECAY, 0.1f); - SetTime(ADSR_SEG_RELEASE, 0.1f); -} - -void Adsr::Retrigger(bool hard) -{ - mode_ = ADSR_SEG_ATTACK; - if(hard) - x_ = 0.f; -} - -void Adsr::SetTime(int seg, float time) -{ - switch(seg) - { - case ADSR_SEG_ATTACK: SetAttackTime(time, 0.0f); break; - case ADSR_SEG_DECAY: - { - SetTimeConstant(time, decayTime_, decayD0_); - } - break; - case ADSR_SEG_RELEASE: - { - SetTimeConstant(time, releaseTime_, releaseD0_); - } - break; - default: return; - } -} - -void Adsr::SetAttackTime(float timeInS, float shape) -{ - if((timeInS != attackTime_) || (shape != attackShape_)) - { - attackTime_ = timeInS; - attackShape_ = shape; - if(timeInS > 0.f) - { - float x = shape; - float target = 9.f * powf(x, 10.f) + 0.3f * x + 1.01f; - attackTarget_ = target; - float logTarget = logf(1.f - (1.f / target)); // -1 for decay - attackD0_ = 1.f - expf(logTarget / (timeInS * sample_rate_)); - } - else - attackD0_ = 1.f; // instant change - } -} -void Adsr::SetDecayTime(float timeInS) -{ - SetTimeConstant(timeInS, decayTime_, decayD0_); -} -void Adsr::SetReleaseTime(float timeInS) -{ - SetTimeConstant(timeInS, releaseTime_, releaseD0_); -} - - -void Adsr::SetTimeConstant(float timeInS, float& time, float& coeff) -{ - if(timeInS != time) - { - time = timeInS; - if(time > 0.f) - { - const float target = logf(1. / M_E); - coeff = 1.f - expf(target / (time * sample_rate_)); - } - else - coeff = 1.f; // instant change - } -} - - -float Adsr::Process(bool gate) -{ - float out = 0.0f; - - if(gate && !gate_) // rising edge - mode_ = ADSR_SEG_ATTACK; - else if(!gate && gate_) // falling edge - mode_ = ADSR_SEG_RELEASE; - gate_ = gate; - - float D0(attackD0_); - if(mode_ == ADSR_SEG_DECAY) - D0 = decayD0_; - else if(mode_ == ADSR_SEG_RELEASE) - D0 = releaseD0_; - - float target = mode_ == ADSR_SEG_DECAY ? sus_level_ : -0.01f; - switch(mode_) - { - case ADSR_SEG_IDLE: out = 0.0f; break; - case ADSR_SEG_ATTACK: - x_ += D0 * (attackTarget_ - x_); - out = x_; - if(out > 1.f) - { - x_ = out = 1.f; - mode_ = ADSR_SEG_DECAY; - } - break; - case ADSR_SEG_DECAY: - case ADSR_SEG_RELEASE: - x_ += D0 * (target - x_); - out = x_; - if(out < 0.0f) - { - x_ = out = 0.f; - mode_ = ADSR_SEG_IDLE; - } - default: break; - } - return out; -} diff --git a/src/daisysp/Control/adsr.h b/src/daisysp/Control/adsr.h deleted file mode 100644 index d85d8aa..0000000 --- a/src/daisysp/Control/adsr.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_ADSR_H -#define DSY_ADSR_H - -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Distinct stages that the phase of the envelope can be located in. -- IDLE = located at phase location 0, and not currently running -- ATTACK = First segment of envelope where phase moves from 0 to 1 -- DECAY = Second segment of envelope where phase moves from 1 to SUSTAIN value -- RELEASE = Fourth segment of envelop where phase moves from SUSTAIN to 0 -*/ -enum -{ - ADSR_SEG_IDLE = 0, - ADSR_SEG_ATTACK = 1, - ADSR_SEG_DECAY = 2, - ADSR_SEG_RELEASE = 4 -}; - - -/** adsr envelope module - -Original author(s) : Paul Batchelor - -Ported from Soundpipe by Ben Sergentanis, May 2020 - -Remake by Steffan DIedrichsen, May 2021 -*/ -class Adsr -{ - public: - Adsr() {} - ~Adsr() {} - /** Initializes the Adsr module. - \param sample_rate - The sample rate of the audio engine being run. - */ - void Init(float sample_rate, int blockSize = 1); - /** - \function Retrigger forces the envelope back to attack phase - \param hard resets the history to zero, results in a click. - */ - void Retrigger(bool hard); - /** Processes one sample through the filter and returns one sample. - \param gate - trigger the envelope, hold it to sustain - */ - float Process(bool gate); - /** Sets time - Set time per segment in seconds - */ - void SetTime(int seg, float time); - void SetAttackTime(float timeInS, float shape = 0.0f); - void SetDecayTime(float timeInS); - void SetReleaseTime(float timeInS); - - private: - void SetTimeConstant(float timeInS, float& time, float& coeff); - - public: - /** Sustain level - \param sus_level - sets sustain level, 0...1.0 - */ - inline void SetSustainLevel(float sus_level) - { - sus_level = (sus_level <= 0.f) ? -0.01f // forces envelope into idle - : (sus_level > 1.f) ? 1.f : sus_level; - sus_level_ = sus_level; - } - /** get the current envelope segment - \return the segment of the envelope that the phase is currently located in. - */ - inline uint8_t GetCurrentSegment() { return mode_; } - /** Tells whether envelope is active - \return true if the envelope is currently in any stage apart from idle. - */ - inline bool IsRunning() const { return mode_ != ADSR_SEG_IDLE; } - - private: - float sus_level_{0.f}; - float x_{0.f}; - float attackShape_{-1.f}; - float attackTarget_{0.0f}; - float attackTime_{-1.0f}; - float decayTime_{-1.0f}; - float releaseTime_{-1.0f}; - float attackD0_{0.f}; - float decayD0_{0.f}; - float releaseD0_{0.f}; - int sample_rate_; - uint8_t mode_{ADSR_SEG_IDLE}; - bool gate_{false}; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Control/phasor.cpp b/src/daisysp/Control/phasor.cpp deleted file mode 100644 index d637972..0000000 --- a/src/daisysp/Control/phasor.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include "phasor.h" -#include "../Utility/dsp.h" - -using namespace daisysp; - -void Phasor::SetFreq(float freq) -{ - freq_ = freq; - inc_ = (TWOPI_F * freq_) / sample_rate_; -} - -float Phasor::Process() -{ - float out; - out = phs_ / TWOPI_F; - phs_ += inc_; - if(phs_ > TWOPI_F) - { - phs_ -= TWOPI_F; - } - if(phs_ < 0.0f) - { - phs_ = 0.0f; - } - return out; -} diff --git a/src/daisysp/Control/phasor.h b/src/daisysp/Control/phasor.h deleted file mode 100644 index 63ba336..0000000 --- a/src/daisysp/Control/phasor.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_PHASOR_H -#define DSY_PHASOR_H -#ifdef __cplusplus - -namespace daisysp -{ -/** Generates a normalized signal moving from 0-1 at the specified frequency. - -\todo Selecting which channels should be initialized/included in the sequence conversion. -\todo Setup a similar start function for an external mux, but that seems outside the scope of this file. - -*/ -class Phasor -{ - public: - Phasor() {} - ~Phasor() {} - /** Initializes the Phasor module - sample rate, and freq are in Hz - initial phase is in radians - Additional Init functions have defaults when arg is not specified: - - phs = 0.0f - - freq = 1.0f - */ - inline void Init(float sample_rate, float freq, float initial_phase) - { - sample_rate_ = sample_rate; - phs_ = initial_phase; - SetFreq(freq); - } - - /** Initialize phasor with samplerate and freq - */ - inline void Init(float sample_rate, float freq) - { - Init(sample_rate, freq, 0.0f); - } - - /** Initialize phasor with samplerate - */ - inline void Init(float sample_rate) { Init(sample_rate, 1.0f, 0.0f); } - /** processes Phasor and returns current value - */ - float Process(); - - - /** Sets frequency of the Phasor in Hz - */ - void SetFreq(float freq); - - - /** Returns current frequency value in Hz - */ - inline float GetFreq() { return freq_; } - - private: - float freq_; - float sample_rate_, inc_, phs_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Drums/analogbassdrum.cpp b/src/daisysp/Drums/analogbassdrum.cpp deleted file mode 100644 index 0137f91..0000000 --- a/src/daisysp/Drums/analogbassdrum.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "../Utility/dsp.h" -#include "analogbassdrum.h" -#include - -using namespace daisysp; - -void AnalogBassDrum::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - trig_ = false; - - pulse_remaining_samples_ = 0; - fm_pulse_remaining_samples_ = 0; - pulse_ = 0.0f; - pulse_height_ = 0.0f; - pulse_lp_ = 0.0f; - fm_pulse_lp_ = 0.0f; - retrig_pulse_ = 0.0f; - lp_out_ = 0.0f; - tone_lp_ = 0.0f; - sustain_gain_ = 0.0f; - phase_ = 0.f; - - - SetSustain(false); - SetAccent(.1f); - SetFreq(50.f); - SetTone(.1f); - SetDecay(.3f); - SetSelfFmAmount(1.f); - SetAttackFmAmount(.5f); - - resonator_.Init(sample_rate_); -} - -inline float AnalogBassDrum::Diode(float x) -{ - if(x >= 0.0f) - { - return x; - } - else - { - x *= 2.0f; - return 0.7f * x / (1.0f + fabsf(x)); - } -} - -float AnalogBassDrum::Process(bool trigger) -{ - const int kTriggerPulseDuration = static_cast(1.0e-3f * sample_rate_); - const int kFMPulseDuration = static_cast(6.0e-3f * sample_rate_); - const float kPulseDecayTime = 0.2e-3f * sample_rate_; - const float kPulseFilterTime = 0.1e-3f * sample_rate_; - const float kRetrigPulseDuration = 0.05f * sample_rate_; - - const float scale = 0.001f / f0_; - const float q = 1500.0f * powf(2.f, kOneTwelfth * decay_ * 80.0f); - const float tone_f - = fmin(4.0f * f0_ * powf(2.f, kOneTwelfth * tone_ * 108.0f), 1.0f); - const float exciter_leak = 0.08f * (tone_ + 0.25f); - - - if(trigger || trig_) - { - trig_ = false; - - pulse_remaining_samples_ = kTriggerPulseDuration; - fm_pulse_remaining_samples_ = kFMPulseDuration; - pulse_height_ = 3.0f + 7.0f * accent_; - lp_out_ = 0.0f; - } - - // Q39 / Q40 - float pulse = 0.0f; - if(pulse_remaining_samples_) - { - --pulse_remaining_samples_; - pulse = pulse_remaining_samples_ ? pulse_height_ : pulse_height_ - 1.0f; - pulse_ = pulse; - } - else - { - pulse_ *= 1.0f - 1.0f / kPulseDecayTime; - pulse = pulse_; - } - if(sustain_) - { - pulse = 0.0f; - } - - // C40 / R163 / R162 / D83 - fonepole(pulse_lp_, pulse, 1.0f / kPulseFilterTime); - pulse = Diode((pulse - pulse_lp_) + pulse * 0.044f); - - // Q41 / Q42 - float fm_pulse = 0.0f; - if(fm_pulse_remaining_samples_) - { - --fm_pulse_remaining_samples_; - fm_pulse = 1.0f; - // C39 / C52 - retrig_pulse_ = fm_pulse_remaining_samples_ ? 0.0f : -0.8f; - } - else - { - // C39 / R161 - retrig_pulse_ *= 1.0f - 1.0f / kRetrigPulseDuration; - } - if(sustain_) - { - fm_pulse = 0.0f; - } - fonepole(fm_pulse_lp_, fm_pulse, 1.0f / kPulseFilterTime); - - // Q43 and R170 leakage - float punch = 0.7f + Diode(10.0f * lp_out_ - 1.0f); - - // Q43 / R165 - float attack_fm = fm_pulse_lp_ * 1.7f * attack_fm_amount_; - float self_fm = punch * 0.08f * self_fm_amount_; - float f = f0_ * (1.0f + attack_fm + self_fm); - f = fclamp(f, 0.0f, 0.4f); - - float resonator_out; - if(sustain_) - { - sustain_gain_ = accent_ * decay_; - phase_ += f; - phase_ = phase_ >= 1.f ? phase_ - 1.f : phase_; - - resonator_out = sin(TWOPI_F * phase_) * sustain_gain_; - lp_out_ = cos(TWOPI_F * phase_) * sustain_gain_; - } - else - { - resonator_.SetFreq(f * sample_rate_); - //resonator_.SetRes(1.0f + q * f); - resonator_.SetRes(.4f * q * f); - - resonator_.Process((pulse - retrig_pulse_ * 0.2f) * scale); - resonator_out = resonator_.Band(); - lp_out_ = resonator_.Low(); - } - - fonepole(tone_lp_, pulse * exciter_leak + resonator_out, tone_f); - - return tone_lp_; -} - -void AnalogBassDrum::Trig() -{ - trig_ = true; -} - -void AnalogBassDrum::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void AnalogBassDrum::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void AnalogBassDrum::SetFreq(float f0) -{ - f0 /= sample_rate_; - f0_ = fclamp(f0, 0.f, .5f); -} - -void AnalogBassDrum::SetTone(float tone) -{ - tone_ = fclamp(tone, 0.f, 1.f); -} - -void AnalogBassDrum::SetDecay(float decay) -{ - decay_ = decay * .1f; - decay_ -= .1f; -} - -void AnalogBassDrum::SetAttackFmAmount(float attack_fm_amount) -{ - attack_fm_amount_ = attack_fm_amount * 50.f; -} - -void AnalogBassDrum::SetSelfFmAmount(float self_fm_amount) -{ - self_fm_amount_ = self_fm_amount * 50.f; -} diff --git a/src/daisysp/Drums/analogbassdrum.h b/src/daisysp/Drums/analogbassdrum.h deleted file mode 100644 index 30ae68f..0000000 --- a/src/daisysp/Drums/analogbassdrum.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_ANALOG_BD_H -#define DSY_ANALOG_BD_H - -#include -#ifdef __cplusplus - -#include "../Synthesis/oscillator.h" -#include "../Filters/svf.h" - -/** @file analogbassdrum.h */ - -namespace daisysp -{ -/** - @brief 808 bass drum model, revisited. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/analog_bass_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class AnalogBassDrum -{ - public: - AnalogBassDrum() {} - ~AnalogBassDrum() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next sample. - \param trigger True strikes the drum. Defaults to false. - */ - float Process(bool trigger = false); - - /** Strikes the drum. */ - void Trig(); - - /** Set the bassdrum to play infinitely - \param sustain True = infinite length - */ - void SetSustain(bool sustain); - - /** Set a small accent. - \param accent Works 0-1 - */ - void SetAccent(float accent); - - /** Set the drum's root frequency - \param f0 Frequency in Hz - */ - void SetFreq(float f0); - - /** Set the amount of click. - \param tone Works 0-1. - */ - void SetTone(float tone); - - /** Set the decay length of the drum. - \param decay Works best 0-1. - */ - void SetDecay(float decay); - - /** Set the amount of fm attack. Works together with self fm. - \param attack_fm_amount Works best 0-1. - */ - void SetAttackFmAmount(float attack_fm_amount); - - /**Set the amount of self fm. Also affects fm attack, and volume decay. - \param self_fm_amount Works best 0-1. - */ - void SetSelfFmAmount(float self_fm_amount); - - private: - inline float Diode(float x); - - float sample_rate_; - - float accent_, f0_, tone_, decay_; - float attack_fm_amount_, self_fm_amount_; - - bool trig_, sustain_; - - int pulse_remaining_samples_; - int fm_pulse_remaining_samples_; - float pulse_; - float pulse_height_; - float pulse_lp_; - float fm_pulse_lp_; - float retrig_pulse_; - float lp_out_; - float tone_lp_; - float sustain_gain_; - - Svf resonator_; - - //for use in sin + cos osc. in sustain mode - float phase_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Drums/analogsnaredrum.cpp b/src/daisysp/Drums/analogsnaredrum.cpp deleted file mode 100644 index 5d10c7d..0000000 --- a/src/daisysp/Drums/analogsnaredrum.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "../Utility/dsp.h" -#include "analogsnaredrum.h" -#include -#include - -using namespace daisysp; - -static const int kNumModes = 5; - -void AnalogSnareDrum::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - trig_ = false; - - pulse_remaining_samples_ = 0; - pulse_ = 0.0f; - pulse_height_ = 0.0f; - pulse_lp_ = 0.0f; - noise_envelope_ = 0.0f; - sustain_gain_ = 0.0f; - - SetSustain(false); - SetAccent(.6f); - SetFreq(200.f); - SetDecay(.3f); - SetSnappy(.7f); - SetTone(.5f); - - for(int i = 0; i < kNumModes; ++i) - { - resonator_[i].Init(sample_rate_); - phase_[i] = 0.f; - } - noise_filter_.Init(sample_rate_); -} - -/** Trigger the drum */ -void AnalogSnareDrum::Trig() -{ - trig_ = true; -} - -void AnalogSnareDrum::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void AnalogSnareDrum::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void AnalogSnareDrum::SetFreq(float f0) -{ - f0 = f0 / sample_rate_; - f0_ = fclamp(f0, 0.f, .4f); -} - -void AnalogSnareDrum::SetTone(float tone) -{ - tone_ = fclamp(tone, 0.f, 1.f); - tone_ *= 2.f; -} - -void AnalogSnareDrum::SetDecay(float decay) -{ - decay_ = decay; - return; - decay_ = fmax(decay, 0.f); -} - -void AnalogSnareDrum::SetSnappy(float snappy) -{ - snappy_ = fclamp(snappy, 0.f, 1.f); -} - -float AnalogSnareDrum::Process(bool trigger) -{ - const float decay_xt = decay_ * (1.0f + decay_ * (decay_ - 1.0f)); - const int kTriggerPulseDuration = 1.0e-3 * sample_rate_; - const float kPulseDecayTime = 0.1e-3 * sample_rate_; - const float q = 2000.0f * powf(2.f, kOneTwelfth * decay_xt * 84.0f); - const float noise_envelope_decay - = 1.0f - - 0.0017f - * powf(2.f, - kOneTwelfth * (-decay_ * (50.0f + snappy_ * 10.0f))); - const float exciter_leak = snappy_ * (2.0f - snappy_) * 0.1f; - - float snappy = snappy_ * 1.1f - 0.05f; - snappy = fclamp(snappy, 0.0f, 1.0f); - - float tone = tone_; - - if(trigger || trig_) - { - trig_ = false; - pulse_remaining_samples_ = kTriggerPulseDuration; - pulse_height_ = 3.0f + 7.0f * accent_; - noise_envelope_ = 2.0f; - } - - static const float kModeFrequencies[kNumModes] - = {1.00f, 2.00f, 3.18f, 4.16f, 5.62f}; - - float f[kNumModes]; - float gain[kNumModes]; - - for(int i = 0; i < kNumModes; ++i) - { - f[i] = fmin(f0_ * kModeFrequencies[i], 0.499f); - resonator_[i].SetFreq(f[i] * sample_rate_); - // resonator_[i].SetRes(1.0f + f[i] * (i == 0 ? q : q * 0.25f)); - resonator_[i].SetRes((f[i] * (i == 0 ? q : q * 0.25f)) * .2); - } - - if(tone < 0.666667f) - { - // 808-style (2 modes) - tone *= 1.5f; - gain[0] = 1.5f + (1.0f - tone) * (1.0f - tone) * 4.5f; - gain[1] = 2.0f * tone + 0.15f; - for(int i = 2; i < kNumModes; i++) - { - gain[i] = 0.f; - } - } - else - { - // What the 808 could have been if there were extra modes! - tone = (tone - 0.666667f) * 3.0f; - gain[0] = 1.5f - tone * 0.5f; - gain[1] = 2.15f - tone * 0.7f; - for(int i = 2; i < kNumModes; ++i) - { - gain[i] = tone; - tone *= tone; - } - } - - float f_noise = f0_ * 16.0f; - fclamp(f_noise, 0.0f, 0.499f); - noise_filter_.SetFreq(f_noise * sample_rate_); - //noise_filter_.SetRes(1.0f + f_noise * 1.5f); - noise_filter_.SetRes(f_noise * 1.5f); - - // Q45 / Q46 - float pulse = 0.0f; - if(pulse_remaining_samples_) - { - --pulse_remaining_samples_; - pulse = pulse_remaining_samples_ ? pulse_height_ : pulse_height_ - 1.0f; - pulse_ = pulse; - } - else - { - pulse_ *= 1.0f - 1.0f / kPulseDecayTime; - pulse = pulse_; - } - - float sustain_gain_value = sustain_gain_ = accent_ * decay_; - - // R189 / C57 / R190 + C58 / C59 / R197 / R196 / IC14 - pulse_lp_ = fclamp(pulse_lp_, pulse, 0.75f); - - float shell = 0.0f; - for(int i = 0; i < kNumModes; ++i) - { - float excitation - = i == 0 ? (pulse - pulse_lp_) + 0.006f * pulse : 0.026f * pulse; - - phase_[i] += f[i]; - phase_[i] = phase_[i] >= 1.f ? phase_[i] - 1.f : phase_[i]; - - resonator_[i].Process(excitation); - - shell += gain[i] - * (sustain_ - ? sin(phase_[i] * TWOPI_F) * sustain_gain_value * 0.25f - : resonator_[i].Band() + excitation * exciter_leak); - } - shell = SoftClip(shell); - - // C56 / R194 / Q48 / C54 / R188 / D54 - float noise = 2.0f * rand() * kRandFrac - 1.0f; - if(noise < 0.0f) - noise = 0.0f; - noise_envelope_ *= noise_envelope_decay; - noise *= (sustain_ ? sustain_gain_value : noise_envelope_) * snappy * 2.0f; - - // C66 / R201 / C67 / R202 / R203 / Q49 - noise_filter_.Process(noise); - noise = noise_filter_.Band(); - - // IC13 - return noise + shell * (1.0f - snappy); -} - -inline float AnalogSnareDrum::SoftLimit(float x) -{ - return x * (27.0f + x * x) / (27.0f + 9.0f * x * x); -} - -inline float AnalogSnareDrum::SoftClip(float x) -{ - if(x < -3.0f) - { - return -1.0f; - } - else if(x > 3.0f) - { - return 1.0f; - } - else - { - return SoftLimit(x); - } -} \ No newline at end of file diff --git a/src/daisysp/Drums/analogsnaredrum.h b/src/daisysp/Drums/analogsnaredrum.h deleted file mode 100644 index adeb3c3..0000000 --- a/src/daisysp/Drums/analogsnaredrum.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_ANALOG_SNARE_H -#define DSY_ANALOG_SNARE_H - -#include "../Filters/svf.h" - -#include -#ifdef __cplusplus - -/** @file analogsnaredrum.h */ - -namespace daisysp -{ -/** - @brief 808 snare drum model, revisited. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/analog_snare_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class AnalogSnareDrum -{ - public: - AnalogSnareDrum() {} - ~AnalogSnareDrum() {} - - static const int kNumModes = 5; - - /** Init the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next sample - \param trigger Hit the drum with true. Defaults to false. - */ - float Process(bool trigger = false); - - /** Trigger the drum */ - void Trig(); - - /** Init the module - \param sample_rate Audio engine sample rate - */ - void SetSustain(bool sustain); - - /** Set how much accent to use - \param accent Works 0-1. - */ - void SetAccent(float accent); - - /** Set the drum's root frequency - \param f0 Freq in Hz - */ - void SetFreq(float f0); - - /** Set the brightness of the drum tone. - \param tone Works 0-1. 1 = bright, 0 = dark. - */ - void SetTone(float tone); - - /** Set the length of the drum decay - \param decay Works with positive numbers - */ - void SetDecay(float decay); - - /** Sets the mix between snare and drum. - \param snappy 1 = just snare. 0 = just drum. - */ - void SetSnappy(float snappy); - - private: - float sample_rate_; - - float f0_, tone_, accent_, snappy_, decay_; - bool sustain_; - bool trig_; - - inline float SoftLimit(float x); - inline float SoftClip(float x); - - int pulse_remaining_samples_; - float pulse_; - float pulse_height_; - float pulse_lp_; - float noise_envelope_; - float sustain_gain_; - - Svf resonator_[kNumModes]; - Svf noise_filter_; - - // Replace the resonators in "free running" (sustain) mode. - float phase_[kNumModes]; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Drums/hihat.cpp b/src/daisysp/Drums/hihat.cpp deleted file mode 100644 index 27e12e7..0000000 --- a/src/daisysp/Drums/hihat.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "../Utility/dsp.h" -#include "hihat.h" -#include - -using namespace daisysp; - -void SquareNoise::Init(float sample_rate) -{ - for(int i = 0; i < 6; i++) - { - phase_[i] = 0; - } -} - -float SquareNoise::Process(float f0) -{ - const float ratios[6] = {// Nominal f0: 414 Hz - 1.0f, - 1.304f, - 1.466f, - 1.787f, - 1.932f, - 2.536f}; - - uint32_t increment[6]; - uint32_t phase[6]; - for(int i = 0; i < 6; ++i) - { - float f = f0 * ratios[i]; - if(f >= 0.499f) - f = 0.499f; - increment[i] = static_cast(f * 4294967296.0f); - phase[i] = phase_[i]; - } - - phase[0] += increment[0]; - phase[1] += increment[1]; - phase[2] += increment[2]; - phase[3] += increment[3]; - phase[4] += increment[4]; - phase[5] += increment[5]; - uint32_t noise = 0; - noise += (phase[0] >> 31); - noise += (phase[1] >> 31); - noise += (phase[2] >> 31); - noise += (phase[3] >> 31); - noise += (phase[4] >> 31); - noise += (phase[5] >> 31); - - for(int i = 0; i < 6; ++i) - { - phase_[i] = phase[i]; - } - - return 0.33f * static_cast(noise) - 1.0f; -} - -void RingModNoise::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - for(int i = 0; i < 6; ++i) - { - oscillator_[i].Init(sample_rate_); - } -} - -float RingModNoise::Process(float f0) -{ - const float ratio = f0 / (0.01f + f0); - const float f1a = 200.0f / sample_rate_ * ratio; - const float f1b = 7530.0f / sample_rate_ * ratio; - const float f2a = 510.0f / sample_rate_ * ratio; - const float f2b = 8075.0f / sample_rate_ * ratio; - const float f3a = 730.0f / sample_rate_ * ratio; - const float f3b = 10500.0f / sample_rate_ * ratio; - - float out = ProcessPair(&oscillator_[0], f1a, f1b); - out += ProcessPair(&oscillator_[2], f2a, f2b); - out += ProcessPair(&oscillator_[4], f3a, f3b); - - return out; -} - -float RingModNoise::ProcessPair(Oscillator* osc, float f1, float f2) -{ - osc[0].SetWaveform(Oscillator::WAVE_SQUARE); - osc[0].SetFreq(f1 * sample_rate_); - float temp_1 = osc[0].Process(); - - osc[1].SetWaveform(Oscillator::WAVE_SAW); - osc[1].SetFreq(f2 * sample_rate_); - float temp_2 = osc[1].Process(); - - return temp_1 * temp_2; -} \ No newline at end of file diff --git a/src/daisysp/Drums/hihat.h b/src/daisysp/Drums/hihat.h deleted file mode 100644 index 93ea7a8..0000000 --- a/src/daisysp/Drums/hihat.h +++ /dev/null @@ -1,277 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_HIHAT_H -#define DSY_HIHAT_H - -#include "../Filters/svf.h" -#include "../Synthesis/oscillator.h" - -#include -#include -#ifdef __cplusplus - -/** @file hihat.h */ - -namespace daisysp -{ -/** - @brief 808 style "metallic noise" with 6 square oscillators. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/hihat.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SquareNoise -{ - public: - SquareNoise() {} - ~SquareNoise() {} - - void Init(float sample_rate); - - float Process(float f0); - - private: - uint32_t phase_[6]; -}; - -/** - @brief Ring mod style metallic noise generator. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/hihat.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class RingModNoise -{ - public: - RingModNoise() {} - ~RingModNoise() {} - - void Init(float sample_rate); - - float Process(float f0); - - private: - float ProcessPair(Oscillator* osc, float f1, float f2); - Oscillator oscillator_[6]; - - float sample_rate_; -}; - -/** - @brief Swing type VCA - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/hihat.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SwingVCA -{ - public: - float operator()(float s, float gain) - { - s *= s > 0.0f ? 10.0f : 0.1f; - s = s / (1.0f + fabsf(s)); - return (s + 1.0f) * gain; - } -}; - -/** - @brief Linear type VCA - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/hihat.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class LinearVCA -{ - public: - float operator()(float s, float gain) { return s * gain; } -}; - -/** - @brief 808 HH, with a few extra parameters to push things to the CY territory... - @author Ben Sergentanis - @date Jan 2021 - The template parameter MetallicNoiseSource allows another kind of "metallic \n - noise" to be used, for results which are more similar to KR-55 or FM hi-hats. \n \n - Ported from pichenettes/eurorack/plaits/dsp/drums/hihat.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -template -class HiHat -{ - public: - HiHat() {} - ~HiHat() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate) - { - sample_rate_ = sample_rate; - - trig_ = false; - - envelope_ = 0.0f; - noise_clock_ = 0.0f; - noise_sample_ = 0.0f; - sustain_gain_ = 0.0f; - - SetFreq(3000.f); - SetTone(.5f); - SetDecay(.2f); - SetNoisiness(.8f); - SetAccent(.8f); - SetSustain(false); - - metallic_noise_.Init(sample_rate_); - noise_coloration_svf_.Init(sample_rate_); - hpf_.Init(sample_rate_); - } - - /** Get the next sample - \param trigger Hit the hihat with true. Defaults to false. - */ - float Process(bool trigger = false) - { - const float envelope_decay - = 1.0f - 0.003f * SemitonesToRatio(-decay_ * 84.0f); - const float cut_decay - = 1.0f - 0.0025f * SemitonesToRatio(-decay_ * 36.0f); - - if(trigger || trig_) - { - trig_ = false; - - envelope_ - = (1.5f + 0.5f * (1.0f - decay_)) * (0.3f + 0.7f * accent_); - } - - // Process the metallic noise. - float out = metallic_noise_.Process(2.0f * f0_); - - // Apply BPF on the metallic noise. - float cutoff = 150.0f / sample_rate_ * SemitonesToRatio(tone_ * 72.0f); - - cutoff = fclamp(cutoff, 0.0f, 16000.0f / sample_rate_); - - - noise_coloration_svf_.SetFreq(cutoff * sample_rate_); - noise_coloration_svf_.SetRes(resonance ? 3.0f + 6.0f * tone_ : 1.0f); - - noise_coloration_svf_.Process(out); - out = noise_coloration_svf_.Band(); - - // This is not at all part of the 808 circuit! But to add more variety, we - // add a variable amount of clocked noise to the output of the 6 schmitt - // trigger oscillators. - float noise_f = f0_ * (16.0f + 16.0f * (1.0f - noisiness_)); - noise_f = fclamp(noise_f, 0.0f, 0.5f); - - noise_clock_ += noise_f; - if(noise_clock_ >= 1.0f) - { - noise_clock_ -= 1.0f; - noise_sample_ = rand() * kRandFrac - 0.5f; - } - out += noisiness_ * (noise_sample_ - out); - - // Apply VCA. - sustain_gain_ = accent_ * decay_; - VCA vca; - envelope_ *= envelope_ > 0.5f ? envelope_decay : cut_decay; - out = vca(out, sustain_ ? sustain_gain_ : envelope_); - - hpf_.SetFreq(cutoff * sample_rate_); - hpf_.SetRes(.5f); - hpf_.Process(out); - out = hpf_.High(); - - return out; - } - - /** Trigger the hihat */ - void Trig() { trig_ = true; } - - /** Make the hihat ring out infinitely. - \param sustain True = infinite sustain. - */ - void SetSustain(bool sustain) { sustain_ = sustain; } - - /** Set how much accent to use - \param accent Works 0-1. - */ - void SetAccent(float accent) { accent_ = fclamp(accent, 0.f, 1.f); } - - /** Set the hihat tone's root frequency - \param f0 Freq in Hz - */ - void SetFreq(float f0) - { - f0 /= sample_rate_; - f0_ = fclamp(f0, 0.f, 1.f); - } - - /** Set the overall brightness / darkness of the hihat. - \param tone Works from 0-1. - */ - void SetTone(float tone) { tone_ = fclamp(tone, 0.f, 1.f); } - - /** Set the length of the hihat decay - \param decay Works > 0. Tuned for 0-1. - */ - void SetDecay(float decay) - { - decay_ = fmax(decay, 0.f); - decay_ *= 1.7; - decay_ -= 1.2; - } - - /** Sets the mix between tone and noise - \param snappy 1 = just noise. 0 = just tone. - */ - void SetNoisiness(float noisiness) - { - noisiness_ = fclamp(noisiness, 0.f, 1.f); - noisiness_ *= noisiness_; - } - - - private: - float sample_rate_; - - float accent_, f0_, tone_, decay_, noisiness_; - bool sustain_; - bool trig_; - - float SemitonesToRatio(float in) { return powf(2.f, in * kOneTwelfth); } - - float envelope_; - float noise_clock_; - float noise_sample_; - float sustain_gain_; - - MetallicNoiseSource metallic_noise_; - Svf noise_coloration_svf_; - Svf hpf_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Drums/synthbassdrum.cpp b/src/daisysp/Drums/synthbassdrum.cpp deleted file mode 100644 index 24adf8b..0000000 --- a/src/daisysp/Drums/synthbassdrum.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "synthbassdrum.h" -#include -#include - -using namespace daisysp; - -void SyntheticBassDrumClick::Init(float sample_rate) -{ - lp_ = 0.0f; - hp_ = 0.0f; - filter_.Init(sample_rate); - filter_.SetFreq(5000.0f); - filter_.SetRes(1.f); //2.f -} - -float SyntheticBassDrumClick::Process(float in) -{ - //SLOPE(lp_, in, 0.5f, 0.1f); - float error = in - lp_; - lp_ += (error > 0 ? .5f : .1f) * error; - - fonepole(hp_, lp_, 0.04f); - filter_.Process(lp_ - hp_); - return filter_.Low(); -} - -void SyntheticBassDrumAttackNoise::Init() -{ - lp_ = 0.0f; - hp_ = 0.0f; -} - -float SyntheticBassDrumAttackNoise::Process() -{ - float sample = rand() * kRandFrac; - fonepole(lp_, sample, 0.05f); - fonepole(hp_, lp_, 0.005f); - return lp_ - hp_; -} - -void SyntheticBassDrum::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - trig_ = false; - - phase_ = 0.0f; - phase_noise_ = 0.0f; - f0_ = 0.0f; - fm_ = 0.0f; - fm_lp_ = 0.0f; - body_env_lp_ = 0.0f; - body_env_ = 0.0f; - body_env_pulse_width_ = 0; - fm_pulse_width_ = 0; - tone_lp_ = 0.0f; - sustain_gain_ = 0.0f; - - SetFreq(100.f); - SetSustain(false); - SetAccent(.2f); - SetTone(.6f); - SetDecay(.7f); - SetDirtiness(.3f); - SetFmEnvelopeAmount(.6); - SetFmEnvelopeDecay(.3); - - click_.Init(sample_rate); - noise_.Init(); -} - -inline float SyntheticBassDrum::DistortedSine(float phase, - float phase_noise, - float dirtiness) -{ - phase += phase_noise * dirtiness; - - //MAKE_INTEGRAL_FRACTIONAL(phase); - int32_t phase_integral = static_cast(phase); - float phase_fractional = phase - static_cast(phase_integral); - - phase = phase_fractional; - float triangle = (phase < 0.5f ? phase : 1.0f - phase) * 4.0f - 1.0f; - float sine = 2.0f * triangle / (1.0f + fabsf(triangle)); - float clean_sine = sinf(TWOPI_F * (phase + 0.75f)); - return sine + (1.0f - dirtiness) * (clean_sine - sine); -} - -inline float SyntheticBassDrum::TransistorVCA(float s, float gain) -{ - s = (s - 0.6f) * gain; - return 3.0f * s / (2.0f + fabsf(s)) + gain * 0.3f; -} - -float SyntheticBassDrum::Process(bool trigger) -{ - float dirtiness = dirtiness_; - dirtiness *= fmax(1.0f - 8.0f * new_f0_, 0.0f); - - const float fm_decay - = 1.0f - - 1.0f / (0.008f * (1.0f + fm_envelope_decay_ * 4.0f) * sample_rate_); - - const float body_env_decay - = 1.0f - - 1.0f / (0.02f * sample_rate_) - * powf(2.f, (-decay_ * 60.0f) * kOneTwelfth); - const float transient_env_decay = 1.0f - 1.0f / (0.005f * sample_rate_); - const float tone_f = fmin( - 4.0f * new_f0_ * powf(2.f, (tone_ * 108.0f) * kOneTwelfth), 1.0f); - const float transient_level = tone_; - - if(trigger || trig_) - { - trig_ = false; - fm_ = 1.0f; - body_env_ = transient_env_ = 0.3f + 0.7f * accent_; - body_env_pulse_width_ = sample_rate_ * 0.001f; - fm_pulse_width_ = sample_rate_ * 0.0013f; - } - - sustain_gain_ = accent_ * decay_; - - fonepole(phase_noise_, rand() * kRandFrac - 0.5f, 0.002f); - - float mix = 0.0f; - - if(sustain_) - { - f0_ = new_f0_; - phase_ += f0_; - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - } - float body = DistortedSine(phase_, phase_noise_, dirtiness); - mix -= TransistorVCA(body, sustain_gain_); - } - else - { - if(fm_pulse_width_) - { - --fm_pulse_width_; - phase_ = 0.25f; - } - else - { - fm_ *= fm_decay; - float fm = 1.0f + fm_envelope_amount_ * 3.5f * fm_lp_; - f0_ = new_f0_; - phase_ += fmin(f0_ * fm, 0.5f); - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - } - } - - if(body_env_pulse_width_) - { - --body_env_pulse_width_; - } - else - { - body_env_ *= body_env_decay; - transient_env_ *= transient_env_decay; - } - - const float envelope_lp_f = 0.1f; - fonepole(body_env_lp_, body_env_, envelope_lp_f); - fonepole(transient_env_lp_, transient_env_, envelope_lp_f); - fonepole(fm_lp_, fm_, envelope_lp_f); - - float body = DistortedSine(phase_, phase_noise_, dirtiness); - float transient = click_.Process(body_env_pulse_width_ ? 0.0f : 1.0f) - + noise_.Process(); - - mix -= TransistorVCA(body, body_env_lp_); - mix -= transient * transient_env_lp_ * transient_level; - } - - fonepole(tone_lp_, mix, tone_f); - return tone_lp_; -} - -void SyntheticBassDrum::Trig() -{ - trig_ = true; -} - -void SyntheticBassDrum::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void SyntheticBassDrum::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void SyntheticBassDrum::SetFreq(float freq) -{ - freq /= sample_rate_; - new_f0_ = fclamp(freq, 0.f, 1.f); -} - -void SyntheticBassDrum::SetTone(float tone) -{ - tone_ = fclamp(tone, 0.f, 1.f); -} - -void SyntheticBassDrum::SetDecay(float decay) -{ - decay = fclamp(decay, 0.f, 1.f); - decay_ = decay * decay; -} - -void SyntheticBassDrum::SetDirtiness(float dirtiness) -{ - dirtiness_ = fclamp(dirtiness, 0.f, 1.f); -} - -void SyntheticBassDrum::SetFmEnvelopeAmount(float fm_envelope_amount) -{ - fm_envelope_amount_ = fclamp(fm_envelope_amount, 0.f, 1.f); -} - -void SyntheticBassDrum::SetFmEnvelopeDecay(float fm_envelope_decay) -{ - fm_envelope_decay = fclamp(fm_envelope_decay, 0.f, 1.f); - fm_envelope_decay_ = fm_envelope_decay * fm_envelope_decay; -} \ No newline at end of file diff --git a/src/daisysp/Drums/synthbassdrum.h b/src/daisysp/Drums/synthbassdrum.h deleted file mode 100644 index 58a4de5..0000000 --- a/src/daisysp/Drums/synthbassdrum.h +++ /dev/null @@ -1,187 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SYNTHBD_H -#define DSY_SYNTHBD_H - -#include "../Filters/svf.h" -#include "../Utility/dsp.h" - -#include -#ifdef __cplusplus - -/** @file synthbassdrum.h */ - -namespace daisysp -{ -/** - @brief Click noise for SyntheticBassDrum - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/synthetic_bass_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SyntheticBassDrumClick -{ - public: - SyntheticBassDrumClick() {} - ~SyntheticBassDrumClick() {} - - /** Init the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get the next sample. - \param in Trigger the click. - */ - float Process(float in); - - private: - float lp_; - float hp_; - Svf filter_; -}; - -/** - @brief Attack Noise generator for SyntheticBassDrum. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/drums/synthetic_bass_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SyntheticBassDrumAttackNoise -{ - public: - SyntheticBassDrumAttackNoise() {} - ~SyntheticBassDrumAttackNoise() {} - - /** Init the module */ - void Init(); - - /** Get the next sample. */ - float Process(); - - private: - float lp_; - float hp_; -}; - -/** - @brief Naive bass drum model (modulated oscillator with FM + envelope). - @author Ben Sergentanis - @date Jan 2021 - Inadvertently 909-ish. \n \n - Ported from pichenettes/eurorack/plaits/dsp/drums/synthetic_bass_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SyntheticBassDrum -{ - public: - SyntheticBassDrum() {} - ~SyntheticBassDrum() {} - - /** Init the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Generates a distorted sine wave */ - inline float DistortedSine(float phase, float phase_noise, float dirtiness); - - /** Transistor VCA simulation. - \param s Input sample. - \param gain VCA gain. - */ - inline float TransistorVCA(float s, float gain); - - /** Get the next sample. - \param trigger True triggers the BD. This is optional. - */ - float Process(bool trigger = false); - - /** Trigger the drum */ - void Trig(); - - /** Allows the drum to play continuously - \param sustain True sets the drum on infinite sustain. - */ - void SetSustain(bool sustain); - - /** Sets the amount of accent. - \param accent Works 0-1. - */ - void SetAccent(float accent); - - /** Set the bass drum's root frequency. - \param Frequency in Hz. - */ - void SetFreq(float freq); - - /** Sets the overall bright / darkness of the drum. - \param tone Works 0-1. - */ - void SetTone(float tone); - - /** Sets how long the drum's volume takes to decay. - \param Works 0-1. - */ - void SetDecay(float decay); - - /** Makes things grimy - \param dirtiness Works 0-1. - */ - void SetDirtiness(float dirtiness); - - /** Sets how much of a pitch sweep the drum experiences when triggered. - \param fm_envelope_amount Works 0-1. - */ - void SetFmEnvelopeAmount(float fm_envelope_amount); - - /** Sets how long the initial pitch sweep takes. - \param fm_envelope_decay Works 0-1. - */ - void SetFmEnvelopeDecay(float fm_envelope_decay); - - private: - float sample_rate_; - - bool trig_; - bool sustain_; - float accent_, new_f0_, tone_, decay_; - float dirtiness_, fm_envelope_amount_, fm_envelope_decay_; - - float f0_; - float phase_; - float phase_noise_; - - float fm_; - float fm_lp_; - float body_env_; - float body_env_lp_; - float transient_env_; - float transient_env_lp_; - - float sustain_gain_; - - float tone_lp_; - - SyntheticBassDrumClick click_; - SyntheticBassDrumAttackNoise noise_; - - int body_env_pulse_width_; - int fm_pulse_width_; -}; - -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Drums/synthsnaredrum.cpp b/src/daisysp/Drums/synthsnaredrum.cpp deleted file mode 100644 index d0b9e9b..0000000 --- a/src/daisysp/Drums/synthsnaredrum.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "../Utility/dsp.h" -#include "synthsnaredrum.h" -#include -#include - -using namespace daisysp; - -void SyntheticSnareDrum::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - phase_[0] = 0.0f; - phase_[1] = 0.0f; - drum_amplitude_ = 0.0f; - snare_amplitude_ = 0.0f; - fm_ = 0.0f; - hold_counter_ = 0; - sustain_gain_ = 0.0f; - - SetSustain(false); - SetAccent(.6f); - SetFreq(200.f); - SetFmAmount(.1f); - SetDecay(.3f); - SetSnappy(.7f); - - trig_ = false; - - drum_lp_.Init(sample_rate_); - snare_hp_.Init(sample_rate_); - snare_lp_.Init(sample_rate_); -} - -inline float SyntheticSnareDrum::DistortedSine(float phase) -{ - float triangle = (phase < 0.5f ? phase : 1.0f - phase) * 4.0f - 1.3f; - return 2.0f * triangle / (1.0f + fabsf(triangle)); -} - -bool even = true; - -float SyntheticSnareDrum::Process(bool trigger) -{ - const float decay_xt = decay_ * (1.0f + decay_ * (decay_ - 1.0f)); - const float drum_decay - = 1.0f - - 1.0f / (0.015f * sample_rate_) - * powf(2.f, - kOneTwelfth - * (-decay_xt * 72.0f - fm_amount_ * 12.0f - + snappy_ * 7.0f)); - - const float snare_decay - = 1.0f - - 1.0f / (0.01f * sample_rate_) - * powf(2.f, kOneTwelfth * (-decay_ * 60.0f - snappy_ * 7.0f)); - const float fm_decay = 1.0f - 1.0f / (0.007f * sample_rate_); - - float snappy = snappy_ * 1.1f - 0.05f; - snappy = fclamp(snappy, 0.0f, 1.0f); - - const float drum_level = sqrtf(1.0f - snappy); - const float snare_level = sqrtf(snappy); - - const float snare_f_min = fmin(10.0f * f0_, 0.5f); - const float snare_f_max = fmin(35.0f * f0_, 0.5f); - - snare_hp_.SetFreq(snare_f_min * sample_rate_); - snare_lp_.SetFreq(snare_f_max * sample_rate_); - snare_lp_.SetRes(0.5f + 2.0f * snappy); - - drum_lp_.SetFreq(3.0f * f0_ * sample_rate_); - - if(trigger || trig_) - { - trig_ = false; - snare_amplitude_ = drum_amplitude_ = 0.3f + 0.7f * accent_; - fm_ = 1.0f; - phase_[0] = phase_[1] = 0.0f; - hold_counter_ - = static_cast((0.04f + decay_ * 0.03f) * sample_rate_); - } - - even = !even; - if(sustain_) - { - sustain_gain_ = snare_amplitude_ = accent_ * decay_; - drum_amplitude_ = snare_amplitude_; - fm_ = 0.0f; - } - else - { - // Compute all D envelopes. - // The envelope for the drum has a very long tail. - // The envelope for the snare has a "hold" stage which lasts between - // 40 and 70 ms - drum_amplitude_ - *= (drum_amplitude_ > 0.03f || even) ? drum_decay : 1.0f; - if(hold_counter_) - { - --hold_counter_; - } - else - { - snare_amplitude_ *= snare_decay; - } - fm_ *= fm_decay; - } - - // The 909 circuit has a funny kind of oscillator coupling - the signal - // leaving Q40's collector and resetting all oscillators allow some - // intermodulation. - float reset_noise = 0.0f; - float reset_noise_amount = (0.125f - f0_) * 8.0f; - reset_noise_amount = fclamp(reset_noise_amount, 0.0f, 1.0f); - reset_noise_amount *= reset_noise_amount; - reset_noise_amount *= fm_amount_; - reset_noise += phase_[0] > 0.5f ? -1.0f : 1.0f; - reset_noise += phase_[1] > 0.5f ? -1.0f : 1.0f; - reset_noise *= reset_noise_amount * 0.025f; - - float f = f0_ * (1.0f + fm_amount_ * (4.0f * fm_)); - phase_[0] += f; - phase_[1] += f * 1.47f; - if(reset_noise_amount > 0.1f) - { - if(phase_[0] >= 1.0f + reset_noise) - { - phase_[0] = 1.0f - phase_[0]; - } - if(phase_[1] >= 1.0f + reset_noise) - { - phase_[1] = 1.0f - phase_[1]; - } - } - else - { - if(phase_[0] >= 1.0f) - { - phase_[0] -= 1.0f; - } - if(phase_[1] >= 1.0f) - { - phase_[1] -= 1.0f; - } - } - - float drum = -0.1f; - drum += DistortedSine(phase_[0]) * 0.60f; - drum += DistortedSine(phase_[1]) * 0.25f; - drum *= drum_amplitude_ * drum_level; - - drum_lp_.Process(drum); - drum = drum_lp_.Low(); - - float noise = rand() * kRandFrac; - snare_lp_.Process(noise); - float snare = snare_lp_.Low(); - snare_hp_.Process(snare); - snare = snare_hp_.High(); - snare = (snare + 0.1f) * (snare_amplitude_ + fm_) * snare_level; - - return snare + drum; // It's a snare, it's a drum, it's a snare drum. -} - -void SyntheticSnareDrum::Trig() -{ - trig_ = true; -} - -void SyntheticSnareDrum::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void SyntheticSnareDrum::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void SyntheticSnareDrum::SetFreq(float f0) -{ - f0 /= sample_rate_; - f0_ = fclamp(f0, 0.f, 1.f); -} - -void SyntheticSnareDrum::SetFmAmount(float fm_amount) -{ - fm_amount = fclamp(fm_amount, 0.f, 1.f); - fm_amount_ = fm_amount * fm_amount; -} - -void SyntheticSnareDrum::SetDecay(float decay) -{ - decay_ = fmax(decay, 0.f); -} - -void SyntheticSnareDrum::SetSnappy(float snappy) -{ - snappy_ = fclamp(snappy, 0.f, 1.f); -} diff --git a/src/daisysp/Drums/synthsnaredrum.h b/src/daisysp/Drums/synthsnaredrum.h deleted file mode 100644 index db5404e..0000000 --- a/src/daisysp/Drums/synthsnaredrum.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SYNTHSD_H -#define DSY_SYNTHSD_H - -#include "../Filters/svf.h" - -#include -#ifdef __cplusplus - -/** @file synthsnaredrum.h */ - -namespace daisysp -{ -/** - @brief Naive snare drum model (two modulated oscillators + filtered noise). - @author Ben Sergentanis - @date Jan 2021 - Uses a few magic numbers taken from the 909 schematics: \n - - Ratio between the two modes of the drum set to 1.47. \n - - Funky coupling between the two modes. \n - - Noise coloration filters and envelope shapes for the snare. \n \n - Ported from pichenettes/eurorack/plaits/dsp/drums/synthetic_snare_drum.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SyntheticSnareDrum -{ - public: - SyntheticSnareDrum() {} - ~SyntheticSnareDrum() {} - - /** Init the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next sample. - \param trigger True = hit the drum. This argument is optional. - */ - float Process(bool trigger = false); - - /** Trigger the drum */ - void Trig(); - - /** Make the drum ring out infinitely. - \param sustain True = infinite sustain. - */ - void SetSustain(bool sustain); - - /** Set how much accent to use - \param accent Works 0-1. - */ - void SetAccent(float accent); - - /** Set the drum's root frequency - \param f0 Freq in Hz - */ - void SetFreq(float f0); - - /** Set the amount of fm sweep. - \param fm_amount Works from 0 - 1. - */ - void SetFmAmount(float fm_amount); - - /** Set the length of the drum decay - \param decay Works with positive numbers - */ - void SetDecay(float decay); - - /** Sets the mix between snare and drum. - \param snappy 1 = just snare. 0 = just drum. - */ - void SetSnappy(float snappy); - - private: - inline float DistortedSine(float phase); - - float sample_rate_; - - bool trig_; - bool sustain_; - float accent_, f0_, fm_amount_, decay_, snappy_; - - float phase_[2]; - float drum_amplitude_; - float snare_amplitude_; - float fm_; - float sustain_gain_; - int hold_counter_; - - Svf drum_lp_; - Svf snare_hp_; - Svf snare_lp_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Dynamics/crossfade.cpp b/src/daisysp/Dynamics/crossfade.cpp deleted file mode 100644 index 67d03eb..0000000 --- a/src/daisysp/Dynamics/crossfade.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "crossfade.h" -#include "../Utility/dsp.h" - -#define REALLYSMALLFLOAT 0.000001f - -using namespace daisysp; - -const float kCrossLogMin = logf(REALLYSMALLFLOAT); -const float kCrossLogMax = logf(1.0f); - -float CrossFade::Process(float &in1, float &in2) -{ - float scalar_1, scalar_2; - switch(curve_) - { - case CROSSFADE_LIN: - scalar_1 = pos_; - return (in1 * (1.0f - scalar_1)) + (in2 * scalar_1); - - case CROSSFADE_CPOW: - scalar_1 = sinf(pos_ * HALFPI_F); - scalar_2 = sinf((1.0f - pos_) * HALFPI_F); - return (in1 * scalar_2) + (in2 * scalar_1); - - case CROSSFADE_LOG: - scalar_1 - = expf(pos_ * (kCrossLogMax - kCrossLogMin) + kCrossLogMin); - return (in1 * (1.0f - scalar_1)) + (in2 * scalar_1); - - case CROSSFADE_EXP: - scalar_1 = pos_ * pos_; - return (in1 * (1.0f - scalar_1)) + (in2 * scalar_1); - - default: return 0; - } -} diff --git a/src/daisysp/Dynamics/crossfade.h b/src/daisysp/Dynamics/crossfade.h deleted file mode 100644 index 3672b78..0000000 --- a/src/daisysp/Dynamics/crossfade.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_CROSSFADE_H -#define DSY_CROSSFADE_H -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Curve applied to the CrossFade -- LIN = linear -- CPOW = constant power -- LOG = logarithmic -- EXP exponential -- LAST = end of enum (used for array indexing) -*/ -enum -{ - CROSSFADE_LIN, - CROSSFADE_CPOW, - CROSSFADE_LOG, - CROSSFADE_EXP, - CROSSFADE_LAST, -}; - -/** Performs a CrossFade between two signals - - Original author: Paul Batchelor - - Ported from Soundpipe by Andrew Ikenberry - - added curve option for constant power, etc. -*/ -class CrossFade -{ - public: - CrossFade() {} - ~CrossFade() {} - /** Initializes CrossFade module - Defaults - - current position = .5 - - curve = linear - */ - inline void Init(int curve) - { - pos_ = 0.5f; - curve_ = curve < CROSSFADE_LAST ? curve : CROSSFADE_LIN; - } - - /** Initialize with default linear curve - */ - inline void Init() { Init(CROSSFADE_LIN); } - /** processes CrossFade and returns single sample - */ - float Process(float &in1, float &in2); - - - /** Sets position of CrossFade between two input signals - Input range: 0 to 1 - */ - inline void SetPos(float pos) { pos_ = pos; } - /** Sets current curve applied to CrossFade - Expected input: See [Curve Options](##curve-options) - */ - inline void SetCurve(uint8_t curve) { curve_ = curve; } - /** Returns current position - */ - inline float GetPos(float pos) { return pos_; } - /** Returns current curve - */ - inline uint8_t GetCurve(uint8_t curve) { return curve_; } - - private: - float pos_; - uint8_t curve_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Dynamics/limiter.cpp b/src/daisysp/Dynamics/limiter.cpp deleted file mode 100644 index 03494fe..0000000 --- a/src/daisysp/Dynamics/limiter.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "../Utility/dsp.h" -#include "limiter.h" - -#define SLOPE(out, in, positive, negative) \ - { \ - float error = (in)-out; \ - out += (error > 0 ? positive : negative) * error; \ - } - -namespace daisysp -{ -void Limiter::Init() -{ - peak_ = 0.5f; -} - -void Limiter::ProcessBlock(float *in, size_t size, float pre_gain) -{ - while(size--) - { - float pre = *in * pre_gain; - float peak = fabsf(pre); - SLOPE(peak_, peak, 0.05f, 0.00002f); - float gain = (peak_ <= 1.0f ? 1.0f : 1.0f / peak_); - *in++ = SoftLimit(pre * gain * 0.7f); - } -} - -} //namespace daisysp \ No newline at end of file diff --git a/src/daisysp/Dynamics/limiter.h b/src/daisysp/Dynamics/limiter.h deleted file mode 100644 index 2c539d5..0000000 --- a/src/daisysp/Dynamics/limiter.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef LIMITER_H -#define LIMITER_H -#include -namespace daisysp -{ -/** Simple Peak Limiter - -This was extracted from pichenettes/stmlib. - -Credit to pichenettes/Mutable Instruments -*/ -class Limiter -{ - public: - Limiter() {} - ~Limiter() {} - /** Initializes the Limiter instance. - */ - void Init(); - - /** Processes a block of audio through the limiter. - \param in - pointer to a block of audio samples to be processed. The buffer is operated on directly. - \param size - size of the buffer "in" - \param pre_gain - amount of pre_gain applied to the signal. - */ - void ProcessBlock(float *in, size_t size, float pre_gain); - - private: - float peak_; -}; -} // namespace daisysp -#endif diff --git a/src/daisysp/Effects/autowah.cpp b/src/daisysp/Effects/autowah.cpp deleted file mode 100644 index 42e5193..0000000 --- a/src/daisysp/Effects/autowah.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "autowah.h" -#include - -using namespace daisysp; - - -void Autowah::Init(float sample_rate) -{ - sampling_freq_ = sample_rate; - const1_ = 1413.72f / sampling_freq_; - const2_ = expf(0.0f - (100.0f / sampling_freq_)); - const4_ = expf(0.0f - (10.0f / sampling_freq_)); - - wet_dry_ = 100.0f; - level_ = 0.1f; - wah_ = 0.0; - - - for(int i = 0; i < 2; i++) - { - rec1_[i] = rec2_[i] = rec3_[i] = rec4_[i] = rec5_[i] = 0.0f; - } - - for(int i = 0; i < 3; i++) - { - rec0_[i] = 0.0f; - } -} - -float Autowah::Process(float in) -{ - float out; - float fSlow2 = (0.01f * (wet_dry_ * level_)); - float fSlow3 = (1.0f - 0.01f * wet_dry_) + (1.f - wah_); - - float fTemp1 = fabs(in); - rec3_[0] - = fmaxf(fTemp1, (const4_ * rec3_[1]) + ((1.0f - const4_) * fTemp1)); - rec2_[0] = (const2_ * rec2_[1]) + ((1.0f - const2_) * rec3_[0]); - float fTemp2 = fminf(1.0f, rec2_[0]); - float fTemp3 = powf(2.0f, (2.3f * fTemp2)); - float fTemp4 - = 1.0f - - (const1_ * fTemp3 / powf(2.0f, (1.0f + 2.0f * (1.0f - fTemp2)))); - rec1_[0] - = ((0.999f * rec1_[1]) - + (0.001f - * (0.0f - (2.0f * (fTemp4 * cosf((const1_ * 2 * fTemp3))))))); - rec4_[0] = ((0.999f * rec4_[1]) + (0.001f * fTemp4 * fTemp4)); - rec5_[0] = ((0.999f * rec5_[1]) + (0.0001f * powf(4.0f, fTemp2))); - rec0_[0] = (0.0f - - (((rec1_[0] * rec0_[1]) + (rec4_[0] * rec0_[2])) - - (fSlow2 * (rec5_[0] * in)))); - - out = ((wah_ * (rec0_[0] - rec0_[1])) + (fSlow3 * in)); - rec3_[1] = rec3_[0]; - rec2_[1] = rec2_[0]; - rec1_[1] = rec1_[0]; - rec4_[1] = rec4_[0]; - rec5_[1] = rec5_[0]; - rec0_[2] = rec0_[1]; - rec0_[1] = rec0_[0]; - - return out; -} diff --git a/src/daisysp/Effects/autowah.h b/src/daisysp/Effects/autowah.h deleted file mode 100644 index 580a725..0000000 --- a/src/daisysp/Effects/autowah.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_AUTOWAH_H -#define DSY_AUTOWAH_H - -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Autowah module - - Original author(s) : - - Ported from soundpipe by Ben Sergentanis, May 2020 -*/ -class Autowah -{ - public: - Autowah() {} - ~Autowah() {} - /** Initializes the Autowah module. - \param sample_rate - The sample rate of the audio engine being run. - */ - void Init(float sample_rate); - - - /** Initializes the Autowah module. - \param in - input signal to be wah'd - */ - float Process(float in); - - - /** sets wah - \param wah : set wah amount, , 0...1.0 - */ - inline void SetWah(float wah) { wah_ = wah; } - /** sets mix amount - \param drywet : set effect dry/wet, 0...100.0 - */ - inline void SetDryWet(float drywet) { wet_dry_ = drywet; } - /** sets wah level - \param level : set wah level, 0...1.0 - */ - inline void SetLevel(float level) { level_ = level; } - - private: - float sampling_freq_, const1_, const2_, const4_, wah_, level_, wet_dry_, - rec0_[3], rec1_[2], rec2_[2], rec3_[2], rec4_[2], rec5_[2]; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/chorus.cpp b/src/daisysp/Effects/chorus.cpp deleted file mode 100644 index d0031e9..0000000 --- a/src/daisysp/Effects/chorus.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "../Utility/dsp.h" -#include "chorus.h" -#include - -using namespace daisysp; - -//ChorusEngine stuff -void ChorusEngine::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - del_.Init(); - lfo_amp_ = 0.f; - feedback_ = .2f; - SetDelay(.75); - - lfo_phase_ = 0.f; - SetLfoFreq(.3f); - SetLfoDepth(.9f); -} - -float ChorusEngine::Process(float in) -{ - float lfo_sig = ProcessLfo(); - del_.SetDelay(lfo_sig + delay_); - - float out = del_.Read(); - del_.Write(in + out * feedback_); - - return (in + out) * .5f; //equal mix -} - -void ChorusEngine::SetLfoDepth(float depth) -{ - depth = fclamp(depth, 0.f, .93f); - lfo_amp_ = depth * delay_; -} - -void ChorusEngine::SetLfoFreq(float freq) -{ - freq = 4.f * freq / sample_rate_; - freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going - lfo_freq_ = fclamp(freq, -.25f, .25f); //clip at +/- .125 * sr -} - -void ChorusEngine::SetDelay(float delay) -{ - delay = (.1f + delay * 7.9f); //.1 to 8 ms - SetDelayMs(delay); -} - -void ChorusEngine::SetDelayMs(float ms) -{ - ms = fmax(.1f, ms); - delay_ = ms * .001f * sample_rate_; //ms to samples - - lfo_amp_ = fmin(lfo_amp_, delay_); //clip this if needed -} - -void ChorusEngine::SetFeedback(float feedback) -{ - feedback_ = fclamp(feedback, 0.f, 1.f); -} - -float ChorusEngine::ProcessLfo() -{ - lfo_phase_ += lfo_freq_; - - //wrap around and flip direction - if(lfo_phase_ > 1.f) - { - lfo_phase_ = 1.f - (lfo_phase_ - 1.f); - lfo_freq_ *= -1.f; - } - else if(lfo_phase_ < -1.f) - { - lfo_phase_ = -1.f - (lfo_phase_ + 1.f); - lfo_freq_ *= -1.f; - } - - return lfo_phase_ * lfo_amp_; -} - -//Chorus Stuff -void Chorus::Init(float sample_rate) -{ - engines_[0].Init(sample_rate); - engines_[1].Init(sample_rate); - SetPan(.25f, .75f); - - gain_frac_ = .5f; - sigl_ = sigr_ = 0.f; -} - -float Chorus::Process(float in) -{ - sigl_ = 0.f; - sigr_ = 0.f; - - for(int i = 0; i < 2; i++) - { - float sig = engines_[i].Process(in); - sigl_ += (1.f - pan_[i]) * sig; - sigr_ += pan_[i] * sig; - } - - sigl_ *= gain_frac_; - sigr_ *= gain_frac_; - - return sigl_; -} - -float Chorus::GetLeft() -{ - return sigl_; -} - -float Chorus::GetRight() -{ - return sigr_; -} - -void Chorus::SetPan(float panl, float panr) -{ - pan_[0] = fclamp(panl, 0.f, 1.f); - pan_[1] = fclamp(panr, 0.f, 1.f); -} - -void Chorus::SetPan(float pan) -{ - SetPan(pan, pan); -} - -void Chorus::SetLfoDepth(float depthl, float depthr) -{ - engines_[0].SetLfoDepth(depthl); - engines_[1].SetLfoDepth(depthr); -} - -void Chorus::SetLfoDepth(float depth) -{ - SetLfoDepth(depth, depth); -} - -void Chorus::SetLfoFreq(float freql, float freqr) -{ - engines_[0].SetLfoFreq(freql); - engines_[1].SetLfoFreq(freqr); -} - -void Chorus::SetLfoFreq(float freq) -{ - SetLfoFreq(freq, freq); -} - -void Chorus::SetDelay(float delayl, float delayr) -{ - engines_[0].SetDelay(delayl); - engines_[1].SetDelay(delayr); -} - -void Chorus::SetDelay(float delay) -{ - SetDelay(delay, delay); -} - -void Chorus::SetDelayMs(float msl, float msr) -{ - engines_[0].SetDelayMs(msl); - engines_[1].SetDelayMs(msr); -} - -void Chorus::SetDelayMs(float ms) -{ - SetDelayMs(ms, ms); -} - -void Chorus::SetFeedback(float feedbackl, float feedbackr) -{ - engines_[0].SetFeedback(feedbackl); - engines_[1].SetFeedback(feedbackr); -} - -void Chorus::SetFeedback(float feedback) -{ - SetFeedback(feedback, feedback); -} diff --git a/src/daisysp/Effects/chorus.h b/src/daisysp/Effects/chorus.h deleted file mode 100644 index ebbd51a..0000000 --- a/src/daisysp/Effects/chorus.h +++ /dev/null @@ -1,190 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_CHORUS_H -#define DSY_CHORUS_H -#ifdef __cplusplus - -#include -#include "../Utility/delayline.h" - -/** @file chorus.h */ - -namespace daisysp -{ -/** - @brief Single Chorus engine. Used in Chorus. - @author Ben Sergentanis -*/ -class ChorusEngine -{ - public: - ChorusEngine() {} - ~ChorusEngine() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get the next sample - \param in Sample to process - */ - float Process(float in); - - /** How much to modulate the delay by. - \param depth Works 0-1. - */ - void SetLfoDepth(float depth); - - /** Set lfo frequency. - \param freq Frequency in Hz - */ - void SetLfoFreq(float freq); - - /** Set the internal delay rate. - \param delay Tuned for 0-1. Maps to .1 to 50 ms. - */ - void SetDelay(float delay); - - /** Set the delay time in ms. - \param ms Delay time in ms, 0 to 50 ms. - */ - void SetDelayMs(float ms); - - /** Set the feedback amount. - \param feedback Amount from 0-1. - */ - void SetFeedback(float feedback); - - private: - float sample_rate_; - static constexpr int32_t kDelayLength - = 2400; // 50 ms at 48kHz = .05 * 48000 - - //triangle lfos - float lfo_phase_; - float lfo_freq_; - float lfo_amp_; - - float feedback_; - - float delay_; - - DelayLine del_; - - float ProcessLfo(); -}; - -//wraps up all of the chorus engines -/** - @brief Chorus Effect. - @author Ben Sergentanis - @date Jan 2021 - Based on https://www.izotope.com/en/learn/understanding-chorus-flangers-and-phasers-in-audio-production.html \n - and https://www.researchgate.net/publication/236629475_Implementing_Professional_Audio_Effects_with_DSPs \n -*/ -class Chorus -{ - public: - Chorus() {} - ~Chorus() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the net floating point sample. Defaults to left channel. - \param in Sample to process - */ - float Process(float in); - - /** Get the left channel's last sample */ - float GetLeft(); - - /** Get the right channel's last sample */ - float GetRight(); - - /** Pan both channels individually. - \param panl Pan the left channel. 0 is left, 1 is right. - \param panr Pan the right channel. - */ - void SetPan(float panl, float panr); - - /** Pan both channels. - \param pan Where to pan both channels to. 0 is left, 1 is right. - */ - void SetPan(float pan); - - /** Set both lfo depths individually. - \param depthl Left channel lfo depth. Works 0-1. - \param depthr Right channel lfo depth. - */ - void SetLfoDepth(float depthl, float depthr); - - /** Set both lfo depths. - \param depth Both channels lfo depth. Works 0-1. - */ - void SetLfoDepth(float depth); - - /** Set both lfo frequencies individually. - \param depthl Left channel lfo freq in Hz. - \param depthr Right channel lfo freq in Hz. - */ - void SetLfoFreq(float freql, float freqr); - - /** Set both lfo frequencies. - \param depth Both channel lfo freqs in Hz. - */ - void SetLfoFreq(float freq); - - /** Set both channel delay amounts individually. - \param delayl Left channel delay amount. Works 0-1. - \param delayr Right channel delay amount. - */ - void SetDelay(float delayl, float delayr); - - /** Set both channel delay amounts. - \param delay Both channel delay amount. Works 0-1. - */ - void SetDelay(float delay); - - /** Set both channel delay individually. - \param msl Left channel delay in ms. - \param msr Right channel delay in ms. - */ - void SetDelayMs(float msl, float msr); - - /** Set both channel delay in ms. - \param ms Both channel delay amounts in ms. - */ - void SetDelayMs(float ms); - - /** Set both channels feedback individually. - \param feedbackl Left channel feedback. Works 0-1. - \param feedbackr Right channel feedback. - */ - void SetFeedback(float feedbackl, float feedbackr); - - /** Set both channels feedback. - \param feedback Both channel feedback. Works 0-1. - */ - void SetFeedback(float feedback); - - private: - ChorusEngine engines_[2]; - float gain_frac_; - float pan_[2]; - - float sigl_, sigr_; -}; -} //namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Effects/decimator.cpp b/src/daisysp/Effects/decimator.cpp deleted file mode 100644 index 1713eac..0000000 --- a/src/daisysp/Effects/decimator.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "decimator.h" - -using namespace daisysp; - -void Decimator::Init() -{ - downsample_factor_ = 1.0f; - bitcrush_factor_ = 0.0f; - downsampled_ = 0.0f; - bitcrushed_ = 0.0f; - inc_ = 0; - threshold_ = 0; - smooth_crushing_ = false; - bit_overflow_ = 1.0f; -} - -float Decimator::Process(float input) -{ - int32_t temp; - //downsample - threshold_ = (uint32_t)((downsample_factor_ * downsample_factor_) * 96.0f); - inc_ += 1; - if(inc_ > threshold_) - { - inc_ = 0; - downsampled_ = input; - } - - //bitcrush - if(smooth_crushing_) - { - temp = (int32_t)(downsampled_ * 65536.0f * bit_overflow_); - temp >>= bits_to_crush_ + 1; // shift off - temp <<= bits_to_crush_ + 1; // move back with zeros - bitcrushed_ = (float)temp / (65536.0f * bit_overflow_); - } - else - { - temp = (int32_t)(downsampled_ * 65536.0f); - temp >>= bits_to_crush_; // shift off - temp <<= bits_to_crush_; // move back with zeros - bitcrushed_ = (float)temp / 65536.0f; - } - - return bitcrushed_; -} diff --git a/src/daisysp/Effects/decimator.h b/src/daisysp/Effects/decimator.h deleted file mode 100644 index ed55629..0000000 --- a/src/daisysp/Effects/decimator.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DECIMATOR_H -#define DECIMATOR_H -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Performs downsampling and bitcrush effects -*/ -class Decimator -{ - public: - Decimator() {} - ~Decimator() {} - /** Initializes downsample module - */ - void Init(); - - /** Applies downsample and bitcrush effects to input signal. - \return one sample. This should be called once per sample period. - */ - float Process(float input); - - - /** Sets amount of downsample - Input range: - */ - inline void SetDownsampleFactor(float downsample_factor) - { - downsample_factor_ = downsample_factor; - } - - /** Sets amount of bitcrushing - Input range: 0...1.0 - */ - inline void SetBitcrushFactor(float bitcrush_factor) - { - bitcrush_factor_ = bitcrush_factor; - bits_to_crush_ = (uint32_t)(bitcrush_factor * kMaxBitsToCrush); - bit_overflow_ - = 2.0f - (bitcrush_factor * 16.0f) + (float)(bits_to_crush_); - } - - /** Sets the exact number of bits to crush and disables smooth crushing - 0-16 bits - */ - inline void SetBitsToCrush(const uint8_t &bits) - { - bits_to_crush_ = bits <= kMaxBitsToCrush ? bits : kMaxBitsToCrush; - smooth_crushing_ = false; - } - - /** Sets the smooth crushing on or off - true/false - */ - inline void SetSmoothCrushing(bool smooth_crushing) - { - smooth_crushing_ = smooth_crushing; - } - - /** Returns current setting of smooth crushing - */ - inline bool GetSmoothCrushing() { return smooth_crushing_; } - /** Returns current setting of downsample - */ - inline float GetDownsampleFactor() { return downsample_factor_; } - /** Returns current setting of bitcrush - */ - inline float GetBitcrushFactor() { return bitcrush_factor_; } - /** Returns current bitcrush setting in bits - */ - inline int GetBitsToCrush() { return bits_to_crush_; } - - private: - const uint8_t kMaxBitsToCrush = 16; - float downsample_factor_, bitcrush_factor_; - uint32_t bits_to_crush_; - float downsampled_, bitcrushed_; - uint32_t inc_, threshold_; - bool smooth_crushing_; - float bit_overflow_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/flanger.cpp b/src/daisysp/Effects/flanger.cpp deleted file mode 100644 index 7b3206e..0000000 --- a/src/daisysp/Effects/flanger.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "../Utility/dsp.h" -#include "flanger.h" -#include - -using namespace daisysp; - -void Flanger::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - SetFeedback(.2f); - - del_.Init(); - lfo_amp_ = 0.f; - SetDelay(.75); - - lfo_phase_ = 0.f; - SetLfoFreq(.3); - SetLfoDepth(.9); -} - -float Flanger::Process(float in) -{ - float lfo_sig = ProcessLfo(); - del_.SetDelay(1.f + lfo_sig + delay_); - - float out = del_.Read(); - del_.Write(in + out * feedback_); - - return (in + out) * .5f; //equal mix -} - -void Flanger::SetFeedback(float feedback) -{ - feedback_ = fclamp(feedback, 0.f, 1.f); - feedback_ *= .97f; -} - -void Flanger::SetLfoDepth(float depth) -{ - depth = fclamp(depth, 0.f, .93f); - lfo_amp_ = depth * delay_; -} - -void Flanger::SetLfoFreq(float freq) -{ - freq = 4.f * freq / sample_rate_; - freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going - lfo_freq_ = fclamp(freq, -.25f, .25f); //clip at +/- .125 * sr -} - -void Flanger::SetDelay(float delay) -{ - delay = (.1f + delay * 6.9); //.1 to 7 ms - SetDelayMs(delay); -} - -void Flanger::SetDelayMs(float ms) -{ - ms = fmax(.1, ms); - delay_ = ms * .001f * sample_rate_; //ms to samples - - lfo_amp_ = fmin(lfo_amp_, delay_); //clip this if needed -} - -float Flanger::ProcessLfo() -{ - lfo_phase_ += lfo_freq_; - - //wrap around and flip direction - if(lfo_phase_ > 1.f) - { - lfo_phase_ = 1.f - (lfo_phase_ - 1.f); - lfo_freq_ *= -1.f; - } - else if(lfo_phase_ < -1.f) - { - lfo_phase_ = -1.f - (lfo_phase_ + 1.f); - lfo_freq_ *= -1.f; - } - - return lfo_phase_ * lfo_amp_; -} \ No newline at end of file diff --git a/src/daisysp/Effects/flanger.h b/src/daisysp/Effects/flanger.h deleted file mode 100644 index 2e3f499..0000000 --- a/src/daisysp/Effects/flanger.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_FLANGER_H -#define DSY_FLANGER_H -#ifdef __cplusplus - -#include -#include "../Utility/delayline.h" - -/** @file flanger.h */ - -namespace daisysp -{ -/** @brief Flanging Audio Effect - * - * Generates a modulating phase shifted copy of a signal, and recombines - * with the original to create a 'flanging' sound effect. - */ -class Flanger -{ - public: - /** Initialize the modules - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get the next sample - \param in Sample to process - */ - float Process(float in); - - /** How much of the signal to feedback into the delay line. - \param feedback Works 0-1. - */ - void SetFeedback(float feedback); - - /** How much to modulate the delay by. - \param depth Works 0-1. - */ - void SetLfoDepth(float depth); - - /** Set lfo frequency. - \param freq Frequency in Hz - */ - void SetLfoFreq(float freq); - - /** Set the internal delay rate. - \param delay Tuned for 0-1. Maps to .1 to 7 ms. - */ - void SetDelay(float delay); - - /** Set the delay time in ms. - \param ms Delay time in ms, .1 to 7 ms. - */ - void SetDelayMs(float ms); - - private: - float sample_rate_; - static constexpr int32_t kDelayLength = 960; // 20 ms at 48kHz = .02 * 48000 - - float feedback_; - - //triangle lfos - float lfo_phase_; - float lfo_freq_; - float lfo_amp_; - - float delay_; - - DelayLine del_; - - float ProcessLfo(); -}; -} //namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/overdrive.cpp b/src/daisysp/Effects/overdrive.cpp deleted file mode 100644 index d16ddad..0000000 --- a/src/daisysp/Effects/overdrive.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "../Utility/dsp.h" -#include "overdrive.h" -#include - -namespace daisysp -{ -void Overdrive::Init() -{ - SetDrive(.5f); -} - -float Overdrive::Process(float in) -{ - float pre = pre_gain_ * in; - return SoftClip(pre) * post_gain_; -} - -void Overdrive::SetDrive(float drive) -{ - drive = fclamp(drive, 0.f, 1.f); - drive_ = 2.f * drive; - - const float drive_2 = drive_ * drive_; - const float pre_gain_a = drive_ * 0.5f; - const float pre_gain_b = drive_2 * drive_2 * drive_ * 24.0f; - pre_gain_ = pre_gain_a + (pre_gain_b - pre_gain_a) * drive_2; - - const float drive_squashed = drive_ * (2.0f - drive_); - post_gain_ = 1.0f / SoftClip(0.33f + drive_squashed * (pre_gain_ - 0.33f)); -} - -} // namespace daisysp \ No newline at end of file diff --git a/src/daisysp/Effects/overdrive.h b/src/daisysp/Effects/overdrive.h deleted file mode 100644 index dafea3e..0000000 --- a/src/daisysp/Effects/overdrive.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_OVERDRIVE_H -#define DSY_OVERDRIVE_H - -#include -#ifdef __cplusplus - -/** @file overdrive.h */ - -namespace daisysp -{ -/** - @brief Distortion / Overdrive Module - @author Ported by Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/fx/overdrive.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2014. \n -*/ -class Overdrive -{ - public: - Overdrive() {} - ~Overdrive() {} - - /** Initializes the module with 0 gain */ - void Init(); - - /** Get the next sample - \param in Input to be overdriven - */ - float Process(float in); - - /** Set the amount of drive - \param drive Works from 0-1 - */ - void SetDrive(float drive); - - private: - float drive_; - float pre_gain_; - float post_gain_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Effects/phaser.cpp b/src/daisysp/Effects/phaser.cpp deleted file mode 100644 index da9c2d5..0000000 --- a/src/daisysp/Effects/phaser.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "../Utility/dsp.h" -#include "phaser.h" -#include - -using namespace daisysp; - -//PhaserEngine stuff -void PhaserEngine::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - del_.Init(); - lfo_amp_ = 0.f; - feedback_ = .2f; - SetFreq(200.f); - - del_.SetDelay(0.f); - - os_ = 30.f; //30 hertz frequency offset, lower than this introduces crunch - deltime_ = 0.f; - - last_sample_ = 0.f; - lfo_phase_ = 0.f; - SetLfoFreq(.3); - SetLfoDepth(.9); -} - -float PhaserEngine::Process(float in) -{ - float lfo_sig = ProcessLfo(); - fonepole(deltime_, sample_rate_ / (lfo_sig + ap_freq_ + os_), .0001f); - - last_sample_ = del_.Allpass(in + feedback_ * last_sample_, deltime_, .3f); - - return (in + last_sample_) * .5f; //equal mix -} - -void PhaserEngine::SetLfoDepth(float depth) -{ - lfo_amp_ = fclamp(depth, 0.f, 1.f); -} - -void PhaserEngine::SetLfoFreq(float lfo_freq) -{ - lfo_freq = 4.f * lfo_freq / sample_rate_; - lfo_freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going - lfo_freq_ = fclamp(lfo_freq, -.25f, .25f); //clip at +/- .125 * sr -} - -void PhaserEngine::SetFreq(float ap_freq) -{ - ap_freq_ = fclamp(ap_freq, 0.f, 20000.f); //0 - 20kHz -} - -void PhaserEngine::SetFeedback(float feedback) -{ - feedback_ = fclamp(feedback, 0.f, .75f); -} - -float PhaserEngine::ProcessLfo() -{ - lfo_phase_ += lfo_freq_; - - //wrap around and flip direction - if(lfo_phase_ > 1.f) - { - lfo_phase_ = 1.f - (lfo_phase_ - 1.f); - lfo_freq_ *= -1.f; - } - else if(lfo_phase_ < -1.f) - { - lfo_phase_ = -1.f - (lfo_phase_ + 1.f); - lfo_freq_ *= -1.f; - } - - return lfo_phase_ * lfo_amp_ * ap_freq_; -} - -//Phaser Stuff -void Phaser::Init(float sample_rate) -{ - for(size_t i = 0; i < kMaxPoles; i++) - { - engines_[i].Init(sample_rate); - } - - poles_ = 4; - gain_frac_ = .5f; -} - -float Phaser::Process(float in) -{ - float sig = 0.f; - - for(int i = 0; i < poles_; i++) - { - sig += engines_[i].Process(in); - } - - return sig; -} - -void Phaser::SetPoles(int poles) -{ - poles_ = DSY_CLAMP(poles, 1, 8); -} - -void Phaser::SetLfoDepth(float depth) -{ - for(int i = 0; i < kMaxPoles; i++) - { - engines_[i].SetLfoDepth(depth); - } -} - -void Phaser::SetLfoFreq(float lfo_freq) -{ - for(int i = 0; i < kMaxPoles; i++) - { - engines_[i].SetLfoFreq(lfo_freq); - } -} - -void Phaser::SetFreq(float ap_freq) -{ - for(int i = 0; i < kMaxPoles; i++) - { - engines_[i].SetFreq(ap_freq); - } -} - -void Phaser::SetFeedback(float feedback) -{ - for(int i = 0; i < kMaxPoles; i++) - { - engines_[i].SetFeedback(feedback); - } -} diff --git a/src/daisysp/Effects/phaser.h b/src/daisysp/Effects/phaser.h deleted file mode 100644 index 77c99f4..0000000 --- a/src/daisysp/Effects/phaser.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_PHASER_H -#define DSY_PHASER_H -#ifdef __cplusplus - -#include -#include "../Utility/delayline.h" - -/** @file phaser.h */ - -namespace daisysp -{ -/** - @brief Single Phaser engine. Used in Phaser. - @author Ben Sergentanis -*/ -class PhaserEngine -{ - public: - PhaserEngine() {} - ~PhaserEngine() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get the next sample - \param in Sample to process - */ - float Process(float in); - - /** How much to modulate the allpass filter by. - \param depth Works 0-1. - */ - void SetLfoDepth(float depth); - - /** Set lfo frequency. - \param lfo_freq Frequency in Hz - */ - void SetLfoFreq(float lfo_freq); - - /** Set the allpass frequency - \param ap_freq Frequency in Hz. - */ - void SetFreq(float ap_freq); - - /** Set the feedback amount. - \param feedback Amount from 0-1. - */ - void SetFeedback(float feedback); - - private: - float sample_rate_; - static constexpr int32_t kDelayLength - = 2400; // 50 ms at 48kHz = .05 * 48000 - - //triangle lfo - float lfo_phase_; - float lfo_freq_; - float lfo_amp_; - - float os_; - - float feedback_; - float ap_freq_; - - float deltime_; - float last_sample_; - - DelayLine del_; - - float ProcessLfo(); -}; - -//wraps up all of the phaser engines -/** - @brief Phaser Effect. - @author Ben Sergentanis - @date Jan 2021 -*/ -class Phaser -{ - public: - Phaser() {} - ~Phaser() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next floating point sample. - \param in Sample to process - */ - float Process(float in); - - /** Number of allpass stages. - \param poles Works 1 to 8. - */ - void SetPoles(int poles); - - /** Set all lfo depths - \param depth Works 0-1. - */ - void SetLfoDepth(float depth); - - /** Set all lfo frequencies. - \param lfo_freq Lfo freq in Hz. - */ - void SetLfoFreq(float lfo_freq); - - /** Set all channel allpass freq in Hz. - \param ap_freq Frequency in Hz. - */ - void SetFreq(float ap_freq); - - /** Set all channels feedback. - \param feedback Works 0-1. - */ - void SetFeedback(float feedback); - - private: - static constexpr int kMaxPoles = 8; - PhaserEngine engines_[kMaxPoles]; - float gain_frac_; - int poles_; -}; -} //namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/pitchshifter.h b/src/daisysp/Effects/pitchshifter.h deleted file mode 100644 index d07daee..0000000 --- a/src/daisysp/Effects/pitchshifter.h +++ /dev/null @@ -1,225 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_PITCHSHIFTER_H -#define DSY_PITCHSHIFTER_H -#include -#include -#ifdef USE_ARM_DSP -#include "arm_math.h" -#endif -#include "../Utility/dsp.h" -#include "../Utility/delayline.h" -#include "../Control/phasor.h" - -/** Shift can be 30-100 ms lets just start with 50 for now. -0.050 * SR = 2400 samples (at 48kHz) -*/ -// #define SHIFT_BUFFER_SIZE 16384 -// #define SHIFT_BUFFER_SIZE 4800 -#define SHIFT_BUFFER_SIZE 8192 -//#define SHIFT_BUFFER_SIZE 1024 - -namespace daisysp -{ -static inline uint32_t hash_xs32(uint32_t x) -{ - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - return x; -} - -inline uint32_t myrand() -{ - static uint32_t seed = 1; - seed = hash_xs32(seed); - return seed; -} - -/** time-domain pitchshifter - -Author: shensley - -Based on "Pitch Shifting" from ucsd.edu - -t = 1 - ((s *f) / R) - -where: - s is the size of the delay - f is the frequency of the lfo - r is the sample_rate - -solving for t = 12.0 -f = (12 - 1) * 48000 / SHIFT_BUFFER_SIZE; - -\todo - move hash_xs32 and myrand to dsp.h and give appropriate names -*/ -class PitchShifter -{ - public: - PitchShifter() {} - ~PitchShifter() {} - /** Initialize pitch shifter - */ - void Init(float sr) - { - force_recalc_ = false; - sr_ = sr; - mod_freq_ = 5.0f; - SetSemitones(); - for(uint8_t i = 0; i < 2; i++) - { - gain_[i] = 0.0f; - d_[i].Init(); - phs_[i].Init(sr, 50, i == 0 ? 0 : PI_F); - } - shift_up_ = true; - del_size_ = SHIFT_BUFFER_SIZE; - SetDelSize(del_size_); - fun_ = 0.0f; - - // Reset slewed_mod - for (size_t n = 0; n < 2; n++) { - slewed_mod_[n] = 0; - mod_coeff_[n] = 0; - } - } - - /** process pitch shifter - */ - float Process(float &in) - { - float val, fade1, fade2; - // First Process delay mod/crossfade - fade1 = phs_[0].Process(); - fade2 = phs_[1].Process(); - if(prev_phs_a_ > fade1) - { - mod_a_amt_ = fun_ * ((float)(myrand() % 255) / 255.0f) - * (del_size_ * 0.5f); - mod_coeff_[0] - = 0.0002f + (((float)(myrand() % 255) / 255.0f) * 0.001f); - } - if(prev_phs_b_ > fade2) - { - mod_b_amt_ = fun_ * ((float)(myrand() % 255) / 255.0f) - * (del_size_ * 0.5f); - mod_coeff_[1] - = 0.0002f + (((float)(myrand() % 255) / 255.0f) * 0.001f); - } - slewed_mod_[0] += mod_coeff_[0] * (mod_a_amt_ - slewed_mod_[0]); - slewed_mod_[1] += mod_coeff_[1] * (mod_b_amt_ - slewed_mod_[1]); - prev_phs_a_ = fade1; - prev_phs_b_ = fade2; - if(shift_up_) - { - fade1 = 1.0f - fade1; - fade2 = 1.0f - fade2; - } - mod_[0] = fade1 * (del_size_ - 1); - mod_[1] = fade2 * (del_size_ - 1); -#ifdef USE_ARM_DSP - gain_[0] = arm_sin_f32(fade1 * (float)M_PI); - gain_[1] = arm_sin_f32(fade2 * (float)M_PI); -#else - gain_[0] = sinf(fade1 * PI_F); - gain_[1] = sinf(fade2 * PI_F); -#endif - - // Handle Delay Writing - d_[0].Write(in); - d_[1].Write(in); - // Modulate Delay Lines - //mod_a_amt = mod_b_amt = 0.0f; - d_[0].SetDelay(mod_[0] + mod_a_amt_); - d_[1].SetDelay(mod_[1] + mod_b_amt_); - d_[0].SetDelay(mod_[0] + slewed_mod_[0]); - d_[1].SetDelay(mod_[1] + slewed_mod_[1]); - val = 0.0f; - val += (d_[0].Read() * gain_[0]); - val += (d_[1].Read() * gain_[1]); - return val; - } - - /** sets transposition in semitones - */ - void SetTransposition(const float &transpose) - { - float ratio; - uint8_t idx; - if(transpose_ != transpose || force_recalc_) - { - transpose_ = transpose; - idx = (uint8_t)fabsf(transpose); - ratio = semitone_ratios_[idx % 12]; - ratio *= (uint8_t)(fabsf(transpose) / 12) + 1; - if(transpose > 0.0f) - { - shift_up_ = true; - } - else - { - shift_up_ = false; - } - mod_freq_ = ((ratio - 1.0f) * sr_) / del_size_; - if(mod_freq_ < 0.0f) - { - mod_freq_ = 0.0f; - } - phs_[0].SetFreq(mod_freq_); - phs_[1].SetFreq(mod_freq_); - if(force_recalc_) - { - force_recalc_ = false; - } - } - } - - /** sets delay size changing the timbre of the pitchshifting - */ - void SetDelSize(uint32_t size) - { - del_size_ = size < SHIFT_BUFFER_SIZE ? size : SHIFT_BUFFER_SIZE; - force_recalc_ = true; - SetTransposition(transpose_); - } - - /** sets an amount of internal random modulation, kind of sounds like tape-flutter - */ - inline void SetFun(float f) { fun_ = f; } - - private: - inline void SetSemitones() - { - for(size_t i = 0; i < 12; i++) - { - semitone_ratios_[i] = powf(2.0f, (float)i / 12); - } - } - typedef DelayLine ShiftDelay; - ShiftDelay d_[2]; - float pitch_shift_, mod_freq_; - uint32_t del_size_; - /** lfo stuff -*/ - bool force_recalc_; - float sr_; - bool shift_up_; - Phasor phs_[2]; - float gain_[2], mod_[2], transpose_; - float fun_, mod_a_amt_, mod_b_amt_, prev_phs_a_, prev_phs_b_; - float slewed_mod_[2], mod_coeff_[2]; - /** pitch stuff -*/ - float semitone_ratios_[12]; -}; -} // namespace daisysp - -#endif diff --git a/src/daisysp/Effects/sampleratereducer.cpp b/src/daisysp/Effects/sampleratereducer.cpp deleted file mode 100644 index 23dbd21..0000000 --- a/src/daisysp/Effects/sampleratereducer.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "../Utility/dsp.h" -#include "sampleratereducer.h" -#include - -using namespace daisysp; -void SampleRateReducer::Init() -{ - frequency_ = .2f; - phase_ = 0.0f; - sample_ = 0.0f; - next_sample_ = 0.0f; - previous_sample_ = 0.0f; -} - -float SampleRateReducer::Process(float in) -{ - float this_sample = next_sample_; - next_sample_ = 0.f; - phase_ += frequency_; - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - float t = phase_ / frequency_; - // t = 0: the transition occurred right at this sample. - // t = 1: the transition occurred at the previous sample. - // Use linear interpolation to recover the fractional sample. - float new_sample - = previous_sample_ + (in - previous_sample_) * (1.0f - t); - float discontinuity = new_sample - sample_; - this_sample += discontinuity * ThisBlepSample(t); - next_sample_ = discontinuity * NextBlepSample(t); - sample_ = new_sample; - } - next_sample_ += sample_; - previous_sample_ = in; - - return this_sample; -} - -void SampleRateReducer::SetFreq(float frequency) -{ - frequency_ = fclamp(frequency, 0.f, 1.f); -} diff --git a/src/daisysp/Effects/sampleratereducer.h b/src/daisysp/Effects/sampleratereducer.h deleted file mode 100644 index 735672b..0000000 --- a/src/daisysp/Effects/sampleratereducer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SR_REDUCER_H -#define DSY_SR_REDUCER_H - -#include -#ifdef __cplusplus - -/** @file sampleratereducer.h */ - -namespace daisysp -{ -/** - @brief Sample rate reducer. - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/fx/sample_rate_reducer.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2014. \n -*/ -class SampleRateReducer -{ - public: - SampleRateReducer() {} - ~SampleRateReducer() {} - - /** Initialize the module */ - void Init(); - - /** Get the next floating point sample - \param in Sample to be processed. - */ - float Process(float in); - - /** Set the new sample rate. - \param frequency over 0-1. 1 is full quality, .5 is half sample rate, etc. - */ - void SetFreq(float frequency); - - private: - float frequency_; - float phase_; - float sample_; - float previous_sample_; - float next_sample_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/tremolo.cpp b/src/daisysp/Effects/tremolo.cpp deleted file mode 100644 index 7fbe00a..0000000 --- a/src/daisysp/Effects/tremolo.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "tremolo.h" -#include - -using namespace daisysp; - -void Tremolo::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - osc_.Init(sample_rate_); - SetDepth(1.f); - SetFreq(1.f); -} - -float Tremolo::Process(float in) -{ - float modsig = dc_os_ + osc_.Process(); - return in * modsig; -} - -void Tremolo::SetFreq(float freq) -{ - osc_.SetFreq(freq); -} - -void Tremolo::SetWaveform(int waveform) -{ - osc_.SetWaveform(waveform); -} -void Tremolo::SetDepth(float depth) -{ - depth = fclamp(depth, 0.f, 1.f); - depth *= .5f; - osc_.SetAmp(depth); - dc_os_ = 1.f - depth; -} \ No newline at end of file diff --git a/src/daisysp/Effects/tremolo.h b/src/daisysp/Effects/tremolo.h deleted file mode 100644 index ca1c220..0000000 --- a/src/daisysp/Effects/tremolo.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_TREMOLO_H -#define DSY_TREMOLO_H - -#include -#ifdef __cplusplus - -#include -#include "../Synthesis/oscillator.h" - -/** @file tremolo.h */ - -namespace daisysp -{ -/** - @brief Tremolo effect. - @author Ben Sergentanis - @date Jan 2021 - Based on https://christianfloisand.wordpress.com/2012/04/18/coding-some-tremolo/ \n -*/ -class Tremolo -{ - public: - Tremolo() {} - ~Tremolo() {} - - /** Initializes the module - \param sample_rate The sample rate of the audio engine being run. - */ - void Init(float sample_rate); - - /** - \param in Input sample. - \return Next floating point sample. - */ - float Process(float in); - - /** Sets the tremolo rate. - \param freq Tremolo freq in Hz. - */ - void SetFreq(float freq); - - /** Shape of the modulating lfo - \param waveform Oscillator waveform. Use Oscillator::WAVE_SIN for example. - */ - void SetWaveform(int waveform); - - /** How much to modulate your volume. - \param depth Works 0-1. - */ - void SetDepth(float depth); - - - private: - float sample_rate_, dc_os_; - Oscillator osc_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Effects/wavefolder.cpp b/src/daisysp/Effects/wavefolder.cpp deleted file mode 100644 index 8d0704d..0000000 --- a/src/daisysp/Effects/wavefolder.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "wavefolder.h" -#include - -using namespace daisysp; - -void Wavefolder::Init() -{ - gain_ = 1.0f; - offset_ = 0.0f; -} - -float Wavefolder::Process(float in) -{ - float ft, sgn; - in += offset_; - in *= gain_; - ft = floorf((in + 1.0f) * 0.5f); - sgn = static_cast(ft) % 2 == 0 ? 1.0f : -1.0f; - return sgn * (in - 2.0f * ft); -} \ No newline at end of file diff --git a/src/daisysp/Effects/wavefolder.h b/src/daisysp/Effects/wavefolder.h deleted file mode 100644 index af9c457..0000000 --- a/src/daisysp/Effects/wavefolder.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Nick Donaldson - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_WAVEFOFOLDER_H -#define DSY_WAVEFOFOLDER_H - -#include -#include "../Utility/dcblock.h" -#ifdef __cplusplus - -namespace daisysp -{ -/** Basic wavefolder module. - -Amplitude of input determines level of folding. -Amplitudes of magnitude > 1.0 will start to fold. - -Original author(s) : Nick Donaldson -Year : 2022 -*/ -class Wavefolder -{ - public: - Wavefolder() {} - ~Wavefolder() {} - /** Initializes the wavefolder module. - */ - void Init(); - /** applies wavefolding to input - */ - float Process(float in); - /** - \param gain Set input gain. - Supports negative values for thru-zero - */ - inline void SetGain(float gain) { gain_ = gain; } - /** - \param offset Offset odded to input (pre-gain) for asymmetrical folding. - */ - inline void SetOffset(float offset) { offset_ = offset; } - - private: - float gain_, offset_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Filters/fir.h b/src/daisysp/Filters/fir.h deleted file mode 100644 index 1d33fee..0000000 --- a/src/daisysp/Filters/fir.h +++ /dev/null @@ -1,351 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Alexander Petrov-Savchenko - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_FIRFILTER_H -#define DSY_FIRFILTER_H - -#include -#include // for memset -#include -#include - -#ifdef USE_ARM_DSP -#include // required for platform-optimized version -#endif - -/** @brief FIR Filter implementation, generic and ARM CMSIS DSP based - * @author Alexander Petrov-Savchenko (axp@soft-amp.com) - * @date February 2021 - */ - -namespace daisysp -{ -/* use this as a template parameter to indicate user-provided memory storage */ -#define FIRFILTER_USER_MEMORY 0, 0 - -/** Helper class that defines the memory model - internal or user-provided - * \param max_size - maximal filter length - * \param max_block - maximal length of the block processing - * if both parameters are 0, does NOT allocate any memory and instead - * requires user-provided memory blocks to be passed as parameters. - * - * Not intended to be used directly, so constructor is not exposed - */ -template -struct FIRMemory -{ - /* Public part of the API to be passed through to the FIR users */ - public: - /* Reset the internal filter state (but not the coefficients) */ - void Reset() { memset(state_, 0, state_size_ * sizeof(state_[0])); } - - - protected: - FIRMemory() : state_{0}, coefs_{0}, size_(0) {} - - /* Expression for the maximum block size */ - static constexpr size_t MaxBlock() { return max_block; } - - /** Configure the filter coefficients - * \param coefs - pointer to coefficients (tail-first order) - * \param size - number of coefficients pointed by coefs (filter length) - * \param reverse - flag to perform reversing of the filter - * \return true if all conditions are met and the filter is configured - */ - bool SetCoefs(const float coefs[], size_t size, bool reverse) - { - /* truncate silently */ - size_ = DSY_MIN(size, max_size); - - if(reverse) - { - /* reverse the IR */ - for(size_t i = 0; i < size_; i++) - { - /* start from size, not size_! */ - coefs_[i] = coefs[size - 1u - i]; - } - } - else - { - /* just copy as is */ - memcpy(coefs_, coefs, size_ * sizeof(coefs[0])); - } - - return true; - } - - static constexpr size_t state_size_ = max_size + max_block - 1u; - float state_[state_size_]; /*< Internal state buffer */ - float coefs_[max_size]; /*< Filter coefficients */ - size_t size_; /*< Active filter length (<= max_size) */ -}; - -/* Specialization for user-provided memory */ -template <> -struct FIRMemory -{ - /* Public part of the API to be passed through to the FIRFilter user */ - public: - /** Set user-provided state buffer - * \param state - pointer to the allocated memory block - * \param length - length of the provided memory block (in elements) - * The length should be determined as follows - * length >= max_filter_size + max_processing_block - 1 - */ - void SetStateBuffer(float state[], size_t length) - { - state_ = state; - state_size_ = length; - } - /* Reset the internal filter state (but not the coefficients) */ - void Reset() - { - assert(nullptr != state_); - assert(0 != state_size_); - if(nullptr != state_) - { - memset(state_, 0, state_size_ * sizeof(state_[0])); - } - } - - protected: - FIRMemory() : state_(nullptr), coefs_(nullptr), size_(0), state_size_(0) {} - - /* Expression for the maximum processing block size currently supported */ - size_t MaxBlock() const - { - return state_size_ + 1u > size_ ? state_size_ + 1u - size_ : 0; - } - - /** Configure the filter coefficients - * \param coefs - pointer to coefficients (tail-first order) - * \param size - number of coefficients pointed by coefs (filter length) - * \param reverse - flag to perform reversing of the filter - * \return true if all conditions are met and the filter is configured - */ - bool SetCoefs(const float coefs[], size_t size, bool reverse) - { - /* reversing of external IR is not supported*/ - assert(false == reverse); - assert(nullptr != coefs || 0 == size); - - if(false == reverse && (nullptr != coefs || 0 == size)) - { - coefs_ = coefs; - size_ = size; - return true; - } - - return false; - } - - /* Internal member variables */ - - float* state_; /*< Internal state buffer */ - const float* coefs_; /*< Filter coefficients */ - size_t size_; /*< number of filter coefficients */ - size_t state_size_; /*< length of the state buffer */ -}; - - -/** Generic FIR implementation is always available - * \param max_size - maximal filter length - * \param max_block - maximal block size for ProcessBlock() - * if both parameters are 0 (via FIRFILTER_USER_MEMORY macro) - * Assumes the user will provide own memory buffers - * via SetIR() and SetStateBuffer() functions - * Otherwise statically allocates the necessary buffers itself - */ -template -class FIRFilterImplGeneric : public FIRMemory -{ - private: - using FIRMem = FIRMemory; // just a shorthand - - public: - /* Default constructor */ - FIRFilterImplGeneric() {} - - /* Reset filter state (but not the coefficients) */ - using FIRMem::Reset; - - /* FIR Latency is always 0, but API is unified with FFT and fast convolution */ - static constexpr size_t GetLatency() { return 0; } - - /* Process one sample at a time */ - float Process(float in) - { - assert(size_ > 0u); - /* Feed data into the buffer */ - state_[size_ - 1u] = in; - - /* Convolution loop */ - float acc(0); - for(size_t i = 0; i < size_ - 1; i++) - { - acc += state_[i] * coefs_[i]; - /** Shift the state simulatenously - * (note: better solutions are available) - */ - state_[i] = state_[1 + i]; - } - acc += in * coefs_[size_ - 1u]; - - return acc; - } - - /* Process a block of data */ - void ProcessBlock(const float* pSrc, float* pDst, size_t block) - { - /* be sure to run debug version from time to time */ - assert(block <= FIRMem::MaxBlock()); - assert(size_ > 0u); - assert(nullptr != pSrc); - assert(nullptr != pDst); - - /* Process the block of data */ - for(size_t j = 0; j < block; j++) - { - /* Feed data into the buffer */ - state_[size_ - 1u + j] = pSrc[j]; - - /* Convolution loop */ - float acc = 0.0f; - for(size_t i = 0; i < size_; i++) - { - acc += state_[j + i] * coefs_[i]; - } - - /* Write output */ - pDst[j] = acc; - } - - /* Copy data tail for the next block */ - for(size_t i = 0; i < size_ - 1u; i++) - { - state_[i] = state_[block + i]; - } - } - - /** Set filter coefficients (aka Impulse Response) - * Coefficients need to be in reversed order (tail-first) - * If internal storage is used, makes a local copy - * and allows reversing the impulse response - */ - bool SetIR(const float* ir, size_t len, bool reverse) - { - /* Function order is important */ - const bool result = FIRMem::SetCoefs(ir, len, reverse); - Reset(); - return result; - } - - /* Create an alias to comply with DaisySP API conventions */ - template - inline auto Init(Args&&... args) - -> decltype(SetIR(std::forward(args)...)) - { - return SetIR(std::forward(args)...); - } - - - protected: - using FIRMem::coefs_; /*< FIR coefficients buffer or pointer */ - using FIRMem::size_; /*< FIR length */ - using FIRMem::state_; /*< FIR state buffer or pointer */ -}; - - -#if(defined(USE_ARM_DSP) && defined(__arm__)) - -/** ARM-specific FIR implementation, expose only on __arm__ platforms - * \param max_size - maximal filter length - * \param max_block - maximal block size for ProcessBlock() - * if both parameters are 0 (via FIRFILTER_USER_MEMORY macro) - * Assumes the user will provide own memory buffers - * Otherwise statically allocates the necessary buffers - */ -template -class FIRFilterImplARM : public FIRMemory -{ - private: - using FIRMem = FIRMemory; // just a shorthand - - public: - /* Default constructor */ - FIRFilterImplARM() : fir_{0} {} - - /* Reset filter state (but not the coefficients) */ - using FIRMem::Reset; - - /* FIR Latency is always 0, but API is unified with FFT and FastConv */ - static constexpr size_t GetLatency() { return 0; } - - /* Process one sample at a time */ - float Process(float in) - { - float out(0); - arm_fir_f32(&fir_, &in, &out, 1); - return out; - } - - /* Process a block of data */ - void ProcessBlock(float* pSrc, float* pDst, size_t block) - { - assert(block <= FIRMem::MaxBlock()); - arm_fir_f32(&fir_, pSrc, pDst, block); - } - - /** Set filter coefficients (aka Impulse Response) - * Coefficients need to be in reversed order (tail-first) - * If internal storage is used, makes a local copy - * and allows reversing the impulse response - */ - bool SetIR(const float* ir, size_t len, bool reverse) - { - /* Function order is important */ - const bool result = FIRMem::SetCoefs(ir, len, reverse); - arm_fir_init_f32(&fir_, len, (float*)coefs_, state_, max_block); - return result; - } - - /* Create an alias to comply with DaisySP API conventions */ - template - inline auto Init(Args&&... args) - -> decltype(SetIR(std::forward(args)...)) - { - return SetIR(std::forward(args)...); - } - - protected: - arm_fir_instance_f32 fir_; /*< ARM CMSIS DSP library FIR filter instance */ - using FIRMem::coefs_; /*< FIR coefficients buffer or pointer */ - using FIRMem::size_; /*< FIR length*/ - using FIRMem::state_; /*< FIR state buffer or pointer */ -}; - - -/* default to ARM implementation */ -template -using FIR = FIRFilterImplARM; - - -#else // USE_ARM_DSP - -/* default to generic implementation */ -template -using FIR = FIRFilterImplGeneric; - -#endif // USE_ARM_DSP - - -} // namespace daisysp - -#endif // DSY_FIRFILTER_H diff --git a/src/daisysp/Filters/ladder.cpp b/src/daisysp/Filters/ladder.cpp deleted file mode 100644 index d5d1449..0000000 --- a/src/daisysp/Filters/ladder.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* Ported from Audio Library for Teensy, Ladder Filter - * Copyright (c) 2021, Richard van Hoesel - * Copyright (c) 2024, Infrasonic Audio LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice, development funding notice, and this permission - * notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -//----------------------------------------------------------- -// Huovilainen New Moog (HNM) model as per CMJ jun 2006 -// Richard van Hoesel, v. 1.03, Feb. 14 2021 -// v1.7 (Infrasonic/Daisy) add configurable filter mode -// v1.6 (Infrasonic/Daisy) removes polyphase FIR, uses 4x linear -// oversampling for performance reasons -// v1.5 adds polyphase FIR or Linear interpolation -// v1.4 FC extended to 18.7kHz, max res to 1.8, 4x oversampling, -// and a minor Q-tuning adjustment -// v.1.03 adds oversampling, extended resonance, -// and exposes parameters input_drive and passband_gain -// v.1.02 now includes both cutoff and resonance "CV" modulation inputs -// please retain this header if you use this code. -//----------------------------------------------------------- - -#include "ladder.h" -#include "../Utility/dsp.h" - -using namespace daisysp; - -static inline float fast_tanh(float x) -{ - if(x > 3.0f) - return 1.0f; - if(x < -3.0f) - return -1.0f; - float x2 = x * x; - return x * (27.0f + x2) / (27.0f + 9.0f * x2); -} - -void LadderFilter::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - sr_int_recip_ = 1.0f / (sample_rate * kInterpolation); - alpha_ = 1.0f; - K_ = 1.0f; - Fbase_ = 1000.0f; - Qadjust_ = 1.0f; - oldinput_ = 0.f; - mode_ = FilterMode::LP24; - - SetPassbandGain(0.5f); - SetInputDrive(0.5f); - SetFreq(5000.f); - SetRes(0.2f); -} - -float LadderFilter::Process(float in) -{ - float input = in * drive_scaled_; - float total = 0.0f; - float interp = 0.0f; - for(size_t os = 0; os < kInterpolation; os++) - { - float in_interp = (interp * oldinput_ + (1.0f - interp) * input); - float u = in_interp - (z1_[3] - pbg_ * in_interp) * K_ * Qadjust_; - u = fast_tanh(u); - float stage1 = LPF(u, 0); - float stage2 = LPF(stage1, 1); - float stage3 = LPF(stage2, 2); - float stage4 = LPF(stage3, 3); - total += weightedSumForCurrentMode({u, stage1, stage2, stage3, stage4}) - * kInterpolationRecip; - interp += kInterpolationRecip; - } - oldinput_ = input; - return total; -} - -__attribute__((optimize("unroll-loops"))) void -LadderFilter::ProcessBlock(float* buf, size_t size) -{ - for(size_t i = 0; i < size; i++) - { - buf[i] = Process(buf[i]); - } -} - -void LadderFilter::SetFreq(float freq) -{ - Fbase_ = freq; - compute_coeffs(freq); -} - -void LadderFilter::SetRes(float res) -{ - // maps resonance = 0->1 to K = 0 -> 4 - res = daisysp::fclamp(res, 0.0f, kMaxResonance); - K_ = 4.0f * res; -} - -void LadderFilter::SetPassbandGain(float pbg) -{ - pbg_ = daisysp::fclamp(pbg, 0.0f, 0.5f); - SetInputDrive(drive_); -} - -void LadderFilter::SetInputDrive(float odrv) -{ - drive_ = daisysp::fmax(odrv, 0.0f); - if(drive_ > 1.0f) - { - drive_ = fmin(drive_, 4.0f); - // max is 4 when pbg = 0, and 2.5 when pbg is 0.5 - drive_scaled_ = 1.0f + (drive_ - 1.0f) * (1.0f - pbg_); - } - else - { - drive_scaled_ = drive_; - } -} - -float LadderFilter::LPF(float s, int i) -{ - // (1.0 / 1.3) (0.3 / 1.3) - float ft = s * 0.76923077f + 0.23076923f * z0_[i] - z1_[i]; - ft = ft * alpha_ + z1_[i]; - z1_[i] = ft; - z0_[i] = s; - return ft; -} - -void LadderFilter::compute_coeffs(float freq) -{ - freq = daisysp::fclamp(freq, 5.0f, sample_rate_ * 0.425f); - float wc = freq * 2.0f * PI_F * sr_int_recip_; - float wc2 = wc * wc; - alpha_ = 0.9892f * wc - 0.4324f * wc2 + 0.1381f * wc * wc2 - - 0.0202f * wc2 * wc2; - //Qadjust = 1.0029f + 0.0526f * wc - 0.0926 * wc2 + 0.0218* wc * wc2; - Qadjust_ = 1.006f + 0.0536f * wc - 0.095f * wc2 - 0.05f * wc2 * wc2; - // revised hfQ (rvh - feb 14 2021) -} - -float LadderFilter::weightedSumForCurrentMode( - const std::array& stage_outs) -{ - // Weighted filter stage mixing to achieve selected response - // as described in "Oscillator and Filter Algorithms for Virtual Analog Synthesis" - // Välimäki and Huovilainen, Computer Music Journal, vol 60, 2006 - switch(mode_) - { - case FilterMode::LP24: return stage_outs[4]; - case FilterMode::LP12: return stage_outs[2]; - case FilterMode::BP24: - return (stage_outs[2] + stage_outs[4]) * 4.0f - - stage_outs[3] * 8.0f; - case FilterMode::BP12: return (stage_outs[1] - stage_outs[2]) * 2.0f; - case FilterMode::HP24: - return stage_outs[0] + stage_outs[4] - - ((stage_outs[1] + stage_outs[3]) * 4.0f) - + stage_outs[2] * 6.0f; - case FilterMode::HP12: - return stage_outs[0] + stage_outs[2] - stage_outs[1] * 2.0f; - default: return 0.0f; - } -} diff --git a/src/daisysp/Filters/ladder.h b/src/daisysp/Filters/ladder.h deleted file mode 100644 index 8506f01..0000000 --- a/src/daisysp/Filters/ladder.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Ported from Audio Library for Teensy, Ladder Filter - * Copyright (c) 2021, Richard van Hoesel - * Copyright (c) 2024, Infrasonic Audio LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice, development funding notice, and this permission - * notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -//----------------------------------------------------------- -// Huovilainen New Moog (HNM) model as per CMJ jun 2006 -// Richard van Hoesel, v. 1.03, Feb. 14 2021 -// v1.7 (Infrasonic/Daisy) add configurable filter mode -// v1.6 (Infrasonic/Daisy) removes polyphase FIR, uses 4x linear -// oversampling for performance reasons -// v1.5 adds polyphase FIR or Linear interpolation -// v1.4 FC extended to 18.7kHz, max res to 1.8, 4x oversampling, -// and a minor Q-tuning adjustment -// v.1.03 adds oversampling, extended resonance, -// and exposes parameters input_drive and passband_gain -// v.1.02 now includes both cutoff and resonance "CV" modulation inputs -// please retain this header if you use this code. -//----------------------------------------------------------- - -#pragma once -#ifndef DSY_LADDER_H -#define DSY_LADDER_H - -#include -#include -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** - * 4-pole ladder filter model with selectable filter type (LP/BP/HP 12 or 24 dB/oct), - * drive, passband gain compensation, and stable self-oscillation. - * - * - */ -class LadderFilter -{ - public: - enum class FilterMode - { - LP24, - LP12, - BP24, - BP12, - HP24, - HP12 - }; - - LadderFilter() = default; - ~LadderFilter() = default; - - /** Initializes the ladder filter module. - */ - void Init(float sample_rate); - - /** Process single sample */ - float Process(float in); - - /** Process mono buffer/block of samples in place */ - void ProcessBlock(float* buf, size_t size); - - /** - Sets the cutoff frequency of the filter. - Units of hz, valid in range 5 - ~nyquist (samp_rate / 2) - Internally clamped to this range. - */ - void SetFreq(float freq); - - /** - Sets the resonance of the filter. - Filter will stably self oscillate at higher values. - Valid in range 0 - 1.8 - Internally clamped to this range. - */ - void SetRes(float res); - - /** - Set "passband gain" compensation factor to mitigate - loss of energy in passband at higher resonance values. - Drive and passband gain have a dependent relationship. - Valid in range 0 - 0.5 - Internally clamped to this range. - */ - void SetPassbandGain(float pbg); - - /** - Sets drive of the input stage into the tanh clipper - Valid in range 0 - 4.0 - */ - void SetInputDrive(float drv); - - /** - Sets the filter mode/response - Defaults to classic lowpass 24dB/oct - */ - inline void SetFilterMode(FilterMode mode) { mode_ = mode; } - - private: - static constexpr uint8_t kInterpolation = 4; - static constexpr float kInterpolationRecip = 1.0f / kInterpolation; - static constexpr float kMaxResonance = 1.8f; - - float sample_rate_, sr_int_recip_; - float alpha_; - float beta_[4] = {0.0, 0.0, 0.0, 0.0}; - float z0_[4] = {0.0, 0.0, 0.0, 0.0}; - float z1_[4] = {0.0, 0.0, 0.0, 0.0}; - float K_; - float Fbase_; - float Qadjust_; - float pbg_; - float drive_, drive_scaled_; - float oldinput_; - FilterMode mode_; - - float LPF(float s, int i); - void compute_coeffs(float fc); - float weightedSumForCurrentMode(const std::array& stage_outs); -}; - - -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Filters/onepole.h b/src/daisysp/Filters/onepole.h deleted file mode 100644 index ec82536..0000000 --- a/src/daisysp/Filters/onepole.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#ifndef DSY_ONEPOLE_H -#define DSY_ONEPOLE_H - -#include "../Utility/dsp.h" -#include -#include - -namespace daisysp -{ -/** - @brief One Pole Lowpass / Highpass Filter - @author beserge - @date Dec 2023 - Ported from pichenettes/stmlib/dsp/filter.h \n - \n to an independent module. \n - Original code written by Emilie Gillet. \n -*/ -class OnePole -{ - public: - OnePole() {} - ~OnePole() {} - - /** - * @brief Operational modes of the filter - * - LOW_PASS = cuts out high frequency sound, lets low frequency sound pass through - * - HIGH_PASS = cuts out low frequency sound, lets high frequency sound pass through - */ - enum FilterMode - { - FILTER_MODE_LOW_PASS, - FILTER_MODE_HIGH_PASS - }; - - /** Initializes the module */ - void Init() - { - Reset(); - mode_ = FILTER_MODE_LOW_PASS; - } - - /** Reset the module to its default state */ - inline void Reset() { state_ = 0.0f; } - - /** Set the filter cutoff frequency - * \param freq Cutoff frequency. Valid range from 0 to .497f - */ - inline void SetFrequency(float freq) - { - // Clip coefficient to about 100. - freq = freq < 0.497f ? freq : 0.497f; - - g_ = tanf(PI_F * freq); - gi_ = 1.f / (1.f + g_); - } - - /** Set the filter mode - * \param mode Filter mode. Can be lowpass or highpass - */ - inline void SetFilterMode(FilterMode mode) { mode_ = mode; } - - /** Process audio through the filter - * \param in The next sample to be processed - */ - inline float Process(float in) - { - float lp; - lp = (g_ * in + state_) * gi_; - state_ = g_ * (in - lp) + lp; - - switch(mode_) - { - case FILTER_MODE_LOW_PASS: return lp; - case FILTER_MODE_HIGH_PASS: return in - lp; - } - - return 0.0f; - } - - /** Process a block of audio through the filter - * \param in_out Pointer to the block of samples to be processed - * \param size Size of the block of samples to be processed. - */ - inline void ProcessBlock(float* in_out, size_t size) - { - while(size--) - { - *in_out = Process(*in_out); - ++in_out; - } - } - - private: - float g_; - float gi_; - float state_; - FilterMode mode_; -}; - -} // namespace daisysp - -#endif // DSY_ONEPOLE_H diff --git a/src/daisysp/Filters/soap.cpp b/src/daisysp/Filters/soap.cpp deleted file mode 100644 index ea95289..0000000 --- a/src/daisysp/Filters/soap.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "soap.h" -#include - -#define PI 3.141592653589793 - -using namespace daisysp; - -void Soap::Init(float sample_rate) -{ - soap_center_freq_ = 400.0; - soap_bandwidth_ = 50.0; - in_0_ = 0.0; // input x0 - din_1_ = 0.0; // delayed input x1 - din_2_ = 0.0; // delayed input x2 - dout_1_ = 0.0; // delayed output y1 - dout_2_ = 0.0; // delayed output y2 - all_output_ = 0.0; // all pass output y0 - out_bandpass_ = 0.0; // bandpass output - out_bandreject_ = 0.0; // bandreject output - sr_ = sample_rate; - return; -} - -void Soap::Process(float in) -{ - // recalculate the coefficients, later move this to a lookup table - float d = -std::cos(2.0 * PI * (soap_center_freq_ / sr_)); - - // tangent bandwidth - float tf = std::tan(PI * (soap_bandwidth_ / sr_)); - - // coefficient - float c = (tf - 1.0) / (tf + 1.0); - - in_0_ = in; - - all_output_ = -c * in_0_ + (d - d * c) * din_1_ + din_2_ - - (d - d * c) * dout_1_ + c * dout_2_; - - // move samples in delay for next sample - din_2_ = din_1_; - din_1_ = in_0_; - dout_2_ = dout_1_; - dout_1_ = all_output_; - - // make factor -1.0 to create a bandpass - out_bandpass_ = (in_0_ + all_output_ * -1.0) * 0.5; - - // make factor +1.0 to create a bandreject - out_bandreject_ = (in_0_ + all_output_ * 0.99) * 0.5; - - return; -} - -void Soap::SetCenterFreq(float f) -{ - soap_center_freq_ = f; - return; -} - -void Soap::SetFilterBandwidth(float b) -{ - soap_bandwidth_ = b; - return; -} \ No newline at end of file diff --git a/src/daisysp/Filters/soap.h b/src/daisysp/Filters/soap.h deleted file mode 100644 index 3d4b4b6..0000000 --- a/src/daisysp/Filters/soap.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Brian Tice, Tom Erbe - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once - -namespace daisysp -{ -/** Second Order All Pass Filter - -This is from Tom Erbe's synth notes. The filter -can be configured to be a band pass or band reject - -Ported by: Brian Tice -*/ -class Soap -{ - public: - Soap() {} - ~Soap() {} - - /** Initializes the filter - float sample_rate - sample rate of the audio engine being run, and the frequency that the Process function will be called. - */ - void Init(float sample_rate); - - /** - Process the input signal, updating all of the outputs - */ - void Process(float in); - - /** - Sets the center frequency of the filter. - */ - void SetCenterFreq(float f); - - /** - Sets the low frequency threshold of the filter. - */ - void SetFilterBandwidth(float b); - - /** Bandpass output - \return bandpass output of the filter - */ - inline float Bandpass() { return out_bandpass_; } - - /** Bandreject output - \return bandreject output of the filter - */ - inline float Bandreject() { return out_bandreject_; } - - private: - float soap_center_freq_; - float soap_bandwidth_; - float in_0_; - float din_1_; - float din_2_; - float dout_1_; - float dout_2_; - float all_output_; - float out_bandpass_; - float out_bandreject_; - float sr_; -}; - -} // namespace daisysp diff --git a/src/daisysp/Filters/svf.cpp b/src/daisysp/Filters/svf.cpp deleted file mode 100644 index 369c341..0000000 --- a/src/daisysp/Filters/svf.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include "svf.h" -#include "../Utility/dsp.h" -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) - -using namespace daisysp; - -void Svf::Init(float sample_rate) -{ - sr_ = sample_rate; - fc_ = 200.0f; - res_ = 0.5f; - drive_ = 0.5f; - pre_drive_ = 0.5f; - freq_ = 0.25f; - damp_ = 0.0f; - notch_ = 0.0f; - low_ = 0.0f; - high_ = 0.0f; - band_ = 0.0f; - peak_ = 0.0f; - input_ = 0.0f; - out_notch_ = 0.0f; - out_low_ = 0.0f; - out_high_ = 0.0f; - out_peak_ = 0.0f; - out_band_ = 0.0f; - fc_max_ = sr_ / 3.f; -} - -void Svf::Process(float in) -{ - input_ = in; - // first pass - notch_ = input_ - damp_ * band_; - low_ = low_ + freq_ * band_; - high_ = notch_ - low_; - band_ = freq_ * high_ + band_ - drive_ * band_ * band_ * band_; - // take first sample of output - out_low_ = 0.5f * low_; - out_high_ = 0.5f * high_; - out_band_ = 0.5f * band_; - out_peak_ = 0.5f * (low_ - high_); - out_notch_ = 0.5f * notch_; - // second pass - notch_ = input_ - damp_ * band_; - low_ = low_ + freq_ * band_; - high_ = notch_ - low_; - band_ = freq_ * high_ + band_ - drive_ * band_ * band_ * band_; - // average second pass outputs - out_low_ += 0.5f * low_; - out_high_ += 0.5f * high_; - out_band_ += 0.5f * band_; - out_peak_ += 0.5f * (low_ - high_); - out_notch_ += 0.5f * notch_; -} - -void Svf::SetFreq(float f) -{ - fc_ = fclamp(f, 1.0e-6, fc_max_); - // Set Internal Frequency for fc_ - freq_ = 2.0f - * sinf(PI_F - * MIN(0.25f, - fc_ / (sr_ * 2.0f))); // fs*2 because double sampled - // recalculate damp - damp_ = MIN(2.0f * (1.0f - powf(res_, 0.25f)), - MIN(2.0f, 2.0f / freq_ - freq_ * 0.5f)); -} - -void Svf::SetRes(float r) -{ - float res = fclamp(r, 0.f, 1.f); - res_ = res; - // recalculate damp - damp_ = MIN(2.0f * (1.0f - powf(res_, 0.25f)), - MIN(2.0f, 2.0f / freq_ - freq_ * 0.5f)); - drive_ = pre_drive_ * res_; -} - -void Svf::SetDrive(float d) -{ - float drv = fclamp(d * 0.1f, 0.f, 1.f); - pre_drive_ = drv; - drive_ = pre_drive_ * res_; -} diff --git a/src/daisysp/Filters/svf.h b/src/daisysp/Filters/svf.h deleted file mode 100644 index e41eef5..0000000 --- a/src/daisysp/Filters/svf.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SVF_H -#define DSY_SVF_H - -namespace daisysp -{ -/** Double Sampled, Stable State Variable Filter - -Credit to Andrew Simper from musicdsp.org - -This is his "State Variable Filter (Double Sampled, Stable)" - -Additional thanks to Laurent de Soras for stability limit, and -Stefan Diedrichsen for the correct notch output - -Ported by: Stephen Hensley -*/ -class Svf -{ - public: - Svf() {} - ~Svf() {} - /** Initializes the filter - float sample_rate - sample rate of the audio engine being run, and the frequency that the Process function will be called. - */ - void Init(float sample_rate); - - - /** - Process the input signal, updating all of the outputs. - */ - void Process(float in); - - - /** sets the frequency of the cutoff frequency. - f must be between 0.0 and sample_rate / 3 - */ - void SetFreq(float f); - - /** sets the resonance of the filter. - Must be between 0.0 and 1.0 to ensure stability. - */ - void SetRes(float r); - - /** sets the drive of the filter - affects the response of the resonance of the filter - */ - void SetDrive(float d); - /** lowpass output - \return low pass output of the filter - */ - inline float Low() { return out_low_; } - /** highpass output - \return high pass output of the filter - */ - inline float High() { return out_high_; } - /** bandpass output - \return band pass output of the filter - */ - inline float Band() { return out_band_; } - /** notchpass output - \return notch pass output of the filter - */ - inline float Notch() { return out_notch_; } - /** peak output - \return peak output of the filter - */ - inline float Peak() { return out_peak_; } - - private: - float sr_, fc_, res_, drive_, freq_, damp_; - float notch_, low_, high_, band_, peak_; - float input_; - float out_low_, out_high_, out_band_, out_peak_, out_notch_; - float pre_drive_, fc_max_; -}; -} // namespace daisysp - -#endif diff --git a/src/daisysp/Noise/clockednoise.cpp b/src/daisysp/Noise/clockednoise.cpp deleted file mode 100644 index a51099b..0000000 --- a/src/daisysp/Noise/clockednoise.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include "../Utility/dsp.h" -#include "clockednoise.h" - -using namespace daisysp; - -void ClockedNoise::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - phase_ = 0.0f; - sample_ = 0.0f; - next_sample_ = 0.0f; - frequency_ = 0.001f; -} - -float ClockedNoise::Process() -{ - float next_sample = next_sample_; - float sample = sample_; - - float this_sample = next_sample; - next_sample = 0.0f; - - const float raw_sample = rand() * kRandFrac * 2.0f - 1.0f; - float raw_amount = 4.0f * (frequency_ - 0.25f); - raw_amount = fclamp(raw_amount, 0.0f, 1.0f); - - phase_ += frequency_; - - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - float t = phase_ / frequency_; - float new_sample = raw_sample; - float discontinuity = new_sample - sample; - this_sample += discontinuity * ThisBlepSample(t); - next_sample += discontinuity * NextBlepSample(t); - sample = new_sample; - } - - next_sample += sample; - next_sample_ = next_sample; - sample_ = sample; - - return this_sample + raw_amount * (raw_sample - this_sample); -} - -void ClockedNoise::SetFreq(float freq) -{ - freq = freq / sample_rate_; - freq = fclamp(freq, 0.0f, 1.0f); - frequency_ = freq; -} - -void ClockedNoise::Sync() -{ - phase_ = 1.0f; -} \ No newline at end of file diff --git a/src/daisysp/Noise/clockednoise.h b/src/daisysp/Noise/clockednoise.h deleted file mode 100644 index e64c9a9..0000000 --- a/src/daisysp/Noise/clockednoise.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_CLOCKEDNOISE_H -#define DSY_CLOCKEDNOISE_H - -#include -#ifdef __cplusplus - -/** @file clockednoise.h */ - -namespace daisysp -{ -/** - @brief Clocked Noise Module - @author Ported by Ben Sergentanis - @date Jan 2021 - Noise processed by a sample and hold running at a target frequency. \n \n - Ported from pichenettes/eurorack/plaits/dsp/noise/clocked_noise.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class ClockedNoise -{ - public: - ClockedNoise() {} - ~ClockedNoise() {} - - /** Initialize module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next floating point sample */ - float Process(); - - /** Set the frequency at which the next sample is generated. - \param freq Frequency in Hz - */ - void SetFreq(float freq); - - /** Calling this forces another random float to be generated */ - void Sync(); - - private: - // Oscillator state. - float phase_; - float sample_; - float next_sample_; - - // For interpolation of parameters. - float frequency_; - - float sample_rate_; - - static constexpr float kRandFrac = 1.f / (float)RAND_MAX; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Noise/dust.h b/src/daisysp/Noise/dust.h deleted file mode 100644 index f16bab8..0000000 --- a/src/daisysp/Noise/dust.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_DUST_H -#define DSY_DUST_H -#include -#include -#include "../Utility/dsp.h" -#ifdef __cplusplus - -/** @file dust.h */ - -namespace daisysp -{ -/** - @brief Dust Module - @author Ported by Ben Sergentanis - @date Jan 2021 - Randomly Clocked Samples \n \n - Ported from pichenettes/eurorack/plaits/dsp/noise/dust.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n - -*/ -class Dust -{ - public: - Dust() {} - ~Dust() {} - - void Init() { SetDensity(.5f); } - - float Process() - { - float inv_density = 1.0f / density_; - float u = rand() * kRandFrac; - if(u < density_) - { - return u * inv_density; - } - return 0.0f; - } - - void SetDensity(float density) - { - density_ = fclamp(density, 0.f, 1.f); - density_ = density_ * .3f; - } - - private: - float density_; - static constexpr float kRandFrac = 1.f / (float)RAND_MAX; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Noise/fractal_noise.h b/src/daisysp/Noise/fractal_noise.h deleted file mode 100644 index 0d4ff9b..0000000 --- a/src/daisysp/Noise/fractal_noise.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_FRACTAL_H -#define DSY_FRACTAL_H - -#include -#ifdef __cplusplus - -/** @file fractal_noise.h */ - -namespace daisysp -{ -/** - @brief Fractal Noise, stacks octaves of a noise source. - @author Ported by Ben Sergentanis - @date Jan 2021 - T is the noise source to use. T must have SetFreq() and Init(sample_rate) functions. \n - Order is the number of noise sources to stack. \n \n - Ported from pichenettes/eurorack/plaits/dsp/noise/fractal_random_generator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n - -*/ -template -class FractalRandomGenerator -{ - public: - FractalRandomGenerator() {} - ~FractalRandomGenerator() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate) - { - sample_rate_ = sample_rate; - - SetColor(.5f); - SetFreq(440.f); - for(int i = 0; i < order; ++i) - { - generator_[i].Init(sample_rate_); - } - } - - /** Get the next sample. */ - float Process() - { - float gain = 0.5f; - float sum = 0.0f; - float frequency = frequency_; - - for(int i = 0; i < order; ++i) - { - generator_[i].SetFreq(frequency); - sum += generator_[i].Process() * gain; - gain *= decay_; - frequency *= 2.0f; - } - - return sum; - } - - /** Set the lowest noise frequency. - \param freq Frequency of the lowest noise source in Hz. - */ - void SetFreq(float freq) { frequency_ = fclamp(freq, 0.f, sample_rate_); } - - /** Sets the amount of high frequency noise. - \** Works 0-1. 1 is the brightest, and 0 is the darkest. - */ - void SetColor(float color) { decay_ = fclamp(color, 0.f, 1.f); } - - private: - float sample_rate_; - float frequency_; - float decay_; - - T generator_[order]; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Noise/grainlet.cpp b/src/daisysp/Noise/grainlet.cpp deleted file mode 100644 index b22927b..0000000 --- a/src/daisysp/Noise/grainlet.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "../Utility/dsp.h" -#include "grainlet.h" -#include - -using namespace daisysp; - -void GrainletOscillator::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - carrier_phase_ = 0.0f; - formant_phase_ = 0.0f; - next_sample_ = 0.0f; - - carrier_shape_ = 0.f; - carrier_bleed_ = 0.f; - - SetFreq(440.f); - SetFormantFreq(220.f); - SetShape(.5f); - SetBleed(.5f); -} - -float GrainletOscillator::Process() -{ - float this_sample = next_sample_; - float next_sample = 0.0f; - - carrier_phase_ += carrier_frequency_; - - if(carrier_phase_ >= 1.0f) - { - carrier_phase_ -= 1.0f; - float reset_time = carrier_phase_ / carrier_frequency_; - - float shape_inc = new_carrier_shape_ - carrier_shape_; - float bleed_inc = new_carrier_bleed_ - carrier_bleed_; - - float before = Grainlet( - 1.0f, - formant_phase_ + (1.0f - reset_time) * formant_frequency_, - new_carrier_shape_ + shape_inc * (1.0f - reset_time), - new_carrier_bleed_ + bleed_inc * (1.0f - reset_time)); - - float after - = Grainlet(0.0f, 0.0f, new_carrier_shape_, new_carrier_bleed_); - - float discontinuity = after - before; - this_sample += discontinuity * ThisBlepSample(reset_time); - next_sample += discontinuity * NextBlepSample(reset_time); - formant_phase_ = reset_time * formant_frequency_; - } - else - { - formant_phase_ += formant_frequency_; - if(formant_phase_ >= 1.0f) - { - formant_phase_ -= 1.0f; - } - } - - carrier_bleed_ = new_carrier_bleed_; - carrier_shape_ = new_carrier_shape_; - next_sample += Grainlet( - carrier_phase_, formant_phase_, carrier_shape_, carrier_bleed_); - next_sample_ = next_sample; - return this_sample; -} - -void GrainletOscillator::SetFreq(float freq) -{ - carrier_frequency_ = freq / sample_rate_; - carrier_frequency_ = carrier_frequency_ > 0.5f ? 0.5f : carrier_frequency_; -} - -void GrainletOscillator::SetFormantFreq(float freq) -{ - formant_frequency_ = freq / sample_rate_; - formant_frequency_ = formant_frequency_ > 0.5f ? 0.5f : formant_frequency_; -} - -void GrainletOscillator::SetShape(float shape) -{ - new_carrier_shape_ = shape; -} - -void GrainletOscillator::SetBleed(float bleed) -{ - new_carrier_bleed_ = bleed; -} - - -float GrainletOscillator::Sine(float phase) -{ - return sinf(phase * TWOPI_F); -} - -float GrainletOscillator::Carrier(float phase, float shape) -{ - shape *= 3.0f; - int shape_integral = static_cast(shape); - float shape_fractional = shape - static_cast(shape_integral); - - float t = 1.0f - shape_fractional; - - if(shape_integral == 0) - { - phase = phase * (1.0f + t * t * t * 15.0f); - if(phase >= 1.0f) - { - phase = 1.0f; - } - phase += 0.75f; - } - else if(shape_integral == 1) - { - float breakpoint = 0.001f + 0.499f * t * t * t; - if(phase < breakpoint) - { - phase *= (0.5f / breakpoint); - } - else - { - phase = 0.5f + (phase - breakpoint) * 0.5f / (1.0f - breakpoint); - } - phase += 0.75f; - } - else - { - t = 1.0f - t; - phase = 0.25f + phase * (0.5f + t * t * t * 14.5f); - if(phase >= 0.75f) - phase = 0.75f; - } - return (Sine(phase) + 1.0f) * 0.25f; -} - -float GrainletOscillator::Grainlet(float carrier_phase, - float formant_phase, - float shape, - float bleed) -{ - float carrier = Carrier(carrier_phase, shape); - float formant = Sine(formant_phase); - return carrier * (formant + bleed) / (1.0f + bleed); -} \ No newline at end of file diff --git a/src/daisysp/Noise/grainlet.h b/src/daisysp/Noise/grainlet.h deleted file mode 100644 index 9734084..0000000 --- a/src/daisysp/Noise/grainlet.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_GRAINLET_H -#define DSY_GRAINLET_H - -#include -#ifdef __cplusplus - -/** @file grainlet.h */ -namespace daisysp -{ -/** - @brief Granular Oscillator Module. - @author Ben Sergentanis - @date Dec 2020 - A phase-distorted single cycle sine * another continuously running sine, \n - the whole thing synced to a main oscillator. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/grainlet_oscillator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ - -class GrainletOscillator -{ - public: - GrainletOscillator() {} - ~GrainletOscillator() {} - - /** Initialize the oscillator - \param sample_rate Sample rate of audio engine - */ - void Init(float sample_rate); - - /** Get the next sample */ - float Process(); - - /** Sets the carrier frequency - \param freq Frequency in Hz - */ - void SetFreq(float freq); - - /** Sets the formant frequency - \param freq Frequency in Hz - */ - void SetFormantFreq(float freq); - - /** Waveshaping - \param shape Shapes differently from 0-1, 1-2, and > 2. - */ - void SetShape(float shape); - - /** Sets the amount of formant to bleed through - \param bleed Works best 0-1 - */ - void SetBleed(float bleed); - - private: - float Sine(float phase); - - float Carrier(float phase, float shape); - - float Grainlet(float carrier_phase, - float formant_phase, - float shape, - float bleed); - - // Oscillator state. - float carrier_phase_; - float formant_phase_; - float next_sample_; - - // For interpolation of parameters. - float carrier_frequency_; - float formant_frequency_; - float carrier_shape_; - float carrier_bleed_; - - float new_carrier_shape_; - float new_carrier_bleed_; - - float sample_rate_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Noise/particle.cpp b/src/daisysp/Noise/particle.cpp deleted file mode 100644 index 3dca0dd..0000000 --- a/src/daisysp/Noise/particle.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "../Utility/dsp.h" -#include "particle.h" -#include - -using namespace daisysp; - -void Particle::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - sync_ = false; - aux_ = 0.f; - SetFreq(440.f); - resonance_ = .9f; - density_ = .5f; - gain_ = 1.f; - spread_ = 1.f; - - SetRandomFreq(sample_rate_ / 48.f); //48 is the default block size - rand_phase_ = 0.f; - - pre_gain_ = 0.0f; - filter_.Init(sample_rate_); - filter_.SetDrive(.7f); -} - -float Particle::Process() -{ - float u = rand() * kRandFrac; - float s = 0.0f; - - if(u <= density_ || sync_) - { - s = u <= density_ ? u * gain_ : s; - rand_phase_ += rand_freq_; - - if(rand_phase_ >= 1.f || sync_) - { - rand_phase_ = rand_phase_ >= 1.f ? rand_phase_ - 1.f : rand_phase_; - - const float u = 2.0f * rand() * kRandFrac - 1.0f; - const float f - = fmin(powf(2.f, kRatioFrac * spread_ * u) * frequency_, .25f); - pre_gain_ = 0.5f / sqrtf(resonance_ * f * sqrtf(density_)); - filter_.SetFreq(f * sample_rate_); - filter_.SetRes(resonance_); - } - } - aux_ = s; - - filter_.Process(pre_gain_ * s); - return filter_.Band(); -} - -float Particle::GetNoise() -{ - return aux_; -} - -void Particle::SetFreq(float freq) -{ - freq /= sample_rate_; - frequency_ = fclamp(freq, 0.f, 1.f); -} - -void Particle::SetResonance(float resonance) -{ - resonance_ = fclamp(resonance, 0.f, 1.f); -} - -void Particle::SetRandomFreq(float freq) -{ - freq /= sample_rate_; - rand_freq_ = fclamp(freq, 0.f, 1.f); -} - -void Particle::SetDensity(float density) -{ - density_ = fclamp(density * .3f, 0.f, 1.f); -} - -void Particle::SetGain(float gain) -{ - gain_ = fclamp(gain, 0.f, 1.f); -} - -void Particle::SetSpread(float spread) -{ - spread_ = spread < 0.f ? 0.f : spread; -} - -void Particle::SetSync(bool sync) -{ - sync_ = sync; -} \ No newline at end of file diff --git a/src/daisysp/Noise/particle.h b/src/daisysp/Noise/particle.h deleted file mode 100644 index 4b23498..0000000 --- a/src/daisysp/Noise/particle.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#ifndef DSY_PARTICLE_H -#define DSY_PARTICLE_H - -#include "../Filters/svf.h" -#include -#include -#ifdef __cplusplus - -/** @file particle.h */ - -namespace daisysp -{ -/** - @brief Random impulse train processed by a resonant filter. - @author Ported by Ben Sergentanis - @date Jan 2021 - Noise processed by a sample and hold running at a target frequency. \n \n - Ported from pichenettes/eurorack/plaits/dsp/noise/particle.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class Particle -{ - public: - Particle() {} - ~Particle() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get the next sample */ - float Process(); - - /** Get the raw noise output. Must call Process() first. */ - float GetNoise(); - - /** Set the resonant filter frequency - \param freq Frequency in Hz - */ - void SetFreq(float frequency); - - /** Set the filter resonance - \param resonance Works 0-1 - */ - void SetResonance(float resonance); - - /** How often to randomize filter frequency - \param freq Frequency in Hz. - */ - void SetRandomFreq(float freq); - - /** Noise density - \param Works 0-1. - */ - void SetDensity(float density); - - /** Overall module gain - \param Works 0-1. - */ - void SetGain(float gain); - - /** How much to randomize the set filter frequency. - \param spread Works over positive numbers. - */ - void SetSpread(float spread); - - /** Force randomize the frequency. - \param sync True to randomize freq. - */ - void SetSync(bool sync); - - private: - static constexpr float kRandFrac = 1.f / (float)RAND_MAX; - static constexpr float kRatioFrac = 1.f / 12.f; - float sample_rate_; - float aux_, frequency_, density_, gain_, spread_, resonance_; - bool sync_; - - - float rand_phase_; - float rand_freq_; - - - float pre_gain_; - Svf filter_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Noise/whitenoise.h b/src/daisysp/Noise/whitenoise.h deleted file mode 100644 index cb4b28a..0000000 --- a/src/daisysp/Noise/whitenoise.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_WHITENOISE_H -#define DSY_WHITENOISE_H -#include -#ifdef __cplusplus -namespace daisysp -{ -/** fast white noise generator - - I think this came from musicdsp.org at some point -*/ -class WhiteNoise -{ - public: - WhiteNoise() {} - ~WhiteNoise() {} - /** Initializes the WhiteNoise object - */ - void Init() - { - amp_ = 1.0f; - randseed_ = 1; - } - - /** sets the amplitude of the noise output - */ - inline void SetAmp(float a) { amp_ = a; } - /** returns a new sample of noise in the range of -amp_ to amp_ - */ - inline float Process() - { - randseed_ *= 16807; - return (randseed_ * coeff_) * amp_; - } - - /** sets the seed (and corrects a seed of 0 to 1) */ - inline void SetSeed(int32_t s) { randseed_ = s == 0 ? 1 : s; } - - private: - static constexpr float coeff_ = 4.6566129e-010f; - float amp_; - int32_t randseed_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/PhysicalModeling/KarplusString.cpp b/src/daisysp/PhysicalModeling/KarplusString.cpp deleted file mode 100644 index e132f7d..0000000 --- a/src/daisysp/PhysicalModeling/KarplusString.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include -#include "../Utility/dsp.h" -#include "KarplusString.h" -#include - -using namespace daisysp; - -void String::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - SetFreq(440.f); - non_linearity_amount_ = .5f; - brightness_ = .5f; - damping_ = .5f; - - string_.Init(); - stretch_.Init(); - Reset(); - - SetFreq(440.f); - SetDamping(.8f); - SetNonLinearity(.1f); - SetBrightness(.5f); - - crossfade_.Init(); -} - -void String::Reset() -{ - string_.Reset(); - stretch_.Reset(); - iir_damping_filter_.Init(); - - dc_blocker_.Init(sample_rate_); - - dispersion_noise_ = 0.0f; - curved_bridge_ = 0.0f; - out_sample_[0] = out_sample_[1] = 0.0f; - src_phase_ = 0.0f; -} - -float String::Process(const float in) -{ - if(non_linearity_amount_ <= 0.0f) - { - non_linearity_amount_ *= -1; - float ret = ProcessInternal(in); - non_linearity_amount_ *= -1; - return ret; - } - else - { - return ProcessInternal(in); - } -} - -void String::SetFreq(float freq) -{ - freq /= sample_rate_; - frequency_ = fclamp(freq, 0.f, .25f); -} - -void String::SetNonLinearity(float non_linearity_amount) -{ - non_linearity_amount_ = fclamp(non_linearity_amount, 0.f, 1.f); -} - -void String::SetBrightness(float brightness) -{ - brightness_ = fclamp(brightness, 0.f, 1.f); -} - -void String::SetDamping(float damping) -{ - damping_ = fclamp(damping, 0.f, 1.f); -} - -template -float String::ProcessInternal(const float in) -{ - float brightness = brightness_; - - float delay = 1.0f / frequency_; - delay = fclamp(delay, 4.f, kDelayLineSize - 4.0f); - - // If there is not enough delay time in the delay line, we play at the - // lowest possible note and we upsample on the fly with a shitty linear - // interpolator. We don't care because it's a corner case (frequency_ < 11.7Hz) - float src_ratio = delay * frequency_; - if(src_ratio >= 0.9999f) - { - // When we are above 11.7 Hz, we make sure that the linear interpolator - // does not get in the way. - src_phase_ = 1.0f; - src_ratio = 1.0f; - } - - float damping_cutoff - = fmin(12.0f + damping_ * damping_ * 60.0f + brightness * 24.0f, 84.0f); - float damping_f - = fmin(frequency_ * powf(2.f, damping_cutoff * kOneTwelfth), 0.499f); - - // Crossfade to infinite decay. - if(damping_ >= 0.95f) - { - float to_infinite = 20.0f * (damping_ - 0.95f); - brightness += to_infinite * (1.0f - brightness); - damping_f += to_infinite * (0.4999f - damping_f); - damping_cutoff += to_infinite * (128.0f - damping_cutoff); - } - - float temp_f = damping_f; - iir_damping_filter_.SetFrequency(temp_f); - - float ratio = powf(2.f, damping_cutoff * kOneTwelfth); - float damping_compensation = 1.f - 2.f * atanf(1.f / ratio) / (TWOPI_F); - - float stretch_point - = non_linearity_amount_ * (2.0f - non_linearity_amount_) * 0.225f; - float stretch_correction = (160.0f / sample_rate_) * delay; - stretch_correction = fclamp(stretch_correction, 1.f, 2.1f); - - float noise_amount_sqrt = non_linearity_amount_ > 0.75f - ? 4.0f * (non_linearity_amount_ - 0.75f) - : 0.0f; - float noise_amount = noise_amount_sqrt * noise_amount_sqrt * 0.1f; - float noise_filter = 0.06f + 0.94f * brightness * brightness; - - float bridge_curving_sqrt = non_linearity_amount_; - float bridge_curving = bridge_curving_sqrt * bridge_curving_sqrt * 0.01f; - - float ap_gain = -0.618f * non_linearity_amount_ - / (0.15f + fabsf(non_linearity_amount_)); - - src_phase_ += src_ratio; - if(src_phase_ > 1.0f) - { - src_phase_ -= 1.0f; - - delay = delay * damping_compensation; - float s = 0.0f; - - if(non_linearity == NON_LINEARITY_DISPERSION) - { - float noise = rand() * kRandFrac - 0.5f; - fonepole(dispersion_noise_, noise, noise_filter); - delay *= 1.0f + dispersion_noise_ * noise_amount; - } - else - { - delay *= 1.0f - curved_bridge_ * bridge_curving; - } - - if(non_linearity == NON_LINEARITY_DISPERSION) - { - float ap_delay = delay * stretch_point; - float main_delay = delay - - ap_delay * (0.408f - stretch_point * 0.308f) - * stretch_correction; - if(ap_delay >= 4.0f && main_delay >= 4.0f) - { - s = string_.Read(main_delay); - s = stretch_.Allpass(s, ap_delay, ap_gain); - } - else - { - s = string_.ReadHermite(delay); - } - } - else - { - s = string_.ReadHermite(delay); - } - - if(non_linearity == NON_LINEARITY_CURVED_BRIDGE) - { - float value = fabsf(s) - 0.025f; - float sign = s > 0.0f ? 1.0f : -1.5f; - curved_bridge_ = (fabsf(value) + value) * sign; - } - - s += in; - s = fclamp(s, -20.f, +20.f); - - s = dc_blocker_.Process(s); - - s = iir_damping_filter_.Process(s); - string_.Write(s); - - out_sample_[1] = out_sample_[0]; - out_sample_[0] = s; - } - - crossfade_.SetPos(src_phase_); - return crossfade_.Process(out_sample_[1], out_sample_[0]); -} diff --git a/src/daisysp/PhysicalModeling/KarplusString.h b/src/daisysp/PhysicalModeling/KarplusString.h deleted file mode 100644 index f5bce6f..0000000 --- a/src/daisysp/PhysicalModeling/KarplusString.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_STRING_H -#define DSY_STRING_H - -#include - -#include "../Dynamics/crossfade.h" -#include "../Utility/dcblock.h" -#include "../Utility/delayline.h" -#include "../Filters/onepole.h" - -#ifdef __cplusplus - -/** @file KarplusString.h */ - -namespace daisysp -{ -/** - @brief Comb filter / KS string. - @author Ben Sergentanis - @date Jan 2021 - "Lite" version of the implementation used in Rings \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/formant_oscillator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class String -{ - public: - String() {} - ~String() {} - - /** Initialize the module. - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Clear the delay line */ - void Reset(); - - /** Get the next floating point sample - \param in Signal to excite the string. - */ - float Process(const float in); - - /** Set the string frequency. - \param freq Frequency in Hz - */ - void SetFreq(float freq); - - /** Set the string's behavior. - \param -1 to 0 is curved bridge, 0 to 1 is dispersion. - */ - void SetNonLinearity(float non_linearity_amount); - - /** Set the string's overall brightness - \param Works 0-1. - */ - void SetBrightness(float brightness); - - /** Set the string's decay time. - \param damping Works 0-1. - */ - void SetDamping(float damping); - - - private: - static constexpr size_t kDelayLineSize = 1024; - - enum StringNonLinearity - { - NON_LINEARITY_CURVED_BRIDGE, - NON_LINEARITY_DISPERSION - }; - - template - float ProcessInternal(const float in); - - DelayLine string_; - DelayLine stretch_; - - float frequency_, non_linearity_amount_, brightness_, damping_; - - float sample_rate_; - - OnePole iir_damping_filter_; - - DcBlock dc_blocker_; - - CrossFade crossfade_; - - float dispersion_noise_; - float curved_bridge_; - - // Very crappy linear interpolation upsampler used for low pitches that - // do not fit the delay line. Rarely used. - float src_phase_; - float out_sample_[2]; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/PhysicalModeling/drip.cpp b/src/daisysp/PhysicalModeling/drip.cpp deleted file mode 100644 index c568d63..0000000 --- a/src/daisysp/PhysicalModeling/drip.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "drip.h" -#include -#include -#include "../Utility/dsp.h" - -using namespace daisysp; - -#define WUTR_SOUND_DECAY 0.95f -#define WUTR_SYSTEM_DECAY 0.996f -#define WUTR_GAIN 1.0f -#define WUTR_NUM_SOURCES 10.0f -#define WUTR_CENTER_FREQ0 450.0f -#define WUTR_CENTER_FREQ1 600.0f -#define WUTR_CENTER_FREQ2 750.0f -#define WUTR_RESON 0.9985f -#define WUTR_FREQ_SWEEP 1.0001f -#define MAX_SHAKE 2000.0f - -int Drip::my_random(int max) -{ - return (rand() % (max + 1)); -} - -float Drip::noise_tick() -{ - float temp; - temp = 1.0f * rand() - 1073741823.5f; - return temp * (1.0f / 1073741823.0f); -} - -void Drip::Init(float sample_rate, float dettack) -{ - sample_rate_ = sample_rate; - float temp; - dettack_ = dettack; - num_tubes_ = 10; - damp_ = 0.2f; - shake_max_ = 0.0f; - freq_ = 450.0f; - freq1_ = 600.0f; - freq2_ = 720.0f; - amp_ = 0.3f; - - snd_level_ = 0.0; - float tpidsr = 2.0 * PI_F / sample_rate_; - - kloop_ = (sample_rate_ * dettack_); - outputs00_ = 0.0f; - outputs01_ = 0.0f; - outputs10_ = 0.0f; - outputs11_ = 0.0f; - outputs20_ = 0.0f; - outputs21_ = 0.0f; - - total_energy_ = 0.0f; - - center_freqs0_ = res_freq0_ = WUTR_CENTER_FREQ0; - center_freqs1_ = res_freq1_ = WUTR_CENTER_FREQ1; - center_freqs2_ = res_freq2_ = WUTR_CENTER_FREQ2; - num_objects_save_ = num_objects_ = WUTR_NUM_SOURCES; - sound_decay_ = WUTR_SOUND_DECAY; - system_decay_ = WUTR_SYSTEM_DECAY; - temp = logf(WUTR_NUM_SOURCES) * WUTR_GAIN / WUTR_NUM_SOURCES; - gains0_ = gains1_ = gains2_ = temp; - coeffs01_ = WUTR_RESON * WUTR_RESON; - coeffs00_ = -WUTR_RESON * 2.0f * cosf(WUTR_CENTER_FREQ0 * tpidsr); - coeffs11_ = WUTR_RESON * WUTR_RESON; - coeffs10_ = -WUTR_RESON * 2.0f * cosf(WUTR_CENTER_FREQ1 * tpidsr); - coeffs21_ = WUTR_RESON * WUTR_RESON; - coeffs20_ = -WUTR_RESON * 2.0f * cosf(WUTR_CENTER_FREQ2 * tpidsr); - - shake_energy_ = amp_ * 1.0f * MAX_SHAKE * 0.1f; - shake_damp_ = 0.0f; - if(shake_energy_ > MAX_SHAKE) - shake_energy_ = MAX_SHAKE; - shake_max_save_ = 0.0f; - num_objects_ = 10.0f; - finalZ0_ = finalZ1_ = finalZ2_ = 0.0f; -} - -float Drip::Process(bool trig) -{ - float data; - float lastOutput; - - float tpidsr = 2.0f * PI_F / sample_rate_; - - if(trig) - { - Init(sample_rate_, dettack_); - } - if(num_tubes_ != 0.0f && num_tubes_ != num_objects_) - { - num_objects_ = num_tubes_; - if(num_objects_ < 1.0f) - { - num_objects_ = 1.0f; - } - } - if(freq_ != 0.0f && freq_ != res_freq0_) - { - res_freq0_ = freq_; - coeffs00_ = -WUTR_RESON * 2.0f * cosf(res_freq0_ * tpidsr); - } - if(damp_ != 0.0f && damp_ != shake_damp_) - { - shake_damp_ = damp_; - system_decay_ = WUTR_SYSTEM_DECAY + (shake_damp_ * 0.002f); - } - if(shake_max_ != 0.0f && shake_max_ != shake_max_save_) - { - shake_max_save_ = shake_max_; - shake_energy_ += shake_max_save_ * MAX_SHAKE * 0.1f; - if(shake_energy_ > MAX_SHAKE) - shake_energy_ = MAX_SHAKE; - } - if(freq1_ != 0.0f && freq1_ != res_freq1_) - { - res_freq1_ = freq1_; - coeffs10_ = -WUTR_RESON * 2.0f * cosf(res_freq1_ * tpidsr); - } - if(freq2_ != 0.0f && freq2_ != res_freq2_) - { - res_freq2_ = freq2_; - coeffs20_ = -WUTR_RESON * 2.0f * cosf(res_freq2_ * tpidsr); - } - if((--kloop_) == 0.0f) - { - shake_energy_ = 0.0f; - } - - float shakeEnergy = shake_energy_; - float systemDecay = system_decay_; - float sndLevel = snd_level_; - float num_objects = num_objects_; - float soundDecay = sound_decay_; - float inputs0, inputs1, inputs2; - - shakeEnergy *= systemDecay; /* Exponential system decay */ - - sndLevel = shakeEnergy; - if(my_random(32767) < num_objects) - { - int j; - j = my_random(3); - if(j == 0) - { - center_freqs0_ = res_freq1_ * (0.75f + (0.25f * noise_tick())); - gains0_ = fabsf(noise_tick()); - } - else if(j == 1) - { - center_freqs1_ = res_freq1_ * (1.0f + (0.25f * noise_tick())); - gains1_ = fabsf(noise_tick()); - } - else - { - center_freqs2_ = res_freq1_ * (1.25f + (0.25f * noise_tick())); - gains2_ = fabsf(noise_tick()); - } - } - - gains0_ *= WUTR_RESON; - if(gains0_ > 0.001f) - { - center_freqs0_ *= WUTR_FREQ_SWEEP; - coeffs00_ = -WUTR_RESON * 2.0f * cosf(center_freqs0_ * tpidsr); - } - gains1_ *= WUTR_RESON; - if(gains1_ > 0.00f) - { - center_freqs1_ *= WUTR_FREQ_SWEEP; - coeffs10_ = -WUTR_RESON * 2.0f * cosf(center_freqs1_ * tpidsr); - } - gains2_ *= WUTR_RESON; - if(gains2_ > 0.001f) - { - center_freqs2_ *= WUTR_FREQ_SWEEP; - coeffs20_ = -WUTR_RESON * 2.0f * cosf(center_freqs2_ * tpidsr); - } - - sndLevel *= soundDecay; - inputs0 = sndLevel; - inputs0 *= noise_tick(); - inputs1 = inputs0 * gains1_; - inputs2 = inputs0 * gains2_; - inputs0 *= gains0_; - inputs0 -= outputs00_ * coeffs00_; - inputs0 -= outputs01_ * coeffs01_; - outputs01_ = outputs00_; - outputs00_ = inputs0; - data = gains0_ * outputs00_; - inputs1 -= outputs10_ * coeffs10_; - inputs1 -= outputs11_ * coeffs11_; - outputs11_ = outputs10_; - outputs10_ = inputs1_; - data += gains1_ * outputs10_; - inputs2 -= outputs20_ * coeffs20_; - inputs2 -= outputs21_ * coeffs21_; - outputs21_ = outputs20_; - outputs20_ = inputs2_; - data += gains2_ * outputs20_; - - finalZ2_ = finalZ1_; - finalZ1_ = finalZ0_; - finalZ0_ = data * 4.0f; - - lastOutput = finalZ2_ - finalZ0_; - lastOutput *= 0.005f; - shake_energy_ = shakeEnergy; - snd_level_ = sndLevel; - return lastOutput; -} diff --git a/src/daisysp/PhysicalModeling/drip.h b/src/daisysp/PhysicalModeling/drip.h deleted file mode 100644 index abaccd5..0000000 --- a/src/daisysp/PhysicalModeling/drip.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_DRIP_H -#define DSY_DRIP_H - -#include -#ifdef __cplusplus - -/** @file drip.h */ - -namespace daisysp -{ -/** - Imitates the sound of dripping water via Physical Modeling Synthesis. \n - Ported from soundpipe by Ben Sergentanis, May 2020 - @author Perry Cook - @date 2000 -*/ -class Drip -{ - public: - Drip() {} - ~Drip() {} - - /** - Initializes the Drip module. - \param sample_rate The sample rate of the audio engine being run. - \param dettack The period of time over which all sound is stopped. - */ - void Init(float sample_rate, float dettack); - - /** - Process the next floating point sample. - \param trig If true, begins a new drip. - \return Next sample. - */ - float Process(bool trig); - - private: - float gains0_, gains1_, gains2_, kloop_, dettack_, num_tubes_, damp_, - shake_max_, freq_, freq1_, freq2_, amp_, snd_level_, outputs00_, - outputs01_, outputs10_, outputs11_, outputs20_, outputs21_, - total_energy_, center_freqs0_, center_freqs1_, center_freqs2_, - num_objects_save_, sound_decay_, system_decay_, finalZ0_, finalZ1_, - finalZ2_, coeffs01_, coeffs00_, coeffs11_, coeffs10_, coeffs21_, - coeffs20_, shake_energy_, shake_damp_, shake_max_save_, num_objects_, - sample_rate_, res_freq0_, res_freq1_, res_freq2_, inputs1_, inputs2_; - - int my_random(int max); - float noise_tick(); -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/PhysicalModeling/modalvoice.cpp b/src/daisysp/PhysicalModeling/modalvoice.cpp deleted file mode 100644 index b34dcb5..0000000 --- a/src/daisysp/PhysicalModeling/modalvoice.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "modalvoice.h" -#include - -using namespace daisysp; - -void ModalVoice::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - aux_ = 0.f; - - excitation_filter_.Init(); - resonator_.Init(0.015f, 24, sample_rate_); - excitation_filter_.Init(); - dust_.Init(); - - SetSustain(false); - SetFreq(440.f); - SetAccent(.3f); - SetStructure(.6f); - SetBrightness(.8f); - SetDamping(.6f); -} - -void ModalVoice::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void ModalVoice::Trig() -{ - trig_ = true; -} - -void ModalVoice::SetFreq(float freq) -{ - resonator_.SetFreq(freq); - f0_ = freq / sample_rate_; - f0_ = fclamp(f0_, 0.f, .25f); -} - -void ModalVoice::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void ModalVoice::SetStructure(float structure) -{ - resonator_.SetStructure(structure); -} - -void ModalVoice::SetBrightness(float brightness) -{ - brightness_ = fclamp(brightness, 0.f, 1.f); - density_ = brightness_ * brightness_; -} - -void ModalVoice::SetDamping(float damping) -{ - damping_ = fclamp(damping, 0.f, 1.f); -} - -float ModalVoice::GetAux() -{ - return aux_; -} - -float ModalVoice::Process(bool trigger) -{ - float brightness = brightness_ + 0.25f * accent_ * (1.0f - brightness_); - float damping = damping_ + 0.25f * accent_ * (1.0f - damping_); - - const float range = sustain_ ? 36.0f : 60.0f; - const float f = sustain_ ? 4.0f * f0_ : 2.0f * f0_; - const float cutoff = fmin( - f - * powf(2.f, - kOneTwelfth - * ((brightness * (2.0f - brightness) - 0.5f) * range)), - 0.499f); - const float q = sustain_ ? 0.7f : 1.5f; - - float temp = 0.f; - // Synthesize excitation signal. - if(sustain_) - { - const float dust_f = 0.00005f + 0.99995f * density_ * density_; - dust_.SetDensity(dust_f); - temp = dust_.Process() * (4.0f - dust_f * 3.0f) * accent_; - } - else if(trigger || trig_) - { - const float attenuation = 1.0f - damping * 0.5f; - const float amplitude = (0.12f + 0.08f * accent_) * attenuation; - temp = amplitude * powf(2.f, kOneTwelfth * (cutoff * cutoff * 24.0f)) - / cutoff; - trig_ = false; - } - - const float one = 1.0f; - excitation_filter_.Process::LOW_PASS, false>( - &cutoff, &q, &one, temp, &temp); - - aux_ = temp; - - resonator_.SetBrightness(brightness); - resonator_.SetDamping(damping); - - return resonator_.Process(temp); -} \ No newline at end of file diff --git a/src/daisysp/PhysicalModeling/modalvoice.h b/src/daisysp/PhysicalModeling/modalvoice.h deleted file mode 100644 index 1be3c92..0000000 --- a/src/daisysp/PhysicalModeling/modalvoice.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_MODAL_H -#define DSY_MODAL_H - -#include -#include "../Filters/svf.h" -#include "../PhysicalModeling/resonator.h" -#include "../Noise/dust.h" -#ifdef __cplusplus - -/** @file modalvoice.h */ - -namespace daisysp -{ -/** - @brief Simple modal synthesis voice with a mallet exciter: click -> LPF -> resonator. - @author Ben Sergentanis - @date Jan 2021 - The click can be replaced by continuous white noise. \n \n - Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/modal_voice.h \n - and pichenettes/eurorack/plaits/dsp/physical_modelling/modal_voice.cc \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class ModalVoice -{ - public: - ModalVoice() {} - ~ModalVoice() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get the next sample - \param trigger Strike the resonator. Defaults to false. - */ - float Process(bool trigger = false); - - /** Continually excite the resonator with noise. - \param sustain True turns on the noise. - */ - void SetSustain(bool sustain); - - /** Strike the resonator. */ - void Trig(); - - /** Set the resonator root frequency. - \param freq Frequency in Hz. - */ - void SetFreq(float freq); - - /** Hit the resonator a bit harder. - \param accent Works 0-1. - */ - void SetAccent(float accent); - - /** Changes the general charater of the resonator (stiffness, brightness) - \param structure Works best from 0-1 - */ - void SetStructure(float structure); - - /** Set the brighness of the resonator, and the noise density. - \param brightness Works best 0-1 - */ - void SetBrightness(float brightness); - - /** How long the resonant body takes to decay. - \param damping Works best 0-1 - */ - void SetDamping(float damping); - - /** Get the raw excitation signal. Must call Process() first. */ - float GetAux(); - - private: - float sample_rate_; - - bool sustain_, trig_; - float f0_, structure_, brightness_, damping_; - float density_, accent_; - float aux_; - - ResonatorSvf<1> excitation_filter_; - Resonator resonator_; - Dust dust_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/PhysicalModeling/resonator.cpp b/src/daisysp/PhysicalModeling/resonator.cpp deleted file mode 100644 index cdef166..0000000 --- a/src/daisysp/PhysicalModeling/resonator.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "resonator.h" -#include - -using namespace daisysp; - -void Resonator::Init(float position, int resolution, float sample_rate) -{ - sample_rate_ = sample_rate; - - SetFreq(440.f); - SetStructure(.5f); - SetBrightness(.5f); - SetDamping(.5f); - - resolution_ = fmin(resolution, kMaxNumModes); - - for(int i = 0; i < resolution; ++i) - { - mode_amplitude_[i] = cos(position * TWOPI_F) * 0.25f; - } - - for(int i = 0; i < kMaxNumModes / kModeBatchSize; ++i) - { - mode_filters_[i].Init(); - } -} - -inline float NthHarmonicCompensation(int n, float stiffness) -{ - float stretch_factor = 1.0f; - for(int i = 0; i < n - 1; ++i) - { - stretch_factor += stiffness; - if(stiffness < 0.0f) - { - stiffness *= 0.93f; - } - else - { - stiffness *= 0.98f; - } - } - return 1.0f / stretch_factor; -} - -float Resonator::Process(const float in) -{ - //convert Hz to cycles / sample - float out = 0.f; - - float stiffness = CalcStiff(structure_); - float f0 = frequency_ * NthHarmonicCompensation(3, stiffness); - float brightness = brightness_; - - float harmonic = f0; - float stretch_factor = 1.0f; - - float input = damping_ * 79.7f; - float q_sqrt = powf(2.f, input * ratiofrac_); - - float q = 500.0f * q_sqrt * q_sqrt; - brightness *= 1.0f - structure_ * 0.3f; - brightness *= 1.0f - damping_ * 0.3f; - float q_loss = brightness * (2.0f - brightness) * 0.85f + 0.15f; - - float mode_q[kModeBatchSize]; - float mode_f[kModeBatchSize]; - float mode_a[kModeBatchSize]; - int batch_counter = 0; - - ResonatorSvf* batch_processor = &mode_filters_[0]; - - for(int i = 0; i < resolution_; ++i) - { - float mode_frequency = harmonic * stretch_factor; - if(mode_frequency >= 0.499f) - { - mode_frequency = 0.499f; - } - const float mode_attenuation = 1.0f - mode_frequency * 2.0f; - - mode_f[batch_counter] = mode_frequency; - mode_q[batch_counter] = 1.0f + mode_frequency * q; - mode_a[batch_counter] = mode_amplitude_[i] * mode_attenuation; - ++batch_counter; - - if(batch_counter == kModeBatchSize) - { - batch_counter = 0; - batch_processor - ->Process::BAND_PASS, true>( - mode_f, mode_q, mode_a, in, &out); - ++batch_processor; - } - - stretch_factor += stiffness; - if(stiffness < 0.0f) - { - // Make sure that the partials do not fold back into negative frequencies. - stiffness *= 0.93f; - } - else - { - // This helps adding a few extra partials in the highest frequencies. - stiffness *= 0.98f; - } - harmonic += f0; - q *= q_loss; - } - - return out; -} - -void Resonator::SetFreq(float freq) -{ - frequency_ = freq / sample_rate_; -} - -void Resonator::SetStructure(float structure) -{ - structure_ = fmax(fmin(structure, 1.f), 0.f); -} - -void Resonator::SetBrightness(float brightness) -{ - brightness_ = fmax(fmin(brightness, 1.f), 0.f); -} - -void Resonator::SetDamping(float damping) -{ - damping_ = fmax(fmin(damping, 1.f), 0.f); -} - -float Resonator::CalcStiff(float sig) -{ - if(sig < .25f) - { - sig = .25 - sig; - sig = -sig * .25; - } - else if(sig < .3f) - { - sig = 0.f; - } - else if(sig < .9f) - { - sig -= .3f; - sig *= stiff_frac_2; - } - else - { - sig -= .9f; - sig *= 10; // div by .1 - sig *= sig; - sig = 1.5 - cos(sig * PI_F) * .5f; - } - return sig; -} diff --git a/src/daisysp/PhysicalModeling/resonator.h b/src/daisysp/PhysicalModeling/resonator.h deleted file mode 100644 index 4229ba2..0000000 --- a/src/daisysp/PhysicalModeling/resonator.h +++ /dev/null @@ -1,191 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_RESONATOR_H -#define DSY_RESONATOR_H - -#include -#include -#include "../Utility/dsp.h" -#ifdef __cplusplus - - -/** @file resonator.h */ - -namespace daisysp -{ -// We render 4 modes simultaneously since there are enough registers to hold -// all state variables. -/** - @brief SVF for use in the Resonator Class \n - @author Ported by Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/resonator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -template -class ResonatorSvf -{ - public: - enum FilterMode - { - LOW_PASS, - BAND_PASS, - BAND_PASS_NORMALIZED, - HIGH_PASS - }; - - ResonatorSvf() {} - ~ResonatorSvf() {} - - void Init() - { - for(int i = 0; i < batch_size; ++i) - { - state_1_[i] = state_2_[i] = 0.0f; - } - } - - template - void Process(const float* f, - const float* q, - const float* gain, - const float in, - float* out) - { - float g[batch_size]; - float r[batch_size]; - float r_plus_g[batch_size]; - float h[batch_size]; - float state_1[batch_size]; - float state_2[batch_size]; - float gains[batch_size]; - for(int i = 0; i < batch_size; ++i) - { - g[i] = fasttan(f[i]); - r[i] = 1.0f / q[i]; - h[i] = 1.0f / (1.0f + r[i] * g[i] + g[i] * g[i]); - r_plus_g[i] = r[i] + g[i]; - state_1[i] = state_1_[i]; - state_2[i] = state_2_[i]; - gains[i] = gain[i]; - } - - float s_in = in; - float s_out = 0.0f; - for(int i = 0; i < batch_size; ++i) - { - const float hp - = (s_in - r_plus_g[i] * state_1[i] - state_2[i]) * h[i]; - const float bp = g[i] * hp + state_1[i]; - state_1[i] = g[i] * hp + bp; - const float lp = g[i] * bp + state_2[i]; - state_2[i] = g[i] * bp + lp; - s_out += gains[i] * ((mode == LOW_PASS) ? lp : bp); - } - if(add) - { - *out++ += s_out; - } - else - { - *out++ = s_out; - } - - for(int i = 0; i < batch_size; ++i) - { - state_1_[i] = state_1[i]; - state_2_[i] = state_2[i]; - } - } - - private: - static constexpr float kPiPow3 = PI_F * PI_F * PI_F; - static constexpr float kPiPow5 = kPiPow3 * PI_F * PI_F; - static inline float fasttan(float f) - { - const float a = 3.260e-01 * kPiPow3; - const float b = 1.823e-01 * kPiPow5; - float f2 = f * f; - return f * (PI_F + f2 * (a + b * f2)); - } - - float state_1_[batch_size]; - float state_2_[batch_size]; -}; - - -/** - @brief Resonant Body Simulation - @author Ported by Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/resonator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class Resonator -{ - public: - Resonator() {} - ~Resonator() {} - - /** Initialize the module - \param position Offset the phase of the amplitudes. 0-1 - \param resolution Quality vs speed scalar - \param sample_rate Samplerate of the audio engine being run. - */ - void Init(float position, int resolution, float sample_rate); - - /** Get the next sample_rate - \param in The signal to excited the resonant body - */ - float Process(const float in); - - /** Resonator frequency. - \param freq Frequency in Hz. - */ - void SetFreq(float freq); - - /** Changes the general charater of the resonator (stiffness, brightness) - \param structure Works best from 0-1 - */ - void SetStructure(float structure); - - /** Set the brighness of the resonator - \param brightness Works best 0-1 - */ - void SetBrightness(float brightness); - - /** How long the resonant body takes to decay. - \param damping Works best 0-1 - */ - void SetDamping(float damping); - - private: - int resolution_; - float frequency_, brightness_, structure_, damping_; - - static constexpr int kMaxNumModes = 24; - static constexpr int kModeBatchSize = 4; - static constexpr float ratiofrac_ = 1.f / 12.f; - static constexpr float stiff_frac_ = 1.f / 64.f; - static constexpr float stiff_frac_2 = 1.f / .6f; - - float sample_rate_; - - float CalcStiff(float sig); - - float mode_amplitude_[kMaxNumModes]; - ResonatorSvf mode_filters_[kMaxNumModes / kModeBatchSize]; -}; - -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/PhysicalModeling/stringvoice.cpp b/src/daisysp/PhysicalModeling/stringvoice.cpp deleted file mode 100644 index 1da2b1c..0000000 --- a/src/daisysp/PhysicalModeling/stringvoice.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "stringvoice.h" -#include -#include "../Utility/dsp.h" - -using namespace daisysp; - -void StringVoice::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - excitation_filter_.Init(sample_rate); - string_.Init(sample_rate_); - dust_.Init(); - remaining_noise_samples_ = 0; - - SetSustain(false); - SetFreq(440.f); - SetAccent(.8f); - SetStructure(.7f); - SetBrightness(.2f); - SetDamping(.7f); -} - -void StringVoice::Reset() -{ - string_.Reset(); -} - -void StringVoice::SetSustain(bool sustain) -{ - sustain_ = sustain; -} - -void StringVoice::Trig() -{ - trig_ = true; -} - -void StringVoice::SetFreq(float freq) -{ - string_.SetFreq(freq); - f0_ = freq / sample_rate_; - f0_ = fclamp(f0_, 0.f, .25f); -} - -void StringVoice::SetAccent(float accent) -{ - accent_ = fclamp(accent, 0.f, 1.f); -} - -void StringVoice::SetStructure(float structure) -{ - structure = fclamp(structure, 0.f, 1.f); - const float non_linearity - = structure < 0.24f - ? (structure - 0.24f) * 4.166f - : (structure > 0.26f ? (structure - 0.26f) * 1.35135f : 0.0f); - string_.SetNonLinearity(non_linearity); -} - -void StringVoice::SetBrightness(float brightness) -{ - brightness_ = fclamp(brightness, 0.f, 1.f); - density_ = brightness_ * brightness_; -} - -void StringVoice::SetDamping(float damping) -{ - damping_ = fclamp(damping, 0.f, 1.f); -} - -float StringVoice::GetAux() -{ - return aux_; -} - -float StringVoice::Process(bool trigger) -{ - const float brightness = brightness_ + .25 * accent_ * (1.f - brightness_); - const float damping = damping_ + .25 * accent_ * (1.f - damping_); - - // Synthesize excitation signal. - if(trigger || trig_ || sustain_) - { - trig_ = false; - const float range = 72.0f; - const float f = 4.0f * f0_; - const float cutoff = fmin( - f - * powf(2.f, - kOneTwelfth * (brightness * (2.0f - brightness) - 0.5f) - * range), - 0.499f); - const float q = sustain_ ? 1.0f : 0.5f; - remaining_noise_samples_ = static_cast(1.0f / f0_); - excitation_filter_.SetFreq(cutoff * sample_rate_); - excitation_filter_.SetRes(q); - } - - float temp = 0.f; - - if(sustain_) - { - const float dust_f = 0.00005f + 0.99995f * density_ * density_; - dust_.SetDensity(dust_f); - temp = dust_.Process() * (8.0f - dust_f * 6.0f) * accent_; - } - else if(remaining_noise_samples_) - { - temp = 2.0f * rand() * kRandFrac - 1.0f; - remaining_noise_samples_--; - remaining_noise_samples_ = DSY_MAX(remaining_noise_samples_, 0.f); - } - - excitation_filter_.Process(temp); - temp = excitation_filter_.Low(); - - aux_ = temp; - - string_.SetBrightness(brightness); - string_.SetDamping(damping); - - return string_.Process(temp); -} diff --git a/src/daisysp/PhysicalModeling/stringvoice.h b/src/daisysp/PhysicalModeling/stringvoice.h deleted file mode 100644 index 9114df1..0000000 --- a/src/daisysp/PhysicalModeling/stringvoice.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_STRINGVOICE_H -#define DSY_STRINGVOICE_H - -#include "../Filters/svf.h" -#include "../PhysicalModeling/KarplusString.h" -#include "../Noise/dust.h" -#include -#ifdef __cplusplus - -/** @file stringvoice.h */ - -namespace daisysp -{ -/** - @brief Extended Karplus-Strong, with all the niceties from Rings - @author Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/string_voice.h \n - and pichenettes/eurorack/plaits/dsp/physical_modelling/string_voice.cc \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class StringVoice -{ - public: - StringVoice() {} - ~StringVoice() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Reset the string oscillator */ - void Reset(); - - /** Get the next sample - \param trigger Strike the string. Defaults to false. - */ - float Process(bool trigger = false); - - /** Continually excite the string with noise. - \param sustain True turns on the noise. - */ - void SetSustain(bool sustain); - - /** Strike the string. */ - void Trig(); - - /** Set the string root frequency. - \param freq Frequency in Hz. - */ - void SetFreq(float freq); - - /** Hit the string a bit harder. Influences brightness and decay. - \param accent Works 0-1. - */ - void SetAccent(float accent); - - /** Changes the string's nonlinearity (string type). - \param structure Works 0-1. 0-.26 is curved bridge, .26-1 is dispersion. - */ - void SetStructure(float structure); - - /** Set the brighness of the string, and the noise density. - \param brightness Works best 0-1 - */ - void SetBrightness(float brightness); - - /** How long the resonant body takes to decay relative to the accent level. - \param damping Works best 0-1. Full damp is only achieved with full accent. - */ - void SetDamping(float damping); - - /** Get the raw excitation signal. Must call Process() first. */ - float GetAux(); - - private: - float sample_rate_; - - bool sustain_, trig_; - float f0_, brightness_, damping_; - float density_, accent_; - float aux_; - - Dust dust_; - Svf excitation_filter_; - String string_; - size_t remaining_noise_samples_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Sampling/granularplayer.cpp b/src/daisysp/Sampling/granularplayer.cpp deleted file mode 100644 index 2456548..0000000 --- a/src/daisysp/Sampling/granularplayer.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "granularplayer.h" - -using namespace daisysp; - -void GranularPlayer::Init(float* sample, int size, float sample_rate) -{ - /*initialize variables to private members*/ - sample_ = sample; - size_ = size; - sample_rate_ = sample_rate; - /*initialize phasors. phs2_ is initialized with a phase offset of 0.5f to create an overlapping effect*/ - phs_.Init(sample_rate_, 0, 0); - phsImp_.Init(sample_rate_, 0, 0); - phs2_.Init(sample_rate_, 0, 0.5f); - phsImp2_.Init(sample_rate_, 0, 0); - /*calculate sample frequency*/ - sample_frequency_ = sample_rate_ / size_; - /*initialize half cosine envelope*/ - for(int i = 0; i < 256; i++) - { - cosEnv_[i] = sinf((i / 256.0f) * M_PI); - } -} - -uint32_t GranularPlayer::WrapIdx(uint32_t idx, uint32_t sz) -{ - /*wraps idx to sz*/ - if(idx > sz) - { - idx = idx - sz; - return idx; - } - - return idx; -} - -float GranularPlayer::CentsToRatio(float cents) -{ - /*converts cents to ratio*/ - return powf(2.0f, cents / 1200.0f); -} - - -float GranularPlayer::MsToSamps(float ms, float samplerate) -{ - /*converts milliseconds to number of samples*/ - return (ms * 0.001f) * samplerate; -} - -float GranularPlayer::NegativeInvert(Phasor* phs, float frequency) -{ - /*inverts the phase of the phasor if the frequency is negative, mimicking pure data's phasor~ object*/ - return (frequency > 0) ? phs->Process() : ((phs->Process() * -1) + 1); -} - -float GranularPlayer::Process(float speed, - float transposition, - float grain_size) -{ - grain_size_ = grain_size; - speed_ = speed * sample_frequency_; - transposition_ = (CentsToRatio(transposition) - speed) - * (grain_size >= 1 ? 1000 / grain_size_ : 1); - phs_.SetFreq(fabs((speed_ / 2))); - phs2_.SetFreq(fabs((speed_ / 2))); - phsImp_.SetFreq(fabs(transposition_)); - phsImp2_.SetFreq(fabs(transposition_)); - idxSpeed_ = NegativeInvert(&phs_, speed_) * size_; - idxSpeed2_ = NegativeInvert(&phs2_, speed_) * size_; - idxTransp_ = (NegativeInvert(&phsImp_, transposition_) - * MsToSamps(grain_size_, sample_rate_)); - idxTransp2_ = (NegativeInvert(&phsImp2_, transposition_) - * MsToSamps(grain_size_, sample_rate_)); - idx_ = WrapIdx((uint32_t)(idxSpeed_ + idxTransp_), size_); - idx2_ = WrapIdx((uint32_t)(idxSpeed2_ + idxTransp2_), size_); - sig_ = sample_[idx_] * cosEnv_[(uint32_t)(phs_.Process() * 256)]; - sig2_ = sample_[idx2_] * cosEnv_[(uint32_t)(phs2_.Process() * 256)]; - return (sig_ + sig2_) / 2; -} \ No newline at end of file diff --git a/src/daisysp/Sampling/granularplayer.h b/src/daisysp/Sampling/granularplayer.h deleted file mode 100644 index cdc3d10..0000000 --- a/src/daisysp/Sampling/granularplayer.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Vinícius Fernandes - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_GRANULARPLAYER_H -#define DSY_GRANULARPLAYER_H - -#include -#include -#include "../Control/phasor.h" -#ifdef __cplusplus -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* pi */ -#endif - -namespace daisysp -{ -/** GranularPlayer Module - - Date: November, 2023 - - Author: Vinícius Fernandes - - GranularPlayer is a lookup table player that provides independent time stretching and pitch shifting - via granulation. - Inspired by the grain.player object from else pure data's library. -*/ - -class GranularPlayer -{ - public: - GranularPlayer() {} - ~GranularPlayer() {} - - /** Initializes the GranularPlayer module. - \param sample pointer to the sample to be played - \param size number of elements in the sample array - \param sample_rate audio engine sample rate - */ - void Init(float* sample, int size, float sample_rate); - - /** Processes the granular player. - \param speed playback speed. 1 is normal speed, 2 is double speed, 0.5 is half speed, etc. Negative values play the sample backwards. - \param transposition transposition in cents. 100 cents is one semitone. Negative values transpose down, positive values transpose up. - \param grain_size grain size in milliseconds. 1 is 1 millisecond, 1000 is 1 second. Does not accept negative values. Minimum value is 1. - */ - float Process(float speed, float transposition, float grain_size); - - private: - //Wraps an index to the size of the sample array - uint32_t WrapIdx(uint32_t idx, uint32_t size); - - //Converts cents(1/100th of a semitone) to a ratio - float CentsToRatio(float cents); - - //Converts milliseconds to number of samples - float MsToSamps(float ms, float samplerate); - - //Inverts the phase of the phasor if the frequency is negative, mimicking pure data's phasor~ object - float NegativeInvert(Phasor* phs, float frequency); - - - float* sample_; //pointer to the sample to be played - float sample_rate_; //audio engine sample rate - int size_; //number of elements in the sample array - float grain_size_; //grain size in milliseconds - float speed_; //processed playback speed. - float transposition_; //processed transpotion. - float sample_frequency_; - float cosEnv_[256] = {0}; //cosine envelope for crossfading between grains - float - idxTransp_; // Adjusted Transposition value contribution to idx of first grain - float - idxTransp2_; // Adjusted Transposition value contribution to idx of second grain - float idxSpeed_; // Adjusted Speed value contribution to idx of first grain - float - idxSpeed2_; // Adjusted Speed value contribution to idx of second grain - float sig_; // Output of first grain - float sig2_; // Output of second grain - - uint32_t idx_; // Index of first grain - uint32_t idx2_; // Index of second grain - - Phasor phs_; // Phasor for speed - Phasor phsImp_; // Phasor for transposition - Phasor phs2_; // Phasor for speed - Phasor phsImp2_; // Phasor for transposition -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/fm2.cpp b/src/daisysp/Synthesis/fm2.cpp deleted file mode 100644 index 4560013..0000000 --- a/src/daisysp/Synthesis/fm2.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "fm2.h" - -using namespace daisysp; - -void Fm2::Init(float samplerate) -{ - //init oscillators - car_.Init(samplerate); - mod_.Init(samplerate); - - //set some reasonable values - lfreq_ = 440.f; - lratio_ = 2.f; - SetFrequency(lfreq_); - SetRatio(lratio_); - - car_.SetAmp(1.f); - mod_.SetAmp(1.f); - - car_.SetWaveform(Oscillator::WAVE_SIN); - mod_.SetWaveform(Oscillator::WAVE_SIN); - - idx_ = 1.f; -} - -float Fm2::Process() -{ - if(lratio_ != ratio_ || lfreq_ != freq_) - { - lratio_ = ratio_; - lfreq_ = freq_; - car_.SetFreq(lfreq_); - mod_.SetFreq(lfreq_ * lratio_); - } - - float modval = mod_.Process(); - car_.PhaseAdd(modval * idx_); - return car_.Process(); -} - -void Fm2::SetFrequency(float freq) -{ - freq_ = fabsf(freq); -} - -void Fm2::SetRatio(float ratio) -{ - ratio_ = fabsf(ratio); -} - -void Fm2::SetIndex(float index) -{ - idx_ = index * kIdxScalar; -} - -float Fm2::GetIndex() -{ - return idx_ * kIdxScalarRecip; -} - -void Fm2::Reset() -{ - car_.Reset(); - mod_.Reset(); -} diff --git a/src/daisysp/Synthesis/fm2.h b/src/daisysp/Synthesis/fm2.h deleted file mode 100644 index 309c713..0000000 --- a/src/daisysp/Synthesis/fm2.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_FM2_H -#define DSY_FM2_H - -#include -#include "../Synthesis/oscillator.h" -#ifdef __cplusplus - -namespace daisysp -{ -/** Simple 2 operator FM synth voice. - - Date: November, 2020 - - Author: Ben Sergentanis -*/ - -class Fm2 -{ - public: - Fm2() {} - ~Fm2() {} - - /** Initializes the FM2 module. - \param samplerate - The sample rate of the audio engine being run. - */ - void Init(float samplerate); - - - /** Returns the next sample - */ - float Process(); - - /** Carrier freq. setter - \param freq Carrier frequency in Hz - */ - void SetFrequency(float freq); - - /** Set modulator freq. relative to carrier - \param ratio New modulator freq = carrier freq. * ratio - */ - void SetRatio(float ratio); - - /** Index setter - \param FM depth, 5 = 2PI rads - */ - void SetIndex(float index); - - /** Returns the current FM index. */ - float GetIndex(); - - /** Resets both oscillators */ - void Reset(); - - private: - static constexpr float kIdxScalar = 0.2f; - static constexpr float kIdxScalarRecip = 1.f / kIdxScalar; - - Oscillator mod_, car_; - float idx_; - float freq_, lfreq_, ratio_, lratio_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Synthesis/formantosc.cpp b/src/daisysp/Synthesis/formantosc.cpp deleted file mode 100644 index 986f82f..0000000 --- a/src/daisysp/Synthesis/formantosc.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "../Utility/dsp.h" -#include "formantosc.h" -#include - -using namespace daisysp; - -void FormantOscillator::Init(float sample_rate) -{ - carrier_phase_ = 0.0f; - formant_phase_ = 0.0f; - next_sample_ = 0.0f; - - carrier_frequency_ = 0.0f; - formant_frequency_ = 100.f; - phase_shift_ = 0.0f; - - sample_rate_ = sample_rate; -} - -float FormantOscillator::Process() -{ - float this_sample = next_sample_; - float next_sample = 0.0f; - carrier_phase_ += carrier_frequency_; - - if(carrier_phase_ >= 1.0f) - { - carrier_phase_ -= 1.0f; - float reset_time = carrier_phase_ / carrier_frequency_; - - float formant_phase_at_reset - = formant_phase_ + (1.0f - reset_time) * formant_frequency_; - float before = Sine(formant_phase_at_reset + phase_shift_ - + (ps_inc_ * (1.0f - reset_time))); - float after = Sine(0.0f + phase_shift_ + ps_inc_); - float discontinuity = after - before; - this_sample += discontinuity * ThisBlepSample(reset_time); - next_sample += discontinuity * NextBlepSample(reset_time); - formant_phase_ = reset_time * formant_frequency_; - } - else - { - formant_phase_ += formant_frequency_; - if(formant_phase_ >= 1.0f) - { - formant_phase_ -= 1.0f; - } - } - - phase_shift_ += ps_inc_; - ps_inc_ = 0.f; - - next_sample += Sine(formant_phase_ + phase_shift_); - - next_sample_ = next_sample; - return this_sample; -} - -void FormantOscillator::SetFormantFreq(float freq) -{ - //convert from Hz to phase_inc / sample - formant_frequency_ = freq / sample_rate_; - formant_frequency_ = formant_frequency_ >= .25f ? .25f : formant_frequency_; - formant_frequency_ - = formant_frequency_ <= -.25f ? -.25f : formant_frequency_; -} - -void FormantOscillator::SetCarrierFreq(float freq) -{ - //convert from Hz to phase_inc / sample - carrier_frequency_ = freq / sample_rate_; - carrier_frequency_ = carrier_frequency_ >= .25f ? .25f : carrier_frequency_; - carrier_frequency_ - = carrier_frequency_ <= -.25f ? -.25f : carrier_frequency_; -} - -void FormantOscillator::SetPhaseShift(float ps) -{ - ps_inc_ = ps - phase_shift_; -} - -inline float FormantOscillator::Sine(float phase) -{ - return sinf(phase * TWOPI_F); -} - -inline float FormantOscillator::ThisBlepSample(float t) -{ - return 0.5f * t * t; -} - -inline float FormantOscillator::NextBlepSample(float t) -{ - t = 1.0f - t; - return -0.5f * t * t; -} diff --git a/src/daisysp/Synthesis/formantosc.h b/src/daisysp/Synthesis/formantosc.h deleted file mode 100644 index 33fda86..0000000 --- a/src/daisysp/Synthesis/formantosc.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_FORMANTOSCILLATOR_H -#define DSY_FORMANTOSCILLATOR_H - -#include -#ifdef __cplusplus - -/** @file formantosc.h */ - -namespace daisysp -{ -/** - @brief Formant Oscillator Module. - @author Ben Sergentanis - @date Dec 2020 - Sinewave with aliasing-free phase reset. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/formant_oscillator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class FormantOscillator -{ - public: - FormantOscillator() {} - ~FormantOscillator() {} - - /** Initializes the FormantOscillator module. - \param sample_rate - The sample rate of the audio engine being run. - */ - void Init(float sample_rate); - - /** Get the next sample - */ - float Process(); - - /** Set the formant frequency. - \param freq Frequency in Hz - */ - void SetFormantFreq(float freq); - - /** Set the carrier frequency. This is the "main" frequency. - \param freq Frequency in Hz - */ - void SetCarrierFreq(float freq); - - /** Set the amount of phase shift - \param ps Typically 0-1. Works with other values though, including negative. - */ - void SetPhaseShift(float ps); - - private: - inline float Sine(float phase); - inline float ThisBlepSample(float t); - inline float NextBlepSample(float t); - - // Oscillator state. - float carrier_phase_; - float formant_phase_; - float next_sample_; - - // For interpolation of parameters. - float carrier_frequency_; - float formant_frequency_; - float phase_shift_; - float ps_inc_; - - float sample_rate_; - - //DISALLOW_COPY_AND_ASSIGN(FormantOscillator); -}; -} //namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/harmonic_osc.h b/src/daisysp/Synthesis/harmonic_osc.h deleted file mode 100644 index c936ba4..0000000 --- a/src/daisysp/Synthesis/harmonic_osc.h +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_HARMONIC_H -#define DSY_HARMONIC_H - -#include -#include "../Utility/dsp.h" -#ifdef __cplusplus - - -/** @file harmonic_osc.h */ -namespace daisysp -{ -/** - @brief Harmonic Oscillator Module based on Chebyshev polynomials. - @author Ben Sergentanis - @date Dec 2020 - Harmonic Oscillator Module based on Chebyshev polynomials \n - Works well for a small number of harmonics. For the higher order harmonics. \n - We need to reinitialize the recurrence by computing two high harmonics. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/harmonic_oscillator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -template -class HarmonicOscillator -{ - public: - HarmonicOscillator() {} - ~HarmonicOscillator() {} - - /** Initialize harmonic oscillator - \param sample_rate Audio engine samplerate - */ - void Init(float sample_rate) - { - sample_rate_ = sample_rate; - phase_ = 0.0f; - - for(int i = 0; i < num_harmonics; ++i) - { - amplitude_[i] = 0.0f; - newamplitude_[i] = 0.f; - } - amplitude_[0] = 1.f; - newamplitude_[0] = 1.f; - - SetFirstHarmIdx(1); - SetFreq(440.f); - - recalc_ = false; - } - - /** Get the next floating point sample */ - float Process() - { - if(recalc_) - { - recalc_ = false; - for(int i = 0; i < num_harmonics; ++i) - { - float f = frequency_ - * static_cast(first_harmonic_index_ + i); - if(f >= 0.5f) - { - f = 0.5f; - } - amplitude_[i] = newamplitude_[i] * (1.0f - f * 2.0f); - } - } - - phase_ += frequency_; - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - } - const float two_x = 2.0f * sinf(phase_ * TWOPI_F); - float previous, current; - if(first_harmonic_index_ == 1) - { - previous = 1.0f; - current = two_x * 0.5f; - } - else - { - const float k = first_harmonic_index_; - previous = sinf((phase_ * (k - 1.0f) + 0.25f) * TWOPI_F); - current = sinf((phase_ * k) * TWOPI_F); - } - - float sum = 0.0f; - for(int i = 0; i < num_harmonics; ++i) - { - sum += amplitude_[i] * current; - float temp = current; - current = two_x * current - previous; - previous = temp; - } - - return sum; - } - - /** Set the main frequency - \param freq Freq to be set in Hz. - */ - void SetFreq(float freq) - { - //convert from Hz to phase_inc / sample - freq = freq / sample_rate_; - freq = freq >= .5f ? .5f : freq; - freq = freq <= -.5f ? -.5f : freq; - recalc_ = cmp(freq, frequency_) || recalc_; - frequency_ = freq; - } - - /** Offset the set of harmonics. Passing in 3 means "harmonic 0" is the 3rd harm., 1 is the 4th, etc. - \param idx Default behavior is 1. Values < 0 default to 1. - */ - void SetFirstHarmIdx(int idx) - { - idx = idx < 1 ? 1 : idx; - recalc_ = cmp(idx, first_harmonic_index_) || recalc_; - first_harmonic_index_ = idx; - } - - /** Set the amplitudes of each harmonic of the root. - \param amplitudes Amplitudes to set. Sum of all amplitudes must be < 1. The array referenced must be at least as large as num_harmonics. - */ - void SetAmplitudes(const float* amplitudes) - { - for(int i = 0; i < num_harmonics; i++) - { - recalc_ = cmp(newamplitude_[i], amplitudes[i]) || recalc_; - newamplitude_[i] = amplitudes[i]; - } - } - - /** Sets one amplitude. Does nothing if idx out of range. - \param amp Amplitude to set - \param idx Which harmonic to set. - */ - void SetSingleAmp(const float amp, int idx) - { - if(idx < 0 || idx >= num_harmonics) - { - return; - } - recalc_ = cmp(amplitude_[idx], amp) || recalc_; - newamplitude_[idx] = amp; - } - - - private: - bool cmp(float a, float b) { return fabsf(a - b) > .000001f; } - - float sample_rate_; - float phase_; - float frequency_; - float amplitude_[num_harmonics]; - float newamplitude_[num_harmonics]; - bool recalc_; - - int first_harmonic_index_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/oscillator.cpp b/src/daisysp/Synthesis/oscillator.cpp deleted file mode 100644 index 8811b56..0000000 --- a/src/daisysp/Synthesis/oscillator.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "../Utility/dsp.h" -#include "oscillator.h" - -using namespace daisysp; -static inline float Polyblep(float phase_inc, float t); - -float Oscillator::Process() -{ - float out, t; - switch(waveform_) - { - case WAVE_SIN: out = sinf(phase_ * TWOPI_F); break; - case WAVE_TRI: - t = -1.0f + (2.0f * phase_); - out = 2.0f * (fabsf(t) - 0.5f); - break; - case WAVE_SAW: out = -1.0f * (((phase_ * 2.0f)) - 1.0f); break; - case WAVE_RAMP: out = ((phase_ * 2.0f)) - 1.0f; break; - case WAVE_SQUARE: out = phase_ < pw_ ? (1.0f) : -1.0f; break; - case WAVE_POLYBLEP_TRI: - t = phase_; - out = phase_ < 0.5f ? 1.0f : -1.0f; - out += Polyblep(phase_inc_, t); - out -= Polyblep(phase_inc_, fastmod1f(t + 0.5f)); - // Leaky Integrator: - // y[n] = A + x[n] + (1 - A) * y[n-1] - out = phase_inc_ * out + (1.0f - phase_inc_) * last_out_; - last_out_ = out; - out *= 4.f; // normalize amplitude after leaky integration - break; - case WAVE_POLYBLEP_SAW: - t = phase_; - out = (2.0f * t) - 1.0f; - out -= Polyblep(phase_inc_, t); - out *= -1.0f; - break; - case WAVE_POLYBLEP_SQUARE: - t = phase_; - out = phase_ < pw_ ? 1.0f : -1.0f; - out += Polyblep(phase_inc_, t); - out -= Polyblep(phase_inc_, fastmod1f(t + (1.0f - pw_))); - out *= 0.707f; // ? - break; - default: out = 0.0f; break; - } - phase_ += phase_inc_; - if(phase_ > 1.0f) - { - phase_ -= 1.0f; - eoc_ = true; - } - else - { - eoc_ = false; - } - eor_ = (phase_ - phase_inc_ < 0.5f && phase_ >= 0.5f); - - return out * amp_; -} - -float Oscillator::CalcPhaseInc(float f) -{ - return f * sr_recip_; -} - -static float Polyblep(float phase_inc, float t) -{ - float dt = phase_inc; - if(t < dt) - { - t /= dt; - return t + t - t * t - 1.0f; - } - else if(t > 1.0f - dt) - { - t = (t - 1.0f) / dt; - return t * t + t + t + 1.0f; - } - else - { - return 0.0f; - } -} diff --git a/src/daisysp/Synthesis/oscillator.h b/src/daisysp/Synthesis/oscillator.h deleted file mode 100644 index 6526484..0000000 --- a/src/daisysp/Synthesis/oscillator.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_OSCILLATOR_H -#define DSY_OSCILLATOR_H -#include -#include "../Utility/dsp.h" -#ifdef __cplusplus - -namespace daisysp -{ -/** Synthesis of several waveforms, including polyBLEP bandlimited waveforms. -*/ -class Oscillator -{ - public: - Oscillator() {} - ~Oscillator() {} - /** Choices for output waveforms, POLYBLEP are appropriately labeled. Others are naive forms. - */ - enum - { - WAVE_SIN, - WAVE_TRI, - WAVE_SAW, - WAVE_RAMP, - WAVE_SQUARE, - WAVE_POLYBLEP_TRI, - WAVE_POLYBLEP_SAW, - WAVE_POLYBLEP_SQUARE, - WAVE_LAST, - }; - - - /** Initializes the Oscillator - - \param sample_rate - sample rate of the audio engine being run, and the frequency that the Process function will be called. - - Defaults: - - freq_ = 100 Hz - - amp_ = 0.5 - - waveform_ = sine wave. - */ - void Init(float sample_rate) - { - sr_ = sample_rate; - sr_recip_ = 1.0f / sample_rate; - freq_ = 100.0f; - amp_ = 0.5f; - pw_ = 0.5f; - phase_ = 0.0f; - phase_inc_ = CalcPhaseInc(freq_); - waveform_ = WAVE_SIN; - eoc_ = true; - eor_ = true; - } - - - /** Changes the frequency of the Oscillator, and recalculates phase increment. - */ - inline void SetFreq(const float f) - { - freq_ = f; - phase_inc_ = CalcPhaseInc(f); - } - - - /** Sets the amplitude of the waveform. - */ - inline void SetAmp(const float a) { amp_ = a; } - /** Sets the waveform to be synthesized by the Process() function. - */ - inline void SetWaveform(const uint8_t wf) - { - waveform_ = wf < WAVE_LAST ? wf : WAVE_SIN; - } - /** Sets the pulse width for WAVE_SQUARE and WAVE_POLYBLEP_SQUARE (range 0 - 1) - */ - inline void SetPw(const float pw) { pw_ = fclamp(pw, 0.0f, 1.0f); } - - /** Returns true if cycle is at end of rise. Set during call to Process. - */ - inline bool IsEOR() { return eor_; } - - /** Returns true if cycle is at end of cycle. Set during call to Process. - */ - inline bool IsEOC() { return eoc_; } - - /** Returns true if cycle rising. - */ - inline bool IsRising() { return phase_ < 0.5f; } - - /** Returns true if cycle falling. - */ - inline bool IsFalling() { return phase_ >= 0.5f; } - - /** Processes the waveform to be generated, returning one sample. This should be called once per sample period. - */ - float Process(); - - - /** Adds a value 0.0-1.0 (equivalent to 0.0-TWO_PI) to the current phase. Useful for PM and "FM" synthesis. - */ - void PhaseAdd(float _phase) { phase_ += _phase; } - /** Resets the phase to the input argument. If no argumeNt is present, it will reset phase to 0.0; - */ - void Reset(float _phase = 0.0f) { phase_ = _phase; } - - private: - float CalcPhaseInc(float f); - uint8_t waveform_; - float amp_, freq_, pw_; - float sr_, sr_recip_, phase_, phase_inc_; - float last_out_, last_freq_; - bool eor_, eoc_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Synthesis/oscillatorbank.cpp b/src/daisysp/Synthesis/oscillatorbank.cpp deleted file mode 100644 index faeab3b..0000000 --- a/src/daisysp/Synthesis/oscillatorbank.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "../Utility/dsp.h" -#include "oscillatorbank.h" -#include - -using namespace daisysp; - -void OscillatorBank::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - phase_ = 0.0f; - next_sample_ = 0.0f; - segment_ = 0.0f; - - frequency_ = 0.f; - saw_8_gain_ = 0.0f; - saw_4_gain_ = 0.0f; - saw_2_gain_ = 0.0f; - saw_1_gain_ = 0.0f; - - recalc_ = recalc_gain_ = true; - SetGain(1.f); - - for(int i = 0; i < 7; i++) - { - registration_[i] = 0.f; - unshifted_registration_[i] = 0.f; - } - SetSingleAmp(1.f, 0); - SetFreq(440.f); -} - -float OscillatorBank::Process() -{ - if(recalc_) - { - recalc_ = false; - frequency_ *= 8.0f; - - // Deal with very high frequencies by shifting everything 1 or 2 octave - // down: Instead of playing the 1st harmonic of a 8kHz wave, we play the - // second harmonic of a 4kHz wave. - size_t shift = 0; - while(frequency_ > 0.5f) - { - shift += 2; - frequency_ *= 0.5f; - } - - for(int i = 0; i < 7; i++) - { - registration_[i] = 0.f; - } - - for(size_t i = 0; i < 7 - shift; i++) - { - registration_[i + shift] = unshifted_registration_[i]; - } - } - - if(recalc_gain_ || recalc_) - { - saw_8_gain_ = (registration_[0] + 2.0f * registration_[1]) * gain_; - saw_4_gain_ - = (registration_[2] - registration_[1] + 2.0f * registration_[3]) - * gain_; - saw_2_gain_ - = (registration_[4] - registration_[3] + 2.0f * registration_[5]) - * gain_; - saw_1_gain_ = (registration_[6] - registration_[5]) * gain_; - } - - float this_sample_ = next_sample_; - next_sample_ = 0.0f; - - phase_ += frequency_; - int next_segment_ = static_cast(phase_); - if(next_segment_ != segment_) - { - float discontinuity = 0.0f; - if(next_segment_ == 8) - { - phase_ -= 8.0f; - next_segment_ -= 8; - discontinuity -= saw_8_gain_; - } - if((next_segment_ & 3) == 0) - { - discontinuity -= saw_4_gain_; - } - if((next_segment_ & 1) == 0) - { - discontinuity -= saw_2_gain_; - } - discontinuity -= saw_1_gain_; - if(discontinuity != 0.0f) - { - float fraction = phase_ - static_cast(next_segment_); - float t = fraction / frequency_; - this_sample_ += ThisBlepSample(t) * discontinuity; - next_sample_ += NextBlepSample(t) * discontinuity; - } - } - segment_ = next_segment_; - - next_sample_ += (phase_ - 4.0f) * saw_8_gain_ * 0.125f; - next_sample_ += (phase_ - float(segment_ & 4) - 2.0f) * saw_4_gain_ * 0.25f; - next_sample_ += (phase_ - float(segment_ & 6) - 1.0f) * saw_2_gain_ * 0.5f; - next_sample_ += (phase_ - float(segment_ & 7) - 0.5f) * saw_1_gain_; - - return 2.0f * this_sample_; -} - -void OscillatorBank::SetFreq(float freq) -{ - freq = freq / sample_rate_; - freq = freq > 0.5f ? 0.5f : freq; - recalc_ = cmp(freq, frequency_) || recalc_; - frequency_ = freq; -} - -void OscillatorBank::SetAmplitudes(const float* amplitudes) -{ - for(int i = 0; i < 7; i++) - { - recalc_ = cmp(unshifted_registration_[i], amplitudes[i]) || recalc_; - unshifted_registration_[i] = amplitudes[i]; - } -} - -void OscillatorBank::SetSingleAmp(float amp, int idx) -{ - if(idx < 0 || idx > 6) - { - return; - } - recalc_ = cmp(unshifted_registration_[idx], amp) || recalc_; - unshifted_registration_[idx] = amp; -} - -void OscillatorBank::SetGain(float gain) -{ - gain = gain > 1.f ? 1.f : gain; - gain = gain < 0.f ? 0.f : gain; - recalc_gain_ = cmp(gain, gain_) || recalc_gain_; - gain_ = gain; -} \ No newline at end of file diff --git a/src/daisysp/Synthesis/oscillatorbank.h b/src/daisysp/Synthesis/oscillatorbank.h deleted file mode 100644 index 0266743..0000000 --- a/src/daisysp/Synthesis/oscillatorbank.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_OSCILLATORBANK_H -#define DSY_OSCILLATORBANK_H - -#include -#ifdef __cplusplus - -/** @file oscillatorbank.h */ - -namespace daisysp -{ -/** - @brief Oscillator Bank module. - @author Ben Sergentanis - @date Dec 2020 - A mixture of 7 sawtooth and square waveforms in the style of divide-down organs \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/string_synth_oscillator.h \n - \n to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ - -class OscillatorBank -{ - public: - OscillatorBank() {} - ~OscillatorBank() {} - - /** Init string synth module - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get next floating point sample - */ - float Process(); - - /** Set oscillator frequency (8' oscillator) - \param freq Frequency in Hz - */ - void SetFreq(float freq); - - /** Set amplitudes of 7 oscillators. 0-6 are Saw 8', Square 8', Saw 4', Square 4', Saw 2', Square 2', Saw 1' - \param amplitudes array of 7 floating point amplitudes. Must sum to 1. - */ - void SetAmplitudes(const float* amplitudes); - - /** Set a single amplitude - \param amp Amplitude to set. - \param idx Which wave's amp to set - */ - void SetSingleAmp(float amp, int idx); - - /** Set overall gain. - \param gain Gain to set. 0-1. - */ - void SetGain(float gain); - - private: - // Oscillator state. - float phase_; - float next_sample_; - int segment_; - float gain_; - float registration_[7]; - float unshifted_registration_[7]; - - float frequency_; - float saw_8_gain_; - float saw_4_gain_; - float saw_2_gain_; - float saw_1_gain_; - - float sample_rate_; - bool recalc_, recalc_gain_; - - bool cmp(float a, float b) { return fabsf(a - b) > .0000001; } -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/variablesawosc.cpp b/src/daisysp/Synthesis/variablesawosc.cpp deleted file mode 100644 index 34aedb1..0000000 --- a/src/daisysp/Synthesis/variablesawosc.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "../Utility/dsp.h" -#include "variablesawosc.h" -#include - -using namespace daisysp; - -void VariableSawOscillator::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - phase_ = 0.0f; - next_sample_ = 0.0f; - previous_pw_ = 0.5f; - high_ = false; - - SetFreq(220.f); - SetPW(0.f); - SetWaveshape(1.f); -} - -float VariableSawOscillator::Process() -{ - float next_sample = next_sample_; - - float this_sample = next_sample; - next_sample = 0.0f; - - const float triangle_amount = waveshape_; - const float notch_amount = 1.0f - waveshape_; - const float slope_up = 1.0f / (pw_); - const float slope_down = 1.0f / (1.0f - pw_); - - phase_ += frequency_; - - if(!high_ && phase_ >= pw_) - { - const float triangle_step - = (slope_up + slope_down) * frequency_ * triangle_amount; - const float notch - = (kVariableSawNotchDepth + 1.0f - pw_) * notch_amount; - const float t = (phase_ - pw_) / (previous_pw_ - pw_ + frequency_); - this_sample += notch * ThisBlepSample(t); - next_sample += notch * NextBlepSample(t); - this_sample -= triangle_step * ThisIntegratedBlepSample(t); - next_sample -= triangle_step * NextIntegratedBlepSample(t); - high_ = true; - } - else if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - const float triangle_step - = (slope_up + slope_down) * frequency_ * triangle_amount; - const float notch = (kVariableSawNotchDepth + 1.0f) * notch_amount; - const float t = phase_ / frequency_; - this_sample -= notch * ThisBlepSample(t); - next_sample -= notch * NextBlepSample(t); - this_sample += triangle_step * ThisIntegratedBlepSample(t); - next_sample += triangle_step * NextIntegratedBlepSample(t); - high_ = false; - } - - next_sample += ComputeNaiveSample( - phase_, pw_, slope_up, slope_down, triangle_amount, notch_amount); - previous_pw_ = pw_; - - next_sample_ = next_sample; - return (2.0f * this_sample - 1.0f) / (1.0f + kVariableSawNotchDepth); -} - -void VariableSawOscillator::SetFreq(float frequency) -{ - frequency = frequency / sample_rate_; - frequency = frequency >= .25f ? .25f : frequency; - pw_ = frequency >= .25f ? .5f : pw_; - frequency_ = frequency; -} - -void VariableSawOscillator::SetPW(float pw) -{ - if(frequency_ >= .25f) - { - pw_ = .5f; - } - else - { - pw_ = fclamp(pw, frequency_ * 2.0f, 1.0f - 2.0f * frequency_); - } -} - -void VariableSawOscillator::SetWaveshape(float waveshape) -{ - waveshape_ = waveshape; -} - -float VariableSawOscillator::ComputeNaiveSample(float phase, - float pw, - float slope_up, - float slope_down, - float triangle_amount, - float notch_amount) -{ - float notch_saw = phase < pw ? phase : 1.0f + kVariableSawNotchDepth; - float triangle - = phase < pw ? phase * slope_up : 1.0f - (phase - pw) * slope_down; - return notch_saw * notch_amount + triangle * triangle_amount; -} \ No newline at end of file diff --git a/src/daisysp/Synthesis/variablesawosc.h b/src/daisysp/Synthesis/variablesawosc.h deleted file mode 100644 index c9d57eb..0000000 --- a/src/daisysp/Synthesis/variablesawosc.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_VARISAWOSCILLATOR_H -#define DSY_VARISAWOSCILLATOR_H - -#include -#ifdef __cplusplus - -/** @file variablesawosc.h */ -namespace daisysp -{ -/** - @brief Variable Saw Oscillator. - @author Ben Sergentanis - @date Dec 2020 - Saw with variable slope or notch. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/variable_saw_oscillator.h \n - \n to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class VariableSawOscillator -{ - public: - VariableSawOscillator() {} - ~VariableSawOscillator() {} - - void Init(float sample_rate); - - /** Get the next sample */ - float Process(); - - /** Set master freq. - \param frequency Freq in Hz. - */ - void SetFreq(float frequency); - - /** Adjust the wave depending on the shape - \param pw Notch or slope. Works best -1 to 1. - */ - void SetPW(float pw); - - /** Slope or notch - \param waveshape 0 = notch, 1 = slope - */ - void SetWaveshape(float waveshape); - - - private: - float ComputeNaiveSample(float phase, - float pw, - float slope_up, - float slope_down, - float triangle_amount, - float notch_amount); - - float sample_rate_; - - // Oscillator state. - float phase_; - float next_sample_; - float previous_pw_; - bool high_; - - const float kVariableSawNotchDepth = 0.2f; - - // For interpolation of parameters. - float frequency_; - float pw_; - float waveshape_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/variableshapeosc.cpp b/src/daisysp/Synthesis/variableshapeosc.cpp deleted file mode 100644 index 6c8c681..0000000 --- a/src/daisysp/Synthesis/variableshapeosc.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "../Utility/dsp.h" -#include "variableshapeosc.h" -#include - -using namespace daisysp; - -void VariableShapeOscillator::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - master_phase_ = 0.0f; - slave_phase_ = 0.0f; - next_sample_ = 0.0f; - previous_pw_ = 0.5f; - high_ = false; - - SetFreq(440.f); - SetWaveshape(0.f); - SetPW(0.f); - SetSync(false); - SetSyncFreq(220.f); -} - -float VariableShapeOscillator::Process() -{ - float next_sample = next_sample_; - - bool reset = false; - bool transition_during_reset = false; - float reset_time = 0.0f; - - float this_sample = next_sample; - next_sample = 0.0f; - - const float square_amount = fmax(waveshape_ - 0.5f, 0.0f) * 2.0f; - const float triangle_amount = fmax(1.0f - waveshape_ * 2.0f, 0.0f); - const float slope_up = 1.0f / (pw_); - const float slope_down = 1.0f / (1.0f - pw_); - - if(enable_sync_) - { - master_phase_ += master_frequency_; - if(master_phase_ >= 1.0f) - { - master_phase_ -= 1.0f; - reset_time = master_phase_ / master_frequency_; - - float slave_phase_at_reset - = slave_phase_ + (1.0f - reset_time) * slave_frequency_; - reset = true; - if(slave_phase_at_reset >= 1.0f) - { - slave_phase_at_reset -= 1.0f; - transition_during_reset = true; - } - if(!high_ && slave_phase_at_reset >= pw_) - { - transition_during_reset = true; - } - float value = ComputeNaiveSample(slave_phase_at_reset, - pw_, - slope_up, - slope_down, - triangle_amount, - square_amount); - this_sample -= value * ThisBlepSample(reset_time); - next_sample -= value * NextBlepSample(reset_time); - } - } - - slave_phase_ += slave_frequency_; - while(transition_during_reset || !reset) - { - if(!high_) - { - if(slave_phase_ < pw_) - { - break; - } - float t = (slave_phase_ - pw_) - / (previous_pw_ - pw_ + slave_frequency_); - float triangle_step = (slope_up + slope_down) * slave_frequency_; - triangle_step *= triangle_amount; - - this_sample += square_amount * ThisBlepSample(t); - next_sample += square_amount * NextBlepSample(t); - this_sample -= triangle_step * ThisIntegratedBlepSample(t); - next_sample -= triangle_step * NextIntegratedBlepSample(t); - high_ = true; - } - - if(high_) - { - if(slave_phase_ < 1.0f) - { - break; - } - slave_phase_ -= 1.0f; - float t = slave_phase_ / slave_frequency_; - float triangle_step = (slope_up + slope_down) * slave_frequency_; - triangle_step *= triangle_amount; - - this_sample -= (1.0f - triangle_amount) * ThisBlepSample(t); - next_sample -= (1.0f - triangle_amount) * NextBlepSample(t); - this_sample += triangle_step * ThisIntegratedBlepSample(t); - next_sample += triangle_step * NextIntegratedBlepSample(t); - high_ = false; - } - } - - if(enable_sync_ && reset) - { - slave_phase_ = reset_time * slave_frequency_; - high_ = false; - } - - next_sample += ComputeNaiveSample(slave_phase_, - pw_, - slope_up, - slope_down, - triangle_amount, - square_amount); - previous_pw_ = pw_; - - - next_sample_ = next_sample; - return (2.0f * this_sample - 1.0f); -} - -void VariableShapeOscillator::SetFreq(float frequency) -{ - frequency = frequency / sample_rate_; - frequency = frequency >= .25f ? .25f : frequency; - master_frequency_ = frequency; -} - -void VariableShapeOscillator::SetPW(float pw) -{ - if(slave_frequency_ >= .25f) - { - pw_ = .5f; - } - else - { - pw_ = fclamp( - pw, slave_frequency_ * 2.0f, 1.0f - 2.0f * slave_frequency_); - } -} - -void VariableShapeOscillator::SetWaveshape(float waveshape) -{ - waveshape_ = waveshape; -} - -void VariableShapeOscillator::SetSync(bool enable_sync) -{ - enable_sync_ = enable_sync; -} - -void VariableShapeOscillator::SetSyncFreq(float frequency) -{ - frequency = frequency / sample_rate_; - pw_ = frequency >= .25f ? .5f : pw_; - frequency = frequency >= .25f ? .25f : frequency; - slave_frequency_ = frequency; -} - -float VariableShapeOscillator::ComputeNaiveSample(float phase, - float pw, - float slope_up, - float slope_down, - float triangle_amount, - float square_amount) -{ - float saw = phase; - float square = phase < pw ? 0.0f : 1.0f; - float triangle - = phase < pw ? phase * slope_up : 1.0f - (phase - pw) * slope_down; - saw += (square - saw) * square_amount; - saw += (triangle - saw) * triangle_amount; - return saw; -} \ No newline at end of file diff --git a/src/daisysp/Synthesis/variableshapeosc.h b/src/daisysp/Synthesis/variableshapeosc.h deleted file mode 100644 index e94d92b..0000000 --- a/src/daisysp/Synthesis/variableshapeosc.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_VARIABLESHAPEOSCILLATOR_H -#define DSY_VARIABLESHAPEOSCILLATOR_H - -#include -#ifdef __cplusplus - -/** @file variableshapeosc.h */ - -namespace daisysp -{ -/** - @brief Variable Waveshape Oscillator. - @author Ben Sergentanis - @date Dec 2020 - Continuously variable waveform. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/variable_shape_oscillator.h \n - \n to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class VariableShapeOscillator -{ - public: - VariableShapeOscillator() {} - ~VariableShapeOscillator() {} - - /** Initialize the oscillator - \param sample_rate Audio engine sample rate - */ - void Init(float sample_rate); - - /** Get next sample - */ - float Process(); - - /** Set master freq. - \param frequency Freq in Hz. - */ - void SetFreq(float frequency); - - /** Set pulse width / saw, ramp, tri. - \param pw PW when shape is square. Saw, ramp, tri otherwise. - */ - void SetPW(float pw); - - /** Switch from saw/ramp/tri to square. - \param waveshape 0 is saw/ramp/tri, 1 is square. - */ - void SetWaveshape(float waveshape); - - /** Whether or not to sync to the sync oscillator - \param enable_sync True to turn sync on. - */ - void SetSync(bool enable_sync); - - /** Set sync oscillator freq. - \param frequency Freq in Hz. - */ - void SetSyncFreq(float frequency); - - private: - float ComputeNaiveSample(float phase, - float pw, - float slope_up, - float slope_down, - float triangle_amount, - float square_amount); - - float sample_rate_; - bool enable_sync_; - - // Oscillator state. - float master_phase_; - float slave_phase_; - float next_sample_; - float previous_pw_; - bool high_; - - // For interpolation of parameters. - float master_frequency_; - float slave_frequency_; - float pw_; - float waveshape_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/vosim.cpp b/src/daisysp/Synthesis/vosim.cpp deleted file mode 100644 index d1b273c..0000000 --- a/src/daisysp/Synthesis/vosim.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "../Utility/dsp.h" -#include "vosim.h" -#include - -using namespace daisysp; - -void VosimOscillator::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - carrier_phase_ = 0.0f; - formant_1_phase_ = 0.0f; - formant_2_phase_ = 0.0f; - - SetFreq(105.f); - SetForm1Freq(1390.f); - SetForm2Freq(817.f); - SetShape(.5f); -} - -float VosimOscillator::Process() -{ - carrier_phase_ += carrier_frequency_; - if(carrier_phase_ >= 1.0f) - { - carrier_phase_ -= 1.0f; - float reset_time = carrier_phase_ / carrier_frequency_; - formant_1_phase_ = reset_time * formant_1_frequency_; - formant_2_phase_ = reset_time * formant_2_frequency_; - } - else - { - formant_1_phase_ += formant_1_frequency_; - if(formant_1_phase_ >= 1.0f) - { - formant_1_phase_ -= 1.0f; - } - formant_2_phase_ += formant_2_frequency_; - if(formant_2_phase_ >= 1.0f) - { - formant_2_phase_ -= 1.0f; - } - } - - float carrier = Sine(carrier_phase_ * 0.5f + 0.25f) + 1.0f; - float reset_phase = 0.75f - 0.25f * carrier_shape_; - float reset_amplitude = Sine(reset_phase); - float formant_0 = Sine(formant_1_phase_ + reset_phase) - reset_amplitude; - float formant_1 = Sine(formant_2_phase_ + reset_phase) - reset_amplitude; - return carrier * (formant_0 + formant_1) * 0.25f + reset_amplitude; -} - -void VosimOscillator::SetFreq(float freq) -{ - carrier_frequency_ = freq / sample_rate_; - carrier_frequency_ = carrier_frequency_ > .25f ? .25f : carrier_frequency_; -} - -void VosimOscillator::SetForm1Freq(float freq) -{ - formant_1_frequency_ = freq / sample_rate_; - formant_1_frequency_ - = formant_1_frequency_ > .25f ? .25f : formant_1_frequency_; -} - -void VosimOscillator::SetForm2Freq(float freq) -{ - formant_2_frequency_ = freq / sample_rate_; - formant_2_frequency_ - = formant_2_frequency_ > .25f ? .25f : formant_2_frequency_; -} - -void VosimOscillator::SetShape(float shape) -{ - carrier_shape_ = shape; -} - -float VosimOscillator::Sine(float phase) -{ - return sinf(TWOPI_F * phase); -} \ No newline at end of file diff --git a/src/daisysp/Synthesis/vosim.h b/src/daisysp/Synthesis/vosim.h deleted file mode 100644 index 0173d88..0000000 --- a/src/daisysp/Synthesis/vosim.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_VOSIM_H -#define DSY_VOSIM_H - -#include -#ifdef __cplusplus - -/** @file vosim.h */ - -namespace daisysp -{ -/** - @brief Vosim Oscillator Module \n - @author Ben Sergentanis - @date Dec 2020 - Two sinewaves multiplied by and sync'ed to a carrier. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/vosim_oscillator.h \n - \n to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class VosimOscillator -{ - public: - VosimOscillator() {} - ~VosimOscillator() {} - - /** Initializes the FormantOscillator module. - \param sample_rate - The sample rate of the audio engine being run. - */ - void Init(float sample_rate); - - /** Get the next sample - */ - float Process(); - - /** Set carrier frequency. - \param freq Frequency in Hz. - */ - void SetFreq(float freq); - - /** Set formant 1 frequency. - \param freq Frequency in Hz. - */ - void SetForm1Freq(float freq); - - /** Set formant 2 frequency. - \param freq Frequency in Hz. - */ - void SetForm2Freq(float freq); - - /** Waveshaping - \param shape Shape to set. Works -1 to 1 - */ - void SetShape(float shape); - - private: - float Sine(float phase); - - float sample_rate_; - - // Oscillator state. - float carrier_phase_; - float formant_1_phase_; - float formant_2_phase_; - - // For interpolation of parameters. - float carrier_frequency_; - float formant_1_frequency_; - float formant_2_frequency_; - float carrier_shape_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Synthesis/zoscillator.cpp b/src/daisysp/Synthesis/zoscillator.cpp deleted file mode 100644 index 20af60c..0000000 --- a/src/daisysp/Synthesis/zoscillator.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "../Utility/dsp.h" -#include "zoscillator.h" -#include - -using namespace daisysp; - -void ZOscillator::Init(float sample_rate) -{ - sample_rate_ = sample_rate; - - carrier_phase_ = 0.0f; - discontinuity_phase_ = 0.0f; - formant_phase_ = 0.0f; - next_sample_ = 0.0f; - - SetFreq(220.f); - SetFormantFreq(550.f); - SetMode(0.f); - SetShape(1.f); -} - -float ZOscillator::Process() -{ - float next_sample = next_sample_; - - bool reset = false; - float reset_time = 0.0f; - - float this_sample = next_sample; - next_sample = 0.0f; - - discontinuity_phase_ += 2.0f * carrier_frequency_; - carrier_phase_ += carrier_frequency_; - reset = discontinuity_phase_ >= 1.0f; - - if(reset) - { - discontinuity_phase_ -= 1.0f; - reset_time = discontinuity_phase_ / (2.0f * carrier_frequency_); - - float carrier_phase_before = carrier_phase_ >= 1.0f ? 1.0f : 0.5f; - float carrier_phase_after = carrier_phase_ >= 1.0f ? 0.0f : 0.5f; - - float mode_sub = mode_ + (1.f - reset_time) * (mode_ - mode_new_); - float shape_sub = carrier_shape_ - + (1.0f - reset_time) * (carrier_shape_ - shape_new_); - float before - = Z(carrier_phase_before, - 1.0f, - formant_phase_ + (1.0f - reset_time) * formant_frequency_, - shape_sub, - mode_sub); - - float after = Z(carrier_phase_after, 0.0f, 0.0f, shape_new_, mode_new_); - - float discontinuity = after - before; - this_sample += discontinuity * ThisBlepSample(reset_time); - next_sample += discontinuity * NextBlepSample(reset_time); - formant_phase_ = reset_time * formant_frequency_; - - if(carrier_phase_ > 1.0f) - { - carrier_phase_ = discontinuity_phase_ * 0.5f; - } - } - else - { - formant_phase_ += formant_frequency_; - if(formant_phase_ >= 1.0f) - { - formant_phase_ -= 1.0f; - } - } - - if(carrier_phase_ >= 1.0f) - { - carrier_phase_ -= 1.0f; - } - - carrier_shape_ = shape_new_; - mode_ = mode_new_; - next_sample += Z(carrier_phase_, - discontinuity_phase_, - formant_phase_, - carrier_shape_, - mode_); - - next_sample_ = next_sample; - return this_sample; -} - -inline float ZOscillator::Sine(float phase) -{ - return sinf(phase * TWOPI_F); -} - -void ZOscillator::SetFreq(float freq) -{ - //convert from Hz to phase_inc / sample - carrier_frequency_ = freq / sample_rate_; - carrier_frequency_ = carrier_frequency_ >= .25f ? .25f : carrier_frequency_; -} - -void ZOscillator::SetFormantFreq(float freq) -{ - //convert from Hz to phase_inc / sample - formant_frequency_ = freq / sample_rate_; - formant_frequency_ = formant_frequency_ >= .25f ? .25f : formant_frequency_; -} - -void ZOscillator::SetShape(float shape) -{ - shape_new_ = shape; -} - -void ZOscillator::SetMode(float mode) -{ - mode_new_ = mode; -} - -inline float ZOscillator::Z(float c, float d, float f, float shape, float mode) -{ - float ramp_down = 0.5f * (1.0f + Sine(0.5f * d + 0.25f)); - - float offset; - float phase_shift; - if(mode < 0.333f) - { - offset = 1.0f; - phase_shift = 0.25f + mode * 1.50f; - } - else if(mode < 0.666f) - { - phase_shift = 0.7495f - (mode - 0.33f) * 0.75f; - offset = -Sine(phase_shift); - } - else - { - phase_shift = 0.7495f - (mode - 0.33f) * 0.75f; - offset = 0.001f; - } - - float discontinuity = Sine(f + phase_shift); - float contour; - if(shape < 0.5f) - { - shape *= 2.0f; - if(c >= 0.5f) - { - ramp_down *= shape; - } - contour = 1.0f + (Sine(c + 0.25f) - 1.0f) * shape; - } - else - { - contour = Sine(c + shape * 0.5f); - } - return (ramp_down * (offset + discontinuity) - offset) * contour; -} \ No newline at end of file diff --git a/src/daisysp/Synthesis/zoscillator.h b/src/daisysp/Synthesis/zoscillator.h deleted file mode 100644 index 0ef1095..0000000 --- a/src/daisysp/Synthesis/zoscillator.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_ZOSCILLATOR_H -#define DSY_ZOSCILLATOR_H - -#include -#ifdef __cplusplus - -/** @file zoscillator.h */ -namespace daisysp -{ -/** - @brief ZOscillator Module \n - @author Ben Sergentanis - @date Dec 2020 - Sinewave multiplied by and sync'ed to a carrier. \n \n - Ported from pichenettes/eurorack/plaits/dsp/oscillator/z_oscillator.h \n - \n to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class ZOscillator -{ - public: - ZOscillator() {} - ~ZOscillator() {} - - /** Init ZOscillator module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate); - - /** Get next sample - */ - float Process(); - - /** Set the carrier frequency - \param freq Frequency in Hz. - */ - void SetFreq(float freq); - - /** Set the formant osc. freq - \param freq Frequency in Hz. - */ - void SetFormantFreq(float freq); - - /** Adjust the contour of the waveform. - \param shape Waveshape to set. Works best 0-1. - */ - void SetShape(float shape); - - /** Set the offset amount and phase shift. \n - < 1/3 is just phase shift, > 2/3 is just offset, and between them is both. \n - \param mode Mode to set. Works best -1 to 1 - */ - void SetMode(float mode); - - private: - inline float Sine(float phase); - inline float Z(float c, float d, float f, float shape, float mode); - - float sample_rate_; - - // Oscillator state. - float carrier_phase_; - float discontinuity_phase_; - float formant_phase_; - float next_sample_; - - // For interpolation of parameters. - float carrier_frequency_; - float formant_frequency_; - float carrier_shape_, shape_new_; - float mode_, mode_new_; -}; -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/Utility/dcblock.cpp b/src/daisysp/Utility/dcblock.cpp deleted file mode 100644 index 5cbe4ad..0000000 --- a/src/daisysp/Utility/dcblock.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "dcblock.h" - -using namespace daisysp; - -void DcBlock::Init(float sample_rate) -{ - output_ = 0.0; - input_ = 0.0; - gain_ = 1.0 - 10.f / sample_rate; -} - -float DcBlock::Process(float in) -{ - float out; - out = in - input_ + (gain_ * output_); - output_ = out; - input_ = in; - return out; -} diff --git a/src/daisysp/Utility/dcblock.h b/src/daisysp/Utility/dcblock.h deleted file mode 100644 index 184173b..0000000 --- a/src/daisysp/Utility/dcblock.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_DCBLOCK_H -#define DSY_DCBLOCK_H -#ifdef __cplusplus - -namespace daisysp -{ -/** Removes DC component of a signal - */ -class DcBlock -{ - public: - DcBlock(){}; - ~DcBlock(){}; - - /** Initializes DcBlock module - */ - void Init(float sample_rate); - - /** performs DcBlock Process - */ - float Process(float in); - - private: - float input_, output_, gain_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Utility/delayline.h b/src/daisysp/Utility/delayline.h deleted file mode 100644 index 56be5a2..0000000 --- a/src/daisysp/Utility/delayline.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_DELAY_H -#define DSY_DELAY_H -#include -#include -namespace daisysp -{ -/** Simple Delay line. -November 2019 - -Converted to Template December 2019 - -declaration example: (1 second of floats) - -DelayLine del; - -By: shensley -*/ -template -class DelayLine -{ - public: - DelayLine() {} - ~DelayLine() {} - /** initializes the delay line by clearing the values within, and setting delay to 1 sample. - */ - void Init() { Reset(); } - /** clears buffer, sets write ptr to 0, and delay to 1 sample. - */ - void Reset() - { - for(size_t i = 0; i < max_size; i++) - { - line_[i] = T(0); - } - write_ptr_ = 0; - delay_ = 1; - } - - /** sets the delay time in samples - If a float is passed in, a fractional component will be calculated for interpolating the delay line. - */ - inline void SetDelay(size_t delay) - { - frac_ = 0.0f; - delay_ = delay < max_size ? delay : max_size - 1; - } - - /** sets the delay time in samples - If a float is passed in, a fractional component will be calculated for interpolating the delay line. - */ - inline void SetDelay(float delay) - { - int32_t int_delay = static_cast(delay); - frac_ = delay - static_cast(int_delay); - delay_ = static_cast(int_delay) < max_size ? int_delay - : max_size - 1; - } - - /** writes the sample of type T to the delay line, and advances the write ptr - */ - inline void Write(const T sample) - { - line_[write_ptr_] = sample; - write_ptr_ = (write_ptr_ - 1 + max_size) % max_size; - } - - /** returns the next sample of type T in the delay line, interpolated if necessary. - */ - inline const T Read() const - { - T a = line_[(write_ptr_ + delay_) % max_size]; - T b = line_[(write_ptr_ + delay_ + 1) % max_size]; - return a + (b - a) * frac_; - } - - /** Read from a set location */ - inline const T Read(float delay) const - { - int32_t delay_integral = static_cast(delay); - float delay_fractional = delay - static_cast(delay_integral); - const T a = line_[(write_ptr_ + delay_integral) % max_size]; - const T b = line_[(write_ptr_ + delay_integral + 1) % max_size]; - return a + (b - a) * delay_fractional; - } - - inline const T ReadHermite(float delay) const - { - int32_t delay_integral = static_cast(delay); - float delay_fractional = delay - static_cast(delay_integral); - - int32_t t = (write_ptr_ + delay_integral + max_size); - const T xm1 = line_[(t - 1) % max_size]; - const T x0 = line_[(t) % max_size]; - const T x1 = line_[(t + 1) % max_size]; - const T x2 = line_[(t + 2) % max_size]; - const float c = (x1 - xm1) * 0.5f; - const float v = x0 - x1; - const float w = c + v; - const float a = w + v + (x2 - x0) * 0.5f; - const float b_neg = w + a; - const float f = delay_fractional; - return (((a * f) - b_neg) * f + c) * f + x0; - } - - inline const T Allpass(const T sample, size_t delay, const T coefficient) - { - T read = line_[(write_ptr_ + delay) % max_size]; - T write = sample + coefficient * read; - Write(write); - return -write * coefficient + read; - } - - private: - float frac_; - size_t write_ptr_; - size_t delay_; - T line_[max_size]; -}; -} // namespace daisysp -#endif diff --git a/src/daisysp/Utility/dsp.h b/src/daisysp/Utility/dsp.h deleted file mode 100644 index 619abdb..0000000 --- a/src/daisysp/Utility/dsp.h +++ /dev/null @@ -1,352 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -/** Helpful defines, functions, and other utilities for use in/with daisysp modules. -*/ -#pragma once -#ifndef DSY_CORE_DSP -#define DSY_CORE_DSP -#include -#include -#include -#include - -/** PIs -*/ -#define PI_F 3.1415927410125732421875f -#define TWOPI_F (2.0f * PI_F) -#define HALFPI_F (PI_F * 0.5f) -#define DSY_MIN(in, mn) (in < mn ? in : mn) -#define DSY_MAX(in, mx) (in > mx ? in : mx) -#define DSY_CLAMP(in, mn, mx) (DSY_MIN(DSY_MAX(in, mn), mx)) -#define DSY_COUNTOF(_arr) (sizeof(_arr) / sizeof(_arr[0])) - -namespace daisysp -{ -//Avoids division for random floats. e.g. rand() * kRandFrac -static constexpr float kRandFrac = 1.f / (float)RAND_MAX; - -//Convert from semitones to other units. e.g. 2 ^ (kOneTwelfth * x) -static constexpr float kOneTwelfth = 1.f / 12.f; - -/** efficient floating point min/max -c/o stephen mccaul -*/ -inline float fmax(float a, float b) -{ - float r; -#ifdef __arm__ - asm("vmaxnm.f32 %[d], %[n], %[m]" : [d] "=t"(r) : [n] "t"(a), [m] "t"(b) :); -#else - r = (a > b) ? a : b; -#endif // __arm__ - return r; -} - -inline float fmin(float a, float b) -{ - float r; -#ifdef __arm__ - asm("vminnm.f32 %[d], %[n], %[m]" : [d] "=t"(r) : [n] "t"(a), [m] "t"(b) :); -#else - r = (a < b) ? a : b; -#endif // __arm__ - return r; -} - -/** quick fp clamp -*/ -inline float fclamp(float in, float min, float max) -{ - return fmin(fmax(in, min), max); -} - -/** From Musicdsp.org "Fast power and root estimates for 32bit floats) -Original code by Stefan Stenzel -These are approximations -*/ -inline float fastpower(float f, int n) -{ - long *lp, l; - lp = (long *)(&f); - l = *lp; - l -= 0x3F800000; - l <<= (n - 1); - l += 0x3F800000; - *lp = l; - return f; -} - -inline float fastroot(float f, int n) -{ - long *lp, l; - lp = (long *)(&f); - l = *lp; - l -= 0x3F800000; - l >>= (n - 1); - l += 0x3F800000; - *lp = l; - return f; -} - -/** Significantly more efficient than fmodf(x, 1.0f) for calculating - * the decimal part of a floating point value. - */ -inline float fastmod1f(float x) -{ - return x - floorf(x); -} - -/** From http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html -No approximation, pow10f(x) gives a 90% speed increase over powf(10.f, x) -*/ -inline float pow10f(float f) -{ - return expf(2.302585092994046f * f); -} - -/* Original code for fastlog2f by Dr. Paul Beckmann from the ARM community forum, adapted from the CMSIS-DSP library -About 25% performance increase over std::log10f -*/ -inline float fastlog2f(float f) -{ - float frac; - int exp; - frac = frexpf(fabsf(f), &exp); - f = 1.23149591368684f; - f *= frac; - f += -4.11852516267426f; - f *= frac; - f += 6.02197014179219f; - f *= frac; - f += -3.13396450166353f; - f += exp; - return (f); -} - -inline float fastlog10f(float f) -{ - return fastlog2f(f) * 0.3010299956639812f; -} - -/** Midi to frequency helper -*/ -inline float mtof(float m) -{ - return powf(2, (m - 69.0f) / 12.0f) * 440.0f; -} - - -/** one pole lpf -out is passed by reference, and must be retained between -calls to properly filter the signal -coeff can be calculated: -coeff = 1.0 / (time * sample_rate) ; where time is in seconds -*/ -inline void fonepole(float &out, float in, float coeff) -{ - out += coeff * (in - out); -} - -/** Curves to use with the fmap function */ -enum class Mapping -{ - LINEAR, - EXP, - LOG, -}; - -/** Maps a float between a specified range, using a specified curve. - * - * \param in a value between 0 to 1 that will be mapped to the new range. - * \param min the new minimum value - * \param max the new maxmimum value - * \param curve a Mapping Value to adjust the response curve of the transformation - * defaults to Linear. @see Mapping - * - * When using the log curve min and max, must be greater than zero. - * - * \retval returns the transformed float within the new range. -*/ -inline float -fmap(float in, float min, float max, Mapping curve = Mapping::LINEAR) -{ - switch(curve) - { - case Mapping::EXP: - return fclamp(min + (in * in) * (max - min), min, max); - case Mapping::LOG: - { - const float a = 1.f / log10f(max / min); - return fclamp(min * powf(10, in / a), min, max); - } - case Mapping::LINEAR: - default: return fclamp(min + in * (max - min), min, max); - } -} - -/** Simple 3-point median filter -c/o stephen mccaul -*/ -template -T median(T a, T b, T c) -{ - return (b < a) ? (b < c) ? (c < a) ? c : a : b - : (a < c) ? (c < b) ? c : b : a; -} - -/** Ported from pichenettes/eurorack/plaits/dsp/oscillator/oscillator.h -*/ -inline float ThisBlepSample(float t) -{ - return 0.5f * t * t; -} - -/** Ported from pichenettes/eurorack/plaits/dsp/oscillator/oscillator.h -*/ -inline float NextBlepSample(float t) -{ - t = 1.0f - t; - return -0.5f * t * t; -} - -/** Ported from pichenettes/eurorack/plaits/dsp/oscillator/oscillator.h -*/ -inline float NextIntegratedBlepSample(float t) -{ - const float t1 = 0.5f * t; - const float t2 = t1 * t1; - const float t4 = t2 * t2; - return 0.1875f - t1 + 1.5f * t2 - t4; -} - -/** Ported from pichenettes/eurorack/plaits/dsp/oscillator/oscillator.h -*/ -inline float ThisIntegratedBlepSample(float t) -{ - return NextIntegratedBlepSample(1.0f - t); -} - -/** Soft Limiting function ported extracted from pichenettes/stmlib */ -inline float SoftLimit(float x) -{ - return x * (27.f + x * x) / (27.f + 9.f * x * x); -} - -/** Soft Clipping function extracted from pichenettes/stmlib */ -inline float SoftClip(float x) -{ - if(x < -3.0f) - return -1.0f; - else if(x > 3.0f) - return 1.0f; - else - return SoftLimit(x); -} - -/** Quick check for Invalid float values (NaN, Inf, out of range) - ** \param x value passed by reference, replaced by y if invalid. - ** \param y value to replace x if invalidity is found. - ** - ** When DEBUG is true in the build, this will halt - ** execution for tracing the reason for the invalidity. */ -inline void TestFloat(float &x, float y = 0.f) -{ - if(!std::isnormal(x) && x != 0) - { -#if defined(__arm__) && defined(DEBUG) - asm("bkpt 255"); -#else - x = y; -#endif - } -} - -/** Based on soft saturate from: -[musicdsp.org](musicdsp.org/en/latest/Effects/42-soft-saturation.html) -Bram de Jong (2002-01-17) -This still needs to be tested/fixed. Definitely does some weird stuff -described as: -x < a: - f(x) = x -x > a: - f(x) = a + (x-a)/(1+((x-a)/(1-a))^2) -x > 1: - f(x) = (a + 1)/2 -*/ -inline float soft_saturate(float in, float thresh) -{ - bool flip; - float val, out; - //val = fabsf(in); - out = 0.f; - flip = in < 0.0f; - val = flip ? -in : in; - if(val < thresh) - { - out = in; - } - else if(val > 1.0f) - { - out = (thresh + 1.0f) / 2.0f; - if(flip) - out *= -1.0f; - } - else if(val > thresh) - { - float temp; - temp = (val - thresh) / (1 - thresh); - out = thresh + (val - thresh) / (1.0f + (temp * temp)); - if(flip) - out *= -1.0f; - } - return out; - // return val < thresh - // ? val - // : val > 1.0f - // ? (thresh + 1.0f) / 2.0f - // : thresh - // + (val - thresh) - // / (1.0f - // + (((val - thresh) / (1.0f - thresh)) - // * ((val - thresh) / (1.0f - thresh)))); -} -constexpr bool is_power2(uint32_t x) -{ - return ((x - 1) & x) == 0; -} - -/** Prior to C++14 constexpr functions were required to be a single return statement. - * So this clause guards against that behavior to allow the library, and this function - * to continue to work with C++11. - * The function itself is not currently (12 May 2021) used within the library itself. - */ -#if __cplusplus <= 201103L -inline uint32_t get_next_power2(uint32_t x) -#else -constexpr uint32_t get_next_power2(uint32_t x) -#endif -{ - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - - assert(is_power2(x)); - return x; -} - -} // namespace daisysp -#endif - -#ifdef DSY_CUSTOM_DSP -#include "custom_dsp.h" -#endif diff --git a/src/daisysp/Utility/looper.h b/src/daisysp/Utility/looper.h deleted file mode 100644 index bfab096..0000000 --- a/src/daisysp/Utility/looper.h +++ /dev/null @@ -1,299 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#include -#include "../Utility/dsp.h" - -namespace daisysp -{ -/** Multimode audio looper -* -* Modes are: -* - Normal -* - Onetime Dub -* - Replace -* - Frippertronics -* -* Read more about the looper modes in the mode enum documentation. -*/ -class Looper -{ - public: - Looper() {} - ~Looper() {} - - /** - ** Normal Mode: Input is added to the existing loop infinitely while recording - ** - ** Onetime Dub Mode: Recording starts at the first sample of the buffer and is added - ** to the existing buffer contents. Recording automatically stops after one full loop. - ** - ** Replace Mode: Audio in the buffer is replaced while recording is on. - ** - ** Frippertronics Mode: infinite looping recording with fixed decay on each loop. The module acts like tape-delay set up. - */ - enum class Mode - { - NORMAL, - ONETIME_DUB, - REPLACE, - FRIPPERTRONICS, - }; - - void Init(float *mem, size_t size) - { - buffer_size_ = size; - buff_ = mem; - - InitBuff(); - state_ = State::EMPTY; - mode_ = Mode::NORMAL; - half_speed_ = false; - reverse_ = false; - rec_queue_ = false; - win_idx_ = 0; - } - - /** Handles reading/writing to the Buffer depending on the mode. */ - float Process(const float input) - { - float sig = 0.f; - float inc; - bool hitloop = false; - // Record forward at normal speed during the first loop no matter what. - inc = state_ == State::EMPTY || state_ == State::REC_FIRST - ? 1.f - : GetIncrementSize(); - win_ = WindowVal(win_idx_ * kWindowFactor); - switch(state_) - { - case State::EMPTY: sig = 0.0f; break; - case State::REC_FIRST: - sig = 0.f; - Write(pos_, input * win_); - if(win_idx_ < kWindowSamps - 1) - win_idx_ += 1; - recsize_ = pos_; - pos_ += inc; - if(pos_ > buffer_size_ - 1) - { - state_ = State::PLAYING; - recsize_ = pos_ - 1; - pos_ = 0; - } - break; - case State::PLAYING: - sig = Read(pos_); - /** This is a way of 'seamless looping' - ** The first N samps after recording is done are recorded with the input faded out. - */ - if(win_idx_ < kWindowSamps - 1) - { - Write(pos_, sig + input * (1.f - win_)); - win_idx_ += 1; - } - - pos_ += inc; - if(pos_ > recsize_ - 1) - { - pos_ = 0; - hitloop = true; - } - else if(pos_ < 0) - { - pos_ = recsize_ - 1; - hitloop = true; - } - if(hitloop) - - { - if(rec_queue_ && mode_ == Mode::ONETIME_DUB) - { - rec_queue_ = false; - state_ = State::REC_DUB; - win_idx_ = 0; - } - } - break; - case State::REC_DUB: - sig = Read(pos_); - switch(mode_) - { - case Mode::REPLACE: Write(pos_, input * win_); break; - case Mode::FRIPPERTRONICS: - Write(pos_, (input * win_) + (sig * kFripDecayVal)); - break; - case Mode::NORMAL: - case Mode::ONETIME_DUB: - default: Write(pos_, (input * win_) + sig); break; - } - if(win_idx_ < kWindowSamps - 1) - win_idx_ += 1; - pos_ += inc; - if(pos_ > recsize_ - 1) - { - pos_ = 0; - hitloop = true; - } - else if(pos_ < 0) - { - pos_ = recsize_ - 1; - hitloop = true; - } - if(hitloop && mode_ == Mode::ONETIME_DUB) - { - state_ = State::PLAYING; - win_idx_ = 0; - } - - break; - default: break; - } - near_beginning_ = state_ != State::EMPTY && !Recording() && pos_ < 4800 - ? true - : false; - - return sig; - } - - /** Effectively erases the buffer - ** Note: This does not actually change what is in the buffer */ - inline void Clear() { state_ = State::EMPTY; } - - /** Engages/Disengages the recording, depending on Mode. - ** In all modes, the first time this is triggered a new loop will be started. - ** The second trigger will set the loop size, and begin playback of the loop. - */ - inline void TrigRecord() - { - switch(state_) - { - case State::EMPTY: - pos_ = 0; - recsize_ = 0; - state_ = State::REC_FIRST; - half_speed_ = false; - reverse_ = false; - break; - case State::REC_FIRST: - case State::REC_DUB: state_ = State::PLAYING; break; - case State::PLAYING: - if(mode_ == Mode::ONETIME_DUB) - rec_queue_ = true; - else - state_ = State::REC_DUB; - break; - default: state_ = State::EMPTY; break; - } - if(!rec_queue_) - win_idx_ = 0; - } - - /** Returns true if the looper is currently being written to. */ - inline const bool Recording() const - { - return state_ == State::REC_DUB || state_ == State::REC_FIRST; - } - - inline const bool RecordingQueued() const { return rec_queue_; } - - /** Increments the Mode by one step useful for buttons, etc. that need to step through the Looper modes. */ - inline void IncrementMode() - { - int m = static_cast(mode_); - m = m + 1; - if(m > kNumModes - 1) - m = 0; - mode_ = static_cast(m); - } - - /** Sets the recording mode to the specified Mode. */ - inline void SetMode(Mode mode) { mode_ = mode; } - - /** Returns the specific recording mode that is currently set. */ - inline const Mode GetMode() const { return mode_; } - - inline void ToggleReverse() { reverse_ = !reverse_; } - inline void SetReverse(bool state) { reverse_ = state; } - inline bool GetReverse() const { return reverse_; } - - inline void ToggleHalfSpeed() { half_speed_ = !half_speed_; } - inline void SetHalfSpeed(bool state) { half_speed_ = state; } - inline bool GetHalfSpeed() const { return half_speed_; } - - inline bool IsNearBeginning() { return near_beginning_; } - - private: - /** Constants */ - - /** Decay value for frippertronics mode is sin(PI / 4) */ - static constexpr float kFripDecayVal = 0.7071067811865476f; - static constexpr int kNumModes = 4; - static constexpr int kNumPlaybackSpeeds = 3; - static constexpr int kWindowSamps = 1200; - static constexpr float kWindowFactor = (1.f / kWindowSamps); - - /** Private Member Functions */ - float GetIncrementSize() - { - float inc = 1.f; - if(half_speed_) - inc = 0.5f; - return reverse_ ? -inc : inc; - } - - /** Initialize the buffer */ - void InitBuff() { std::fill(&buff_[0], &buff_[buffer_size_ - 1], 0); } - - /** Get a floating point sample from the buffer */ - inline const float Read(size_t pos) const { return buff_[pos]; } - - /** Reads from a specified point in the delay line using linear interpolation */ - float ReadF(float pos) - { - float a, b, frac; - uint32_t i_idx = static_cast(pos); - frac = pos - i_idx; - a = buff_[i_idx]; - b = buff_[(i_idx + 1) % buffer_size_]; - return a + (b - a) * frac; - } - - /** Write to a known location in the buffer */ - inline void Write(size_t pos, float val) { buff_[pos] = val; } - - /** Linear to Constpower approximation for windowing*/ - float WindowVal(float in) { return sin(HALFPI_F * in); } - - // Private Enums - - /** Internal looper state */ - enum class State - { - EMPTY, - REC_FIRST, - PLAYING, - REC_DUB, - }; - - /** Private Member Variables */ - Mode mode_; - State state_; - float *buff_; - size_t buffer_size_; - float pos_, win_; - size_t win_idx_; - bool half_speed_; - bool reverse_; - size_t recsize_; - bool rec_queue_; - bool near_beginning_; -}; - -} // namespace daisysp diff --git a/src/daisysp/Utility/maytrig.h b/src/daisysp/Utility/maytrig.h deleted file mode 100644 index 28f7f64..0000000 --- a/src/daisysp/Utility/maytrig.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_MAYTRIG_H -#define DSY_MAYTRIG_H - -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Probabilistic trigger module - -Original author(s) : Paul Batchelor - -Ported from soundpipe by Ben Sergentanis, May 2020 -*/ -class Maytrig -{ - public: - Maytrig() {} - ~Maytrig() {} - /** probabilistically generates triggers - - \param prob (1 always returns true, 0 always false) - - \return given a probability 0 to 1, returns true or false. - */ - inline float Process(float prob) - { - return ((float)rand() / (float)RAND_MAX) <= prob ? true : false; - } - - private: -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Utility/metro.cpp b/src/daisysp/Utility/metro.cpp deleted file mode 100644 index 2dd8462..0000000 --- a/src/daisysp/Utility/metro.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include "metro.h" -#include "../Utility/dsp.h" - -using namespace daisysp; - -void Metro::Init(float freq, float sample_rate) -{ - freq_ = freq; - phs_ = 0.0f; - sample_rate_ = sample_rate; - phs_inc_ = (TWOPI_F * freq_) / sample_rate_; -} - -uint8_t Metro::Process() -{ - phs_ += phs_inc_; - if(phs_ >= TWOPI_F) - { - phs_ -= TWOPI_F; - return 1; - } - return 0; -} - -void Metro::SetFreq(float freq) -{ - freq_ = freq; - phs_inc_ = (TWOPI_F * freq_) / sample_rate_; -} diff --git a/src/daisysp/Utility/metro.h b/src/daisysp/Utility/metro.h deleted file mode 100644 index 6f94d06..0000000 --- a/src/daisysp/Utility/metro.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_METRO_H -#define DSY_METRO_H -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Creates a clock signal at a specific frequency. -*/ -class Metro -{ - public: - Metro() {} - ~Metro() {} - /** Initializes Metro module. - Arguments: - - freq: frequency at which new clock signals will be generated - Input Range: - - sample_rate: sample rate of audio engine - Input range: - */ - void Init(float freq, float sample_rate); - - /** checks current state of Metro object and updates state if necesary. - */ - uint8_t Process(); - - /** resets phase to 0 - */ - inline void Reset() { phs_ = 0.0f; } - /** Sets frequency at which Metro module will run at. - */ - void SetFreq(float freq); - - /** Returns current value for frequency. - */ - inline float GetFreq() { return freq_; } - - private: - float freq_; - float phs_, sample_rate_, phs_inc_; -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Utility/samplehold.h b/src/daisysp/Utility/samplehold.h deleted file mode 100644 index 7bbcfc3..0000000 --- a/src/daisysp/Utility/samplehold.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SAMPLEHOLD_H -#define DSY_SAMPLEHOLD_H - -#include -#ifdef __cplusplus - -namespace daisysp -{ -/** Dual track and hold / Sample and hold module. \n - Ported from soundpipe by Ben Sergentanis, June 2020. - @author Paul Batchelor - @date 2015 -*/ -class SampleHold -{ - public: - SampleHold() {} - ~SampleHold() {} - - enum Mode - { - MODE_SAMPLE_HOLD, - MODE_TRACK_HOLD, - MODE_LAST, - }; - - /** Process the next sample. Both sample and track and hold are run in parallel - \param trigger Trigger the sample/track and hold - \param input Signal to be sampled/tracked and held - \param mode Whether to output the tracked or sampled values. - */ - inline float - Process(bool trigger, float input, Mode mode = MODE_SAMPLE_HOLD) - { - Update(trigger, input); - return mode == MODE_SAMPLE_HOLD ? sample_ : track_; - } - - private: - float track_ = 0; - float sample_ = 0; - bool previous_ = false; - - - inline void Update(bool trigger, float input) - { - if(trigger) - { - if(!previous_) - { - sample_ = input; - } - track_ = input; - } - previous_ = trigger; - } -}; -} // namespace daisysp -#endif -#endif diff --git a/src/daisysp/Utility/smooth_random.h b/src/daisysp/Utility/smooth_random.h deleted file mode 100644 index 56e6d99..0000000 --- a/src/daisysp/Utility/smooth_random.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet - -Use of this source code is governed by an MIT-style -license that can be found in the LICENSE file or at -https://opensource.org/licenses/MIT. -*/ - -#pragma once -#ifndef DSY_SMOOTHRANDOM_H -#define DSY_SMOOTHRANDOM_H - -#include "../Utility/dsp.h" -#include -#include -#ifdef __cplusplus - -/** @file smooth_random.h */ - -namespace daisysp -{ -/** - @brief Smooth random generator for internal modulation. \n - @author Ported by Ben Sergentanis - @date Jan 2021 - Ported from pichenettes/eurorack/plaits/dsp/noise/smooth_random_generator.h \n - to an independent module. \n - Original code written by Emilie Gillet in 2016. \n -*/ -class SmoothRandomGenerator -{ - public: - SmoothRandomGenerator() {} - ~SmoothRandomGenerator() {} - - /** Initialize the module - \param sample_rate Audio engine sample rate. - */ - void Init(float sample_rate) - { - sample_rate_ = sample_rate; - - SetFreq(1.f); - phase_ = 0.0f; - from_ = 0.0f; - interval_ = 0.0f; - } - - /** Get the next float. Ranges from -1 to 1. */ - float Process() - { - phase_ += frequency_; - if(phase_ >= 1.0f) - { - phase_ -= 1.0f; - from_ += interval_; - interval_ = rand() * kRandFrac * 2.0f - 1.0f - from_; - } - float t = phase_ * phase_ * (3.0f - 2.0f * phase_); - return from_ + interval_ * t; - } - - /** How often to slew to a new random value - \param freq Rate in Hz - */ - void SetFreq(float freq) - { - freq = freq / sample_rate_; - frequency_ = fclamp(freq, 0.f, 1.f); - } - - private: - float frequency_; - float phase_; - float from_; - float interval_; - - float sample_rate_; - - static constexpr float kRandFrac = 1.f / (float)RAND_MAX; -}; - -} // namespace daisysp -#endif -#endif \ No newline at end of file diff --git a/src/daisysp/daisysp.h b/src/daisysp/daisysp.h deleted file mode 100644 index bb06f15..0000000 --- a/src/daisysp/daisysp.h +++ /dev/null @@ -1,97 +0,0 @@ -// DaisySP is a DSP Library targeted at the Electrosmith Daisy Product Line. -// Author: Stephen Hensley, 2019 -// -// However, this is decoupled from the hardware in such a way that it -// should be useful outside of the ARM context with different build configurations. -// -// A few general notes about the contents of the library: -// - all memory usage is static. -// - in cases of potentially large memory usage: the user will either supply a buffer and a size, or the class will be a template that can have size set at compile time. -// - all modules will have an Init() function, and a Process() function. -// - all modules, unless otherwise noted, will process a single sample at a time. -// - all processing will be done with 'float' type unless otherwise noted. -// -#pragma once -#ifndef DSYSP_H -#define DSYSP_H - -/** Control Modules */ -#include "../Control/adenv.h" -#include "../Control/adsr.h" -#include "../Control/phasor.h" - -/** Drum Modules */ -#include "../Drums/analogbassdrum.h" -#include "../Drums/analogsnaredrum.h" -#include "../Drums/hihat.h" -#include "../Drums/synthbassdrum.h" -#include "../Drums/synthsnaredrum.h" - -/** Dynamics Modules */ -#include "../Dynamics/crossfade.h" -#include "../Dynamics/limiter.h" - -/** Effects Modules */ -#include "../Effects/autowah.h" -#include "../Effects/chorus.h" -#include "../Effects/decimator.h" -#include "../Effects/flanger.h" -#include "../Effects/overdrive.h" -#include "../Effects/pitchshifter.h" -#include "../Effects/phaser.h" -#include "../Effects/sampleratereducer.h" -#include "../Effects/tremolo.h" -#include "../Effects/wavefolder.h" - -/** Filter Modules */ -#include "../Filters/ladder.h" -#include "../Filters/onepole.h" -#include "../Filters/svf.h" -#include "../Filters/fir.h" -#include "../Filters/soap.h" - -/** Noise Modules */ -#include "../Noise/clockednoise.h" -#include "../Noise/dust.h" -#include "../Noise/fractal_noise.h" -#include "../Noise/grainlet.h" -#include "../Noise/particle.h" -#include "../Noise/whitenoise.h" - -/** Physical Modeling Modules */ -#include "../PhysicalModeling/drip.h" -#include "../PhysicalModeling/KarplusString.h" -#include "../PhysicalModeling/modalvoice.h" -#include "../PhysicalModeling/resonator.h" -#include "../PhysicalModeling/stringvoice.h" - -/** Sampling Modules */ -#include "../Sampling/granularplayer.h" - -/** Synthesis Modules */ -#include "../Synthesis/fm2.h" -#include "../Synthesis/formantosc.h" -#include "../Synthesis/harmonic_osc.h" -#include "../Synthesis/oscillator.h" -#include "../Synthesis/oscillatorbank.h" -#include "../Synthesis/variablesawosc.h" -#include "../Synthesis/variableshapeosc.h" -#include "../Synthesis/vosim.h" -#include "../Synthesis/zoscillator.h" - -/** Utility Modules */ -#include "../Utility/dcblock.h" -#include "../Utility/delayline.h" -#include "../Utility/dsp.h" -#include "../Utility/looper.h" -#include "../Utility/maytrig.h" -#include "../Utility/metro.h" -#include "../Utility/samplehold.h" -#include "../Utility/smooth_random.h" - -/** LGPL Modules */ -#ifdef USE_DAISYSP_LGPL -#include "daisysp-lgpl.h" -#endif - -#endif