| @@ -3,6 +3,11 @@ | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| static const float FREQ_C4 = 261.6256f; | |||||
| static const float FREQ_A4 = 440.0000f; | |||||
| /** The normalized sinc function. https://en.wikipedia.org/wiki/Sinc_function */ | /** The normalized sinc function. https://en.wikipedia.org/wiki/Sinc_function */ | ||||
| @@ -42,13 +47,14 @@ inline float exponentialBipolar(float b, float x) { | |||||
| return (std::pow(b, x) - std::pow(b, -x)) / a; | return (std::pow(b, x) - std::pow(b, -x)) / a; | ||||
| } | } | ||||
| inline float gainToDb(float gain) { | |||||
| return std::log10(gain) * 20.f; | |||||
| inline float amplitudeToDb(float amp) { | |||||
| return std::log10(amp) * 20.f; | |||||
| } | } | ||||
| inline float dbToGain(float db) { | |||||
| inline float dbToAmplitude(float db) { | |||||
| return std::pow(10.f, db / 20.f); | return std::pow(10.f, db / 20.f); | ||||
| } | } | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,2 +0,0 @@ | |||||
| #pragma once | |||||
| #include "resampler.hpp" | |||||
| @@ -1,8 +1,9 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "math.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| /** Turns HIGH when value reaches 1.f, turns LOW when value reaches 0.f. */ | /** Turns HIGH when value reaches 1.f, turns LOW when value reaches 0.f. */ | ||||
| @@ -102,4 +103,5 @@ struct PulseGenerator { | |||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,8 +1,10 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "math.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| struct RCFilter { | struct RCFilter { | ||||
| float c = 0.f; | float c = 0.f; | ||||
| @@ -81,4 +83,5 @@ struct ExponentialFilter { | |||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,9 +1,11 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "dsp/functions.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| #include <pffft.h> | #include <pffft.h> | ||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| /** Performs a direct sum convolution */ | /** Performs a direct sum convolution */ | ||||
| inline float convolveNaive(const float *in, const float *kernel, int len) { | inline float convolveNaive(const float *in, const float *kernel, int len) { | ||||
| @@ -145,4 +147,5 @@ struct RealTimeConvolver { | |||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,8 +1,10 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <stdlib.h> | |||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| /** Useful for storing arrays of samples in ring buffers and casting them to `float*` to be used by interleaved processors, like SampleRateConverter */ | /** Useful for storing arrays of samples in ring buffers and casting them to `float*` to be used by interleaved processors, like SampleRateConverter */ | ||||
| template <size_t CHANNELS> | template <size_t CHANNELS> | ||||
| @@ -10,4 +12,6 @@ struct Frame { | |||||
| float samples[CHANNELS]; | float samples[CHANNELS]; | ||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,8 +1,10 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "math.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| // Pre-made minBLEP samples in minBLEP.cpp | // Pre-made minBLEP samples in minBLEP.cpp | ||||
| extern const float minblep_16_32[]; | extern const float minblep_16_32[]; | ||||
| @@ -33,4 +35,6 @@ struct MinBLEP { | |||||
| } | } | ||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,8 +1,10 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace ode { | |||||
| namespace dsp { | |||||
| /** The callback function `f` in each of these stepping functions must have the signature | /** The callback function `f` in each of these stepping functions must have the signature | ||||
| @@ -84,5 +86,6 @@ void stepRK4(float t, float dt, float x[], int len, F f) { | |||||
| } | } | ||||
| } | } | ||||
| } // namespace ode | |||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,13 +1,16 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "frame.hpp" | |||||
| #include "ringbuffer.hpp" | |||||
| #include "fir.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| #include "dsp/frame.hpp" | |||||
| #include "dsp/ringbuffer.hpp" | |||||
| #include "dsp/fir.hpp" | |||||
| #include <assert.h> | #include <assert.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <speex/speex_resampler.h> | #include <speex/speex_resampler.h> | ||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| template<int CHANNELS> | template<int CHANNELS> | ||||
| struct SampleRateConverter { | struct SampleRateConverter { | ||||
| @@ -170,4 +173,5 @@ struct Upsampler { | |||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,9 +1,11 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "common.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| #include <string.h> | #include <string.h> | ||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| /** A simple cyclic buffer. | /** A simple cyclic buffer. | ||||
| S must be a power of 2. | S must be a power of 2. | ||||
| @@ -196,4 +198,6 @@ struct AppleRingBuffer { | |||||
| } | } | ||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,2 +0,0 @@ | |||||
| #pragma once | |||||
| #include "resampler.hpp" | |||||
| @@ -1,8 +1,9 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "math.hpp" | |||||
| #include "dsp/common.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| namespace dsp { | |||||
| struct VUMeter { | struct VUMeter { | ||||
| @@ -28,4 +29,5 @@ struct VUMeter { | |||||
| }; | }; | ||||
| } // namespace dsp | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -80,6 +80,16 @@ | |||||
| #include "plugin/Model.hpp" | #include "plugin/Model.hpp" | ||||
| #include "plugin/callbacks.hpp" | #include "plugin/callbacks.hpp" | ||||
| #include "dsp/common.hpp" | |||||
| #include "dsp/digital.hpp" | |||||
| #include "dsp/filter.hpp" | |||||
| #include "dsp/fir.hpp" | |||||
| #include "dsp/frame.hpp" | |||||
| #include "dsp/minblep.hpp" | |||||
| #include "dsp/ode.hpp" | |||||
| #include "dsp/resampler.hpp" | |||||
| #include "dsp/ringbuffer.hpp" | |||||
| #include "dsp/vumeter.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| @@ -147,4 +147,19 @@ DEPRECATED inline float engineGetSampleTime() { | |||||
| return context()->engine->getSampleTime(); | return context()->engine->getSampleTime(); | ||||
| } | } | ||||
| //////////////////// | |||||
| // dsp | |||||
| //////////////////// | |||||
| using namespace dsp; | |||||
| inline float gainToDb(float gain) { | |||||
| return dsp::amplitudeToDb(gain); | |||||
| } | |||||
| inline float dbToGain(float db) { | |||||
| return dsp::dbToAmplitude(db); | |||||
| } | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -1,7 +1,5 @@ | |||||
| #include "Core.hpp" | #include "Core.hpp" | ||||
| #include "audio.hpp" | #include "audio.hpp" | ||||
| #include "dsp/resampler.hpp" | |||||
| #include "dsp/ringbuffer.hpp" | |||||
| #include <mutex> | #include <mutex> | ||||
| #include <chrono> | #include <chrono> | ||||
| #include <thread> | #include <thread> | ||||
| @@ -23,9 +21,9 @@ struct AudioInterfaceIO : audio::IO { | |||||
| std::mutex audioMutex; | std::mutex audioMutex; | ||||
| std::condition_variable audioCv; | std::condition_variable audioCv; | ||||
| // Audio thread produces, engine thread consumes | // Audio thread produces, engine thread consumes | ||||
| DoubleRingBuffer<Frame<AUDIO_INPUTS>, (1<<15)> inputBuffer; | |||||
| dsp::DoubleRingBuffer<dsp::Frame<AUDIO_INPUTS>, (1<<15)> inputBuffer; | |||||
| // Audio thread consumes, engine thread produces | // Audio thread consumes, engine thread produces | ||||
| DoubleRingBuffer<Frame<AUDIO_OUTPUTS>, (1<<15)> outputBuffer; | |||||
| dsp::DoubleRingBuffer<dsp::Frame<AUDIO_OUTPUTS>, (1<<15)> outputBuffer; | |||||
| bool active = false; | bool active = false; | ||||
| ~AudioInterfaceIO() { | ~AudioInterfaceIO() { | ||||
| @@ -46,7 +44,7 @@ struct AudioInterfaceIO : audio::IO { | |||||
| for (int i = 0; i < frames; i++) { | for (int i = 0; i < frames; i++) { | ||||
| if (inputBuffer.full()) | if (inputBuffer.full()) | ||||
| break; | break; | ||||
| Frame<AUDIO_INPUTS> inputFrame; | |||||
| dsp::Frame<AUDIO_INPUTS> inputFrame; | |||||
| memset(&inputFrame, 0, sizeof(inputFrame)); | memset(&inputFrame, 0, sizeof(inputFrame)); | ||||
| memcpy(&inputFrame, &input[numInputs * i], numInputs * sizeof(float)); | memcpy(&inputFrame, &input[numInputs * i], numInputs * sizeof(float)); | ||||
| inputBuffer.push(inputFrame); | inputBuffer.push(inputFrame); | ||||
| @@ -62,7 +60,7 @@ struct AudioInterfaceIO : audio::IO { | |||||
| if (audioCv.wait_for(lock, timeout, cond)) { | if (audioCv.wait_for(lock, timeout, cond)) { | ||||
| // Consume audio block | // Consume audio block | ||||
| for (int i = 0; i < frames; i++) { | for (int i = 0; i < frames; i++) { | ||||
| Frame<AUDIO_OUTPUTS> f = outputBuffer.shift(); | |||||
| dsp::Frame<AUDIO_OUTPUTS> f = outputBuffer.shift(); | |||||
| for (int j = 0; j < numOutputs; j++) { | for (int j = 0; j < numOutputs; j++) { | ||||
| output[numOutputs*i + j] = clamp(f.samples[j], -1.f, 1.f); | output[numOutputs*i + j] = clamp(f.samples[j], -1.f, 1.f); | ||||
| } | } | ||||
| @@ -112,12 +110,12 @@ struct AudioInterface : Module { | |||||
| int lastNumOutputs = -1; | int lastNumOutputs = -1; | ||||
| int lastNumInputs = -1; | int lastNumInputs = -1; | ||||
| SampleRateConverter<AUDIO_INPUTS> inputSrc; | |||||
| SampleRateConverter<AUDIO_OUTPUTS> outputSrc; | |||||
| dsp::SampleRateConverter<AUDIO_INPUTS> inputSrc; | |||||
| dsp::SampleRateConverter<AUDIO_OUTPUTS> outputSrc; | |||||
| // in rack's sample rate | // in rack's sample rate | ||||
| DoubleRingBuffer<Frame<AUDIO_INPUTS>, 16> inputBuffer; | |||||
| DoubleRingBuffer<Frame<AUDIO_OUTPUTS>, 16> outputBuffer; | |||||
| dsp::DoubleRingBuffer<dsp::Frame<AUDIO_INPUTS>, 16> inputBuffer; | |||||
| dsp::DoubleRingBuffer<dsp::Frame<AUDIO_OUTPUTS>, 16> outputBuffer; | |||||
| AudioInterface() { | AudioInterface() { | ||||
| setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| @@ -177,7 +175,7 @@ void AudioInterface::step() { | |||||
| } | } | ||||
| // Take input from buffer | // Take input from buffer | ||||
| Frame<AUDIO_INPUTS> inputFrame; | |||||
| dsp::Frame<AUDIO_INPUTS> inputFrame; | |||||
| if (!inputBuffer.empty()) { | if (!inputBuffer.empty()) { | ||||
| inputFrame = inputBuffer.shift(); | inputFrame = inputBuffer.shift(); | ||||
| } | } | ||||
| @@ -195,7 +193,7 @@ void AudioInterface::step() { | |||||
| if (audioIO.active && audioIO.numOutputs > 0) { | if (audioIO.active && audioIO.numOutputs > 0) { | ||||
| // Get and push output SRC frame | // Get and push output SRC frame | ||||
| if (!outputBuffer.full()) { | if (!outputBuffer.full()) { | ||||
| Frame<AUDIO_OUTPUTS> outputFrame; | |||||
| dsp::Frame<AUDIO_OUTPUTS> outputFrame; | |||||
| for (int i = 0; i < AUDIO_OUTPUTS; i++) { | for (int i = 0; i < AUDIO_OUTPUTS; i++) { | ||||
| outputFrame.samples[i] = inputs[AUDIO_INPUT + i].getVoltage() / 10.f; | outputFrame.samples[i] = inputs[AUDIO_INPUT + i].getVoltage() / 10.f; | ||||
| } | } | ||||
| @@ -1,6 +1,5 @@ | |||||
| #include "Core.hpp" | #include "Core.hpp" | ||||
| #include "midi.hpp" | #include "midi.hpp" | ||||
| #include "dsp/filter.hpp" | |||||
| struct MIDICCToCVInterface : Module { | struct MIDICCToCVInterface : Module { | ||||
| @@ -20,7 +19,7 @@ struct MIDICCToCVInterface : Module { | |||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| int8_t ccs[128]; | int8_t ccs[128]; | ||||
| ExponentialFilter ccFilters[16]; | |||||
| dsp::ExponentialFilter ccFilters[16]; | |||||
| int learningId = -1; | int learningId = -1; | ||||
| int learnedCcs[16] = {}; | int learnedCcs[16] = {}; | ||||
| @@ -1,7 +1,5 @@ | |||||
| #include "Core.hpp" | #include "Core.hpp" | ||||
| #include "midi.hpp" | #include "midi.hpp" | ||||
| #include "dsp/digital.hpp" | |||||
| #include "dsp/filter.hpp" | |||||
| #include <algorithm> | #include <algorithm> | ||||
| @@ -35,14 +33,14 @@ struct MIDIToCVInterface : Module { | |||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| uint8_t mod = 0; | uint8_t mod = 0; | ||||
| ExponentialFilter modFilter; | |||||
| dsp::ExponentialFilter modFilter; | |||||
| uint16_t pitch = 8192; | uint16_t pitch = 8192; | ||||
| ExponentialFilter pitchFilter; | |||||
| PulseGenerator retriggerPulse; | |||||
| PulseGenerator clockPulses[2]; | |||||
| PulseGenerator startPulse; | |||||
| PulseGenerator stopPulse; | |||||
| PulseGenerator continuePulse; | |||||
| dsp::ExponentialFilter pitchFilter; | |||||
| dsp::PulseGenerator retriggerPulse; | |||||
| dsp::PulseGenerator clockPulses[2]; | |||||
| dsp::PulseGenerator startPulse; | |||||
| dsp::PulseGenerator stopPulse; | |||||
| dsp::PulseGenerator continuePulse; | |||||
| int clock = 0; | int clock = 0; | ||||
| int divisions[2]; | int divisions[2]; | ||||
| @@ -1,6 +1,5 @@ | |||||
| #include "Core.hpp" | #include "Core.hpp" | ||||
| #include "midi.hpp" | #include "midi.hpp" | ||||
| #include "dsp/digital.hpp" | |||||
| #include <algorithm> | #include <algorithm> | ||||