diff --git a/README.md b/README.md index eb8d4d4..6d54c22 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ ChangeLog ```` +== 2024-12-07 + * Bugfix: + * EnvFollower - IO-page AUX input + * Enhancements: + * EnvFollower - mode Follower, Vactrol (based on MU Streams) == 2024-11-30 * Bugfix: * Crash on patch saving/restoring (#97) diff --git a/app/CV/EnvFollower.bin b/app/CV/EnvFollower.bin new file mode 100644 index 0000000..433a494 Binary files /dev/null and b/app/CV/EnvFollower.bin differ diff --git a/app/CV/EnvFollower.cpp b/app/CV/EnvFollower.cpp new file mode 100644 index 0000000..bd2081e --- /dev/null +++ b/app/CV/EnvFollower.cpp @@ -0,0 +1,134 @@ +// Copyright (C)2021 - E.Heidt +// +// Author: E.Heidt (eh2k@gmx.de) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +#include "../squares-and-circles-api.h" +#include +#include "../../lib/streams/follower.h" +#include "../../lib/streams/vactrol.h" +#include "../../lib/streams/audio_cv_meter.h" + +streams::Follower _follower; +streams::Vactrol _vactrol; +streams::AudioCvMeter _meter; + +int32_t attack_ = 0; +int32_t decay_ = 0; +int32_t mode_ = 0; + +namespace gfx +{ + uint8_t i = 0; + int8_t scope[128] = {}; + void drawScope(int x0, int y) + { + for (int x = x0; x < 127; x++) + { + if (x % 3 == 0) + gfx::setPixel(x, y); + gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); + } + } + + void push_scope(int8_t y) + { + scope[i++ % 128] = y; + if (i > 128) + i = 0; + } +} + +const char *mode_names[] = { + "Follower", + "Vactrol", + ""}; + +void engine::setup() +{ + engine::addParam("Attack", &attack_, 0, UINT16_MAX); + engine::addParam("MODE", &mode_, 0, 1, mode_names); + engine::addParam("Decay", &decay_, 0, INT16_MAX); + decay_ = INT16_MAX / 2; + engine::setMode(ENGINE_MODE_COMPACT | ENGINE_MODE_CV_OUT); + + _meter.Init(); + _follower.Init(); + _vactrol.Init(); +} + +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto outputL = engine::outputBuffer_i16<0>(); + + uint16_t gain; + uint16_t freq; + + int32_t paramters[3] = {}; + int32_t globals[3] = {}; + globals[0] = attack_; + globals[2] = decay_; + paramters[1] = 0; + + if (mode_ == 0) + { + _follower.Configure(false, paramters, globals); + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + { + _follower.Process(0, inputL[i] * INT16_MAX, &gain, &freq); + outputL[i] = gain >> 2; //_follower.process(inputL[i]) * 10.f; + } + } + else + { + _vactrol.Configure(false, paramters, globals); + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + { + _vactrol.Process(0, inputL[i] * INT16_MAX, &gain, &freq); + outputL[i] = gain >> 2; //_follower.process(inputL[i]) * 10.f; + } + } + + _meter.Process(inputL[0] * INT16_MAX); + + if ((engine::t() % 50) == 0) + { + int8_t v = outputL[0] >> 9; + CONSTRAIN(v, 0, 14); + gfx::push_scope(v); + } +} + +void engine::draw() +{ + gfx::drawScope(64, 58); + gfx::drawRect(64, 44, 64, 15); + gfx::drawRect(0, 44, 63, 15); + gfx::fillRect(2, 46, (_meter.peak() >> 8), 11); +} + +#include "../../lib/streams/svf.cc" +#include "../../lib/streams/follower.cc" +#include "../../lib/streams/vactrol.cc" +#include "../../lib/streams/resources.cc" \ No newline at end of file diff --git a/app/CV/EnvGen.bin b/app/CV/EnvGen.bin new file mode 100644 index 0000000..a240f7d Binary files /dev/null and b/app/CV/EnvGen.bin differ diff --git a/app/CV/EnvGen.cpp b/app/CV/EnvGen.cpp new file mode 100644 index 0000000..eeb08ff --- /dev/null +++ b/app/CV/EnvGen.cpp @@ -0,0 +1,139 @@ +// Copyright (C)2021 - E.Heidt +// +// Author: E.Heidt (eh2k@gmx.de) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +// ENGINE_NAME:CV/EnvGen_AD;CV/EnvGen_ADSR +// build_flags: -fno-inline -mfloat-abi=hard -mfpu=fpv5-d16 + +#include "../squares-and-circles-api.h" +#include "lib/peaks/modulations/multistage_envelope.h" + +#include "lib/peaks/modulations/multistage_envelope.cc" +#include "lib/peaks/resources.cc" + +peaks::MultistageEnvelope _processor; + +int32_t _attack = 0; +int32_t _decay = UINT16_MAX / 2; +int32_t _sustain = UINT16_MAX / 2; +int32_t _release = UINT16_MAX / 2; + +struct +{ + int8_t scope[128] = {}; + int i = 0; + + void draw(int y) + { + for (int x = 0; x < 127; x++) + { + if (x % 3 == 0) + gfx::setPixel(x, y); + gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); + } + } + + void push(int y) + { + scope[i++ % 128] = y; + if (i > 127) + i = 0; + } +} _scope; + +void engine::setup() +{ + _processor.Init(); + + engine::addParam("Attack", &_attack, 0, UINT16_MAX); + engine::addParam("Decay", &_decay, 0, UINT16_MAX); + + if (!strcmp(engine::name(), "CV/EnvGen_ADSR")) + { + engine::addParam("Sustain", &_sustain, 0, UINT16_MAX); + engine::addParam("Release", &_release, 0, UINT16_MAX); + } + else + { + // AD - Mode + _sustain = -1; + _release = -1; + } + engine::setMode(ENGINE_MODE_COMPACT | ENGINE_MODE_CV_OUT); +} + +void engine::process() +{ + peaks::GateFlags flags[FRAME_BUFFER_SIZE]; + + uint16_t params[4]; + params[0] = _attack; + params[1] = _decay; + if (_sustain >= 0) + { + params[2] = _sustain; + params[3] = _release; + _processor.Configure(params, peaks::CONTROL_MODE_FULL); + } + else + { + // AD - Mode + _processor.Configure(params, peaks::CONTROL_MODE_HALF); + } + + if (engine::trig()) + { + flags[0] = peaks::GATE_FLAG_RISING; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else if (engine::gate()) + { + std::fill(&flags[0], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else + { + flags[0] = flags[0] == peaks::GATE_FLAG_HIGH ? peaks::GATE_FLAG_FALLING : peaks::GATE_FLAG_LOW; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_LOW); + } + + int16_t *buffer = engine::outputBuffer_i16<0>(); + _processor.Process(flags, buffer, FRAME_BUFFER_SIZE); + + static int y = 0; + if ((engine::t() % 50) == 0) + { + _scope.push(y); + y = 0; + } + else + y = std::max(y, buffer[0] / (INT16_MAX / 16)); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + buffer[i] /= 2; +} + +void engine::draw() +{ + _scope.draw(56); +} \ No newline at end of file diff --git a/app/CV/EnvGen_ADSR.bin b/app/CV/EnvGen_ADSR.bin index c818c19..abea342 100644 Binary files a/app/CV/EnvGen_ADSR.bin and b/app/CV/EnvGen_ADSR.bin differ diff --git a/app/CV/LFO.bin b/app/CV/LFO.bin new file mode 100644 index 0000000..1e79817 Binary files /dev/null and b/app/CV/LFO.bin differ diff --git a/app/CV/LFO.cpp b/app/CV/LFO.cpp new file mode 100644 index 0000000..705898f --- /dev/null +++ b/app/CV/LFO.cpp @@ -0,0 +1,125 @@ +// Copyright (C)2021 - E.Heidt +// +// Author: E.Heidt (eh2k@gmx.de) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +// build_flags: -fno-inline -mfloat-abi=hard -mfpu=fpv5-d16 + +#include "../squares-and-circles-api.h" +#include "lib/peaks/modulations/lfo.h" + +#include "lib/peaks/modulations/lfo.cc" +#include "lib/peaks/resources.cc" +#include "lib/stmlib/utils/random.cc" + +peaks::Lfo _processor; + +int32_t shape = peaks::LFO_SHAPE_SINE; +int32_t rate = -INT16_MIN; +int32_t waveform = -INT16_MIN; +float scale = 0.5f; +float offset = 0; + +const char *shape_names[] = {"SIN", "TRI", "SQR", "STEPS", "NOISE"}; + +struct +{ + int8_t scope[128] = {}; + int i = 0; + + void draw(int x0, int y) + { + for (int x = x0; x < 127; x++) + { + if (x % 3 == 0) + gfx::setPixel(x, y); + gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); + } + } + + void push(int y) + { + scope[i++ % 128] = y; + if (i > 127) + i = 0; + } +} _scope; + +void engine::setup() +{ + _processor.Init(); + _processor.set_level(UINT16_MAX); + _processor.set_rate(rate); + _processor.set_parameter((waveform - 32768)); + _processor.set_reset_phase(-INT16_MIN - 32768); + + engine::addParam("Freq.", &rate, 0, UINT16_MAX); + engine::addParam("Shape", &shape, 0, peaks::LFO_SHAPE_LAST - 1, shape_names); + engine::addParam("Scale", &scale, -0.5f, 0.5f); + engine::addParam("Wavefrm", &waveform, 0, UINT16_MAX); + engine::addParam("Offset", &offset, -1, 1); + + engine::setMode(ENGINE_MODE_COMPACT | ENGINE_MODE_CV_OUT); +} + +void engine::process() +{ + peaks::GateFlags flags[FRAME_BUFFER_SIZE]; + + _processor.set_shape((peaks::LfoShape)shape); + _processor.set_rate(rate); + _processor.set_parameter((waveform - 32768)); + + if (engine::trig()) + { + flags[0] = peaks::GATE_FLAG_RISING; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else if (engine::gate()) + { + std::fill(&flags[0], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else + { + flags[0] = flags[0] == peaks::GATE_FLAG_HIGH ? peaks::GATE_FLAG_FALLING : peaks::GATE_FLAG_LOW; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_LOW); + } + + int16_t *buffer = engine::outputBuffer_i16<0>(); + _processor.Process(flags, buffer, FRAME_BUFFER_SIZE); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + { + buffer[i] >>= 1; + buffer[i] *= scale; + buffer[i] += (offset * PITCH_PER_OCTAVE * 5); + } + + if ((engine::t() % 50) == 0) + _scope.push(buffer[0] >> 10); +} + +void engine::draw() +{ + _scope.draw(64, 51); +} \ No newline at end of file diff --git a/app/CV/V_OCT.bin b/app/CV/V_OCT.bin new file mode 100644 index 0000000..0246cf1 Binary files /dev/null and b/app/CV/V_OCT.bin differ diff --git a/app/CV/V_OCT.cpp b/app/CV/V_OCT.cpp new file mode 100644 index 0000000..e8fffa6 --- /dev/null +++ b/app/CV/V_OCT.cpp @@ -0,0 +1,88 @@ +// Copyright (C)2021 - E.Heidt +// +// Author: E.Heidt (eh2k@gmx.de) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +// ENGINE_NAME: CV/V/OCT + +#include "../squares-and-circles-api.h" +#include + +#define ONE_POLE(out, in, coefficient) out += (coefficient) * ((in) - out); + +float note = 0; +int32_t tune = 128; +int32_t cv0 = 0; +int16_t cv_ = 0; +float glide = 0; + +namespace gfx +{ + uint8_t i = 0; + int8_t scope[128] = {}; + void drawScope(int x0, int y) + { + for (int x = x0; x < 127; x++) + { + if (x % 3 == 0) + gfx::setPixel(x, y); + gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); + } + } + + void push_scope(int8_t y) + { + scope[i++ % 128] = y; + if (i > 128) + i = 0; + } +} + +void engine::setup() +{ + engine::addParam(V_OCT, ¬e); + engine::addParam("Fine", &tune, 0, 254); + engine::addParam("Slew", &glide, 0, 0.5f); + engine::setMode(ENGINE_MODE_COMPACT | ENGINE_MODE_CV_OUT); +} + +void engine::process() +{ + cv0 = engine::qz_process(PITCH_PER_OCTAVE * 2 + engine::cv_i32(), 0, nullptr) // note is added internal + + (((int)tune - 128) << 2); + + ONE_POLE(cv_, cv0, powf(1 - glide, 10)); + + std::fill_n(engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE, cv_); + + if ((engine::t() % 50) == 0) + gfx::push_scope((float)cv_ / PITCH_PER_OCTAVE * 4); +} + +void engine::draw() +{ + char tmp[64]; + sprintf(tmp, "OUT:%.2fV", ((float)cv_ / PITCH_PER_OCTAVE)); + gfx::drawString(4 + 64, 32, tmp, 0); + gfx::drawScope(0, 50); +} diff --git a/app/DRUMS/808ish-BD.bin b/app/DRUMS/808ish-BD.bin index ea5b9d5..9423a4e 100644 Binary files a/app/DRUMS/808ish-BD.bin and b/app/DRUMS/808ish-BD.bin differ diff --git a/app/DRUMS/808ish-BD.cpp b/app/DRUMS/808ish-BD.cpp index 65ef64d..00f8ff6 100644 --- a/app/DRUMS/808ish-BD.cpp +++ b/app/DRUMS/808ish-BD.cpp @@ -26,9 +26,7 @@ // build_flags: -fno-inline -mfloat-abi=hard -mfpu=fpv5-d16 #include "../squares-and-circles-api.h" -#include "peaks/drums/bass_drum.h" -#include "peaks/drums/bass_drum.cc" -#include "resources/peaks_lut_svf.hpp" +#include "lib/peaks/drums/bass_drum.h" peaks::BassDrum _processor; @@ -72,4 +70,7 @@ void engine::process() } _processor.Process(flags, engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE); -} \ No newline at end of file +} + +#include "lib/peaks/drums/bass_drum.cc" +#include "lib/peaks/resources.cc" diff --git a/app/DRUMS/808ish-HiHat.bin b/app/DRUMS/808ish-HiHat.bin index 7f0039f..cbfcc01 100644 Binary files a/app/DRUMS/808ish-HiHat.bin and b/app/DRUMS/808ish-HiHat.bin differ diff --git a/app/DRUMS/808ish-HiHat.cpp b/app/DRUMS/808ish-HiHat.cpp index 5875b1a..fbcd0bb 100644 --- a/app/DRUMS/808ish-HiHat.cpp +++ b/app/DRUMS/808ish-HiHat.cpp @@ -23,13 +23,12 @@ // See http://creativecommons.org/licenses/MIT/ for more information. // +// build_flags: -fno-inline -mfloat-abi=hard -mfpu=fpv5-d16 -ffast-math + #include "../squares-and-circles-api.h" #define private public -#include "peaks/drums/high_hat.h" -#include "peaks/drums/high_hat.cc" -#include "resources/peaks_lut_svf.hpp" -#include "braids/envelope.h" -#include "resources/braids_lut_env.hpp" +#include "lib/peaks/drums/high_hat.h" +#include "lib/braids/envelope.h" peaks::HighHat _oh; peaks::HighHat _ch; @@ -96,4 +95,8 @@ void engine::process() for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) engine::outputBuffer<0>()[i] += (float)buffer[i] / INT16_MAX * oh_ad; -} \ No newline at end of file +} + +#include "lib/peaks/drums/high_hat.cc" +#include "lib/peaks/resources.cc" +#include "lib/braids/resources.cc" \ No newline at end of file diff --git a/app/DRUMS/808ish-SD.bin b/app/DRUMS/808ish-SD.bin index 383bf61..d8fd96a 100644 Binary files a/app/DRUMS/808ish-SD.bin and b/app/DRUMS/808ish-SD.bin differ diff --git a/app/DRUMS/808ish-SD.cpp b/app/DRUMS/808ish-SD.cpp index 902b345..fe5c9c2 100644 --- a/app/DRUMS/808ish-SD.cpp +++ b/app/DRUMS/808ish-SD.cpp @@ -23,11 +23,10 @@ // See http://creativecommons.org/licenses/MIT/ for more information. // +// build_flags: -fno-inline -mfloat-abi=hard -mfpu=fpv5-d16 -ffast-math + #include "../squares-and-circles-api.h" -#include "peaks/drums/snare_drum.h" -#include "peaks/drums/snare_drum.cc" -#include "stmlib/utils/random.cc" -#include "resources/peaks_lut_svf.hpp" +#include "lib/peaks/drums/snare_drum.h" peaks::SnareDrum _processor; @@ -72,4 +71,8 @@ void engine::process() } _processor.Process(flags, engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE); -} \ No newline at end of file +} + +#include "lib/peaks/drums/snare_drum.cc" +#include "lib/stmlib/utils/random.cc" +#include "lib/peaks/resources.cc" diff --git a/app/DRUMS/Djembe.bin b/app/DRUMS/Djembe.bin index df3e3c5..fce4de5 100644 Binary files a/app/DRUMS/Djembe.bin and b/app/DRUMS/Djembe.bin differ diff --git a/app/DRUMS/FM-Drum.bin b/app/DRUMS/FM-Drum.bin index c747b5d..8b1b78c 100644 Binary files a/app/DRUMS/FM-Drum.bin and b/app/DRUMS/FM-Drum.bin differ diff --git a/app/DRUMS/FM-Drum.cpp b/app/DRUMS/FM-Drum.cpp index b1a2288..93a640c 100644 --- a/app/DRUMS/FM-Drum.cpp +++ b/app/DRUMS/FM-Drum.cpp @@ -24,11 +24,10 @@ // #include "../squares-and-circles-api.h" -#include "peaks/drums/fm_drum.h" -#include "peaks/drums/fm_drum.cc" -#include "resources/peaks_lut_osc.hpp" -#include "resources/peaks_lut_env.hpp" -#include "stmlib/utils/random.cc" +#include "lib/peaks/drums/fm_drum.h" +#include "lib/peaks/drums/fm_drum.cc" +#include "lib/peaks/resources.cc" +#include "lib/stmlib/utils/random.cc" static peaks::FmDrum _processor; diff --git a/app/DRUMS/TR707.bin b/app/DRUMS/TR707.bin index e493825..e3878fd 100644 Binary files a/app/DRUMS/TR707.bin and b/app/DRUMS/TR707.bin differ diff --git a/app/DRUMS/TR909-HiHat.bin b/app/DRUMS/TR909-HiHat.bin index 9810530..5b1df88 100644 Binary files a/app/DRUMS/TR909-HiHat.bin and b/app/DRUMS/TR909-HiHat.bin differ diff --git a/app/DRUMS/TR909-Ride.bin b/app/DRUMS/TR909-Ride.bin index 2f6c03f..4074f2b 100644 Binary files a/app/DRUMS/TR909-Ride.bin and b/app/DRUMS/TR909-Ride.bin differ diff --git a/app/FX/Delay.bin b/app/FX/Delay.bin index e75b100..8f87b36 100644 Binary files a/app/FX/Delay.bin and b/app/FX/Delay.bin differ diff --git a/app/FX/Gated-Reverb.bin b/app/FX/Gated-Reverb.bin index b1acd91..8953a68 100644 Binary files a/app/FX/Gated-Reverb.bin and b/app/FX/Gated-Reverb.bin differ diff --git a/app/FX/JU60_chorus.bin b/app/FX/JU60_chorus.bin index 8871caa..c08ce8c 100644 Binary files a/app/FX/JU60_chorus.bin and b/app/FX/JU60_chorus.bin differ diff --git a/app/FX/Rev-Dattorro.bin b/app/FX/Rev-Dattorro.bin index d88ba96..65ceb21 100644 Binary files a/app/FX/Rev-Dattorro.bin and b/app/FX/Rev-Dattorro.bin differ diff --git a/app/FX/Reverb-HP-LP.bin b/app/FX/Reverb-HP-LP.bin index d25e2c1..618243c 100644 Binary files a/app/FX/Reverb-HP-LP.bin and b/app/FX/Reverb-HP-LP.bin differ diff --git a/app/FX/Reverb.bin b/app/FX/Reverb.bin index 597bbb5..1615135 100644 Binary files a/app/FX/Reverb.bin and b/app/FX/Reverb.bin differ diff --git a/app/FX/ReverbSC.bin b/app/FX/ReverbSC.bin index ab477dc..e451b25 100644 Binary files a/app/FX/ReverbSC.bin and b/app/FX/ReverbSC.bin differ diff --git a/app/GND/FFT.bin b/app/GND/FFT.bin index 753c111..611ed7b 100644 Binary files a/app/GND/FFT.bin and b/app/GND/FFT.bin differ diff --git a/app/GND/Scope.bin b/app/GND/Scope.bin index e93f583..76e1ba3 100644 Binary files a/app/GND/Scope.bin and b/app/GND/Scope.bin differ diff --git a/app/M-OSC/Waveforms.bin b/app/M-OSC/Waveforms.bin index f4d5fc4..e520ae2 100644 Binary files a/app/M-OSC/Waveforms.bin and b/app/M-OSC/Waveforms.bin differ diff --git a/app/MIDI/Clock.bin b/app/MIDI/Clock.bin index 6029d3f..6aa3b62 100644 Binary files a/app/MIDI/Clock.bin and b/app/MIDI/Clock.bin differ diff --git a/app/MIDI/Monitor.bin b/app/MIDI/Monitor.bin index 058073b..1191b7e 100644 Binary files a/app/MIDI/Monitor.bin and b/app/MIDI/Monitor.bin differ diff --git a/app/MIDI/VAx6.bin b/app/MIDI/VAx6.bin index 32ab387..361ca02 100644 Binary files a/app/MIDI/VAx6.bin and b/app/MIDI/VAx6.bin differ diff --git a/app/NOISE/808_squares.bin b/app/NOISE/808_squares.bin index f644671..c332bf4 100644 Binary files a/app/NOISE/808_squares.bin and b/app/NOISE/808_squares.bin differ diff --git a/app/NOISE/NES.bin b/app/NOISE/NES.bin index bfd9961..571ae36 100644 Binary files a/app/NOISE/NES.bin and b/app/NOISE/NES.bin differ diff --git a/app/NOISE/WhitePink.bin b/app/NOISE/WhitePink.bin index 32bad21..ba8ecf2 100644 Binary files a/app/NOISE/WhitePink.bin and b/app/NOISE/WhitePink.bin differ diff --git a/app/SEQ/EuclidArp.bin b/app/SEQ/EuclidArp.bin index 05f1b2a..b53bdee 100644 Binary files a/app/SEQ/EuclidArp.bin and b/app/SEQ/EuclidArp.bin differ diff --git a/app/SEQ/EuclidArp.cpp b/app/SEQ/EuclidArp.cpp index 77ffba2..53a8776 100644 --- a/app/SEQ/EuclidArp.cpp +++ b/app/SEQ/EuclidArp.cpp @@ -25,20 +25,20 @@ // #include "../squares-and-circles-api.h" -#include "../lib/misc/euclidean.h" +#include "lib/misc/euclidean.h" #include "patterns_303.h" #include #include -#include "../lib/plaits/dsp/engine2/arpeggiator.h" +#include "lib/plaits/dsp/engine2/arpeggiator.h" #define private public #define SemitonesToRatioFast -#include "../lib/plaits/dsp/chords/chord_bank.cc" -#include "stmlib/utils/random.cc" +#include "lib/plaits/dsp/chords/chord_bank.cc" +#include "lib/stmlib/utils/random.cc" -#include "../lib/stmlib/utils/dsp.h" -#include "../DRUMS/resources/peaks_lut_env.hpp" +#include "lib/stmlib/utils/dsp.h" +#include "lib/peaks/resources.cc" // This app is copiled with soft-fpu - for running on teensy3.2 & teensy 4.x diff --git a/app/SEQ/EuclidRythm.bin b/app/SEQ/EuclidRythm.bin index a7e418d..f81438b 100644 Binary files a/app/SEQ/EuclidRythm.bin and b/app/SEQ/EuclidRythm.bin differ diff --git a/app/SEQ/TuringMachine.bin b/app/SEQ/TuringMachine.bin index b47aec7..864cf92 100644 Binary files a/app/SEQ/TuringMachine.bin and b/app/SEQ/TuringMachine.bin differ diff --git a/app/SPEECH/LPC.bin b/app/SPEECH/LPC.bin index 47420e6..c3f8ba5 100644 Binary files a/app/SPEECH/LPC.bin and b/app/SPEECH/LPC.bin differ diff --git a/app/SPEECH/SAM.bin b/app/SPEECH/SAM.bin index c70e833..b9835fb 100644 Binary files a/app/SPEECH/SAM.bin and b/app/SPEECH/SAM.bin differ diff --git a/app/SYNTH/DxFM.bin b/app/SYNTH/DxFM.bin index 084fd15..86da76f 100644 Binary files a/app/SYNTH/DxFM.bin and b/app/SYNTH/DxFM.bin differ diff --git a/app/SYNTH/DxFM.cpp b/app/SYNTH/DxFM.cpp index 7241b41..66b8a4e 100644 --- a/app/SYNTH/DxFM.cpp +++ b/app/SYNTH/DxFM.cpp @@ -17,9 +17,6 @@ // ENGINE_NAME:SYNTH/DxFM;SYNTH/DxFM_BNK1-3 -#undef FLASHMEM -#define FLASHMEM - #include "../squares-and-circles-api.h" #include "stmlib/utils/ring_buffer.h" #include "misc/dspinst.h" @@ -39,6 +36,7 @@ #include #include +#include "plaits/resources.h" struct dxfm { @@ -195,11 +193,11 @@ void engine::setup() if (!strcmp(engine::name(), "SYNTH/DxFM_BNK1-3")) { - if (fm_patches_table[nprogs / 32] = machine::fs_read("DXFMSYXA")) + if (fm_patches_table[nprogs / 32] = plaits::fm_patches_table[0]) nprogs += 32; - if (fm_patches_table[nprogs / 32] = machine::fs_read("DXFMSYXB")) + if (fm_patches_table[nprogs / 32] = plaits::fm_patches_table[1]) nprogs += 32; - if (fm_patches_table[nprogs / 32] = machine::fs_read("DXFMSYXC")) + if (fm_patches_table[nprogs / 32] = plaits::fm_patches_table[2]) nprogs += 32; } else @@ -396,4 +394,5 @@ void engine::draw() #include "msfa/patch.cc" #include "msfa/porta.cc" #include "msfa/env.cc" -#include "msfa/exp2.cc" \ No newline at end of file +#include "msfa/exp2.cc" +#include "plaits/resources.cc" \ No newline at end of file diff --git a/app/SYNTH/Open303.bin b/app/SYNTH/Open303.bin index 715d383..177437f 100644 Binary files a/app/SYNTH/Open303.bin and b/app/SYNTH/Open303.bin differ diff --git a/app/SYNTH/Resonator.bin b/app/SYNTH/Resonator.bin index 79f83dc..6ba59a9 100644 Binary files a/app/SYNTH/Resonator.bin and b/app/SYNTH/Resonator.bin differ diff --git a/app/SYNTH/plaits.bin b/app/SYNTH/plaits.bin new file mode 100644 index 0000000..f89fd3f Binary files /dev/null and b/app/SYNTH/plaits.bin differ diff --git a/app/SYNTH/plaits.cpp b/app/SYNTH/plaits.cpp new file mode 100644 index 0000000..c7c72a1 --- /dev/null +++ b/app/SYNTH/plaits.cpp @@ -0,0 +1,488 @@ +// Copyright (C)2022 - E.Heidt +// +// Author: Eduard Heidt (eh2k@gmx.de) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +// ENGINE_NAME: M-OSC/Virt.Analog +// ENGINE_NAME: M-OSC/Waveshaping +// ENGINE_NAME: M-OSC/2-OP-FM +// ENGINE_NAME: M-OSC/Formant/PD +// ENGINE_NAME: M-OSC/Harmonic +// ENGINE_NAME: M-OSC/Wavetable +// ENGINE_NAME: M-OSC/Chord +// ENGINE_NAME: DRUMS/Analog BD +// ENGINE_NAME: DRUMS/Analog SD +// ENGINE_NAME: DRUMS/Analog HH2 +// ENGINE_NAME: DRUMS/Analog HH +// ENGINE_NAME: DRUMS/909ish-BD +// ENGINE_NAME: DRUMS/909ish-SD +// ENGINE_NAME: SYNTH/ClassicVAVCF + +#include "../squares-and-circles-api.h" + +#include "stmlib/stmlib.h" +#define private public // ;-) +#include "plaits/dsp/voice.h" +#include "stmlib/dsp/dsp.h" + +using namespace machine; + +plaits::Modulations modulations; +plaits::Voice voice; +plaits::Patch patch; + +float bufferOut[FRAME_BUFFER_SIZE]; +float bufferAux[FRAME_BUFFER_SIZE]; +float out_aux_mix = 0.5f; +float _pitch = 0; +float _base_pitch = DEFAULT_NOTE; + +struct +{ + int engine; + int output; // output=0 -> out, output=1 -> aux, output=3 -> stereo +} _mode = {}; + +uint8_t *_buffer = nullptr; +plaits::Engine *_plaitsEngine = nullptr; + +constexpr int WAVETABLE_ENGINE = 5; +constexpr int CHORD_ENGINE = 6; +constexpr int CLASSIC_VAVCF_ENGINE = 16; + +void engine_free() +{ + free(_plaitsEngine); + free(_buffer); +} + +template +void alloc_engine(size_t mem = 48) +{ + _plaitsEngine = new (malloc(sizeof(T))) T(); + _buffer = (uint8_t *)malloc(mem * sizeof(float)); + + stmlib::BufferAllocator allocator; + allocator.Init(_buffer, mem * sizeof(float)); + _plaitsEngine->Init(&allocator); +} + +float harmonics, timbre, morph; + +bool is_drum() +{ + return _mode.engine == 13 || _mode.engine == 14 || _mode.engine == 15; +} + +void init_params(float hh, float tt, float mm, const plaits::PostProcessingSettings &settings) +{ + patch.harmonics = harmonics = hh; + patch.timbre = timbre = tt; + patch.morph = morph = mm; + if (_plaitsEngine) + _plaitsEngine->post_processing_settings = settings; +} + +void engine::setup() +{ + const char *name = engine::name(); + + while (*name++ != '/') + ; + + if (!strcmp(name, "Virt.Analog")) + _mode = {0, 0}; + else if (!strcmp(name, "Waveshaping")) + _mode = {1, 0}; + else if (!strcmp(name, "2-OP-FM")) + _mode = {2, 0}; + else if (!strcmp(name, "Formant/PD")) + _mode = {3, 2}; + else if (!strcmp(name, "Harmonic")) + _mode = {4, 2}; + else if (!strcmp(name, "Wavetable")) + _mode = {5, 2}; + else if (!strcmp(name, "Chord")) + _mode = {6, 0}; + else if (!strcmp(name, "Analog BD")) + _mode = {13, 0}; + else if (!strcmp(name, "Analog SD")) + _mode = {14, 0}; + else if (!strcmp(name, "Analog HH2")) + _mode = {15, 1}; + else if (!strcmp(name, "Analog HH")) + _mode = {15, 0}; + else if (!strcmp(name, "909ish-BD")) + _mode = {13, 1}; + else if (!strcmp(name, "909ish-SD")) + _mode = {14, 1}; + else if (!strcmp(name, "ClassicVAVCF")) + _mode = {16, 2}; + else + _mode = {0, 0}; + + voice.Init(); + patch.engine = 0; + memset(&patch, 0, sizeof(patch)); + patch.note = DEFAULT_NOTE + _pitch * 12.f; + + modulations.timbre_patched = true; + patch.timbre_modulation_amount = 0; + + modulations.frequency_patched = true; + patch.frequency_modulation_amount = 0; + + modulations.morph_patched = true; + patch.morph_modulation_amount = 0; + + memset(&modulations, 0, sizeof(modulations)); + + patch.lpg_colour = 0.5; + patch.decay = 0.5; + modulations.trigger_patched = true; // trigger; + // modulations.level_patched = true; + // modulations.level = 1; + + switch (_mode.engine) + { + case 0: + alloc_engine(); + init_params(0.5f, 0.5f, 0.5f, {0.8f, 0.8f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Detune", &harmonics); + engine::addParam("Square", &timbre); + engine::addParam("CSAW", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + break; + case 1: + alloc_engine(); + init_params(0.8f, 0.8f, 0.75f, {0.7f, 0.6f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Waveform", &harmonics); + engine::addParam("Fold", &timbre); + engine::addParam("Asym", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + break; + case 2: + alloc_engine(); + init_params(0.8f, 0.8f, 0.75f, {0.6f, 0.6f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Ratio", &harmonics); + engine::addParam("Mod", &timbre); + engine::addParam("Feedb.", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + break; + case 3: + alloc_engine(); + init_params(0.8f, 0.8f, 0.75f, {0.7f, 0.6f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Ratio", &harmonics); + engine::addParam("Frm/Fq.", &timbre); + engine::addParam("Width", &morph); + engine::addParam("Decay", &patch.decay); + engine::addParam("PD-Mix", &out_aux_mix, out_aux_mix); + break; + case 4: + alloc_engine(); + init_params(0.8f, 0.8f, 0.75f, {0.8f, 0.8f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Bump", &harmonics); + engine::addParam("Peak", &timbre); + engine::addParam("Shape", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + break; + case WAVETABLE_ENGINE: + alloc_engine(64 * sizeof(const int16_t *)); + init_params(0.f, 0.8f, 0.75f, {0.6f, 0.6f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Bank", &harmonics, 0.f, 0.5f); + engine::addParam("Row", &timbre); + engine::addParam("Column", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + _plaitsEngine->LoadUserData(nullptr); + break; + case CHORD_ENGINE: + { + alloc_engine(plaits::kChordNumChords * plaits::kChordNumNotes + plaits::kChordNumChords + plaits::kChordNumNotes); + init_params(0.5f, 0.5f, 0.5f, {0.8f, 0.8f, false}); + engine::addParam(V_OCT, &_pitch); + + int32_t *pchord = (int32_t *)&static_cast(_plaitsEngine)->chords_.chord_index_quantizer_.quantized_value_; + *pchord = 8; + engine::addParam("Chord", pchord, 0, + static_cast(_plaitsEngine)->chords_.chord_index_quantizer_.num_steps() - 1, + (const char **)plaits::chord_names); + + engine::addParam("Inv.", &timbre); + engine::addParam("Shape", &morph); + engine::addParam("Decay", &patch.decay); + if (_mode.output == 2) + engine::addParam("AuxMix", &out_aux_mix, out_aux_mix); + else + engine::addParam("Color", &patch.lpg_colour); + } + break; + // case 15: // speech_engine_ + // alloc_engine(false, 0.8f, 0.8f); + // break; + // case 8: // swarm_engine_ + // alloc_engine(false, -3.0f, 1.0f); + // break; + // case 9: // noise_engine_ + // alloc_engine(false, -1.0f, -1.0f); + // break; + // case 10: // particle_engine_ + // alloc_engine(false, -2.0f, 1.0f); + // break; + // case 11: // string_engine_ + // alloc_engine(true, -1.0f, 0.8f); + // break; + // case 12: // modal_engine_ + // alloc_engine(true, -0.5f, 0.8f); + // break; + case 13: + _base_pitch += -24.f; + alloc_engine(); + init_params(0.8f, 0.5f, 0.5f, {0.8f, 0.8f, true}); + engine::addParam("Pitch", &_pitch, -1.f, 1.f); + engine::addParam(_mode.output == 0 ? "Drive" : "Punch", &harmonics); + engine::addParam("Tone", &timbre); + engine::addParam("Decay", &morph); + break; + case 14: + alloc_engine(); + init_params(0.5f, 0.5f, 0.5f, {0.8f, 0.8f, true}); + engine::addParam("Pitch", &_pitch, -1.f, 1.f); + engine::addParam("Snappy", &harmonics); + engine::addParam("Tone", &timbre); + engine::addParam("Decay", &morph); + break; + case 15: + alloc_engine(); + init_params(0.5f, 0.9f, 0.6f, {0.8f, 0.8f, true}); + engine::addParam("Pitch", &_pitch, -1.f, 1.f); + engine::addParam("Noise", &harmonics); + engine::addParam("Tone", &timbre); + engine::addParam("Decay", &morph); + break; + // engines 2 + case CLASSIC_VAVCF_ENGINE: + alloc_engine(); + init_params(0.5f, 0.5f, 0.5f, {1.f, 1.f, false}); + engine::addParam(V_OCT, &_pitch); + engine::addParam("Morph", &morph); + engine::addParam("Cutoff", &timbre); + engine::addParam("Harsh", &harmonics); + out_aux_mix = 0; + modulations.timbre_patched = false; + patch.timbre_modulation_amount = 0; + engine::addParam("EnvMod", &patch.timbre_modulation_amount, -1.f, 1.f); + patch.decay = 0.5f; + engine::addParam("Decay", &patch.decay, 0.f, 0.99f); + break; +#if 0 //TODO.... + case 17: + alloc_engine(plaits::kMaxBlockSize * 4); + _plaitsEngine->post_processing_settings = {0.7f, 0.7f, false}; + break; + case 18: + case 19: + case 20: + alloc_engine( + plaits::kMaxBlockSize * 4 + plaits::kMaxBlockSize * plaits::kNumSixOpVoices + sizeof(plaits::fm::Patch) * 96 / sizeof(float)); + init_params("", 0.0f, "Mod", 0.5f, "Env", 0.5f, {1.f, 1.f, false}); + param[1].init_presets("Preset", &static_cast(_plaitsEngine)->patch_index, 0, 0, 95); + param[1].print_value = [&](char *name) + { + auto i = static_cast(_plaitsEngine)->patch_index; + sprintf(name, ">%.10s", static_cast(_plaitsEngine)->patches_[i].name); + }; + _plaitsEngine->LoadUserData(plaits::fm_patches_table[0]); + modulations.morph_patched = false; + param[5].init("EnvMod", &patch.morph_modulation_amount, 0.0f, -1.f, 1.f); + + modulations.timbre_patched = false; + param[4].init("ModMod", &patch.timbre_modulation_amount, 0.0f, -1.f, 1.f); + break; + case 21: + alloc_engine(plaits::kMaxBlockSize * 4); + _plaitsEngine->post_processing_settings = {0.7f, 0.7f, false}; + patch.engine = (engine - 16); + break; + case 22: + alloc_engine(16 + 3 * (1024 + 265)); + _plaitsEngine->post_processing_settings = {0.8f, 0.8f, false}; + patch.engine = (engine - 16); + break; + case 23: + alloc_engine(plaits::kChordNumChords * plaits::kChordNumNotes + plaits::kChordNumChords + plaits::kChordNumNotes); + _plaitsEngine->post_processing_settings = {0.5f, 0.5f, false}; + patch.engine = (engine - 16); + break; +#endif + } + + if (_mode.engine >= 16) + patch.engine = (_mode.engine - 16); + + _plaitsEngine->Reset(); +} + +void engine::process() +{ + float a = bufferOut[0] / 256.f; + ONE_POLE(patch.harmonics, harmonics + a, 0.1f); + ONE_POLE(patch.timbre, timbre + a, 0.1f); + ONE_POLE(patch.morph, morph + a, 0.1f); + + modulations.level_patched = false; + modulations.level = 1.f; + + patch.note = _base_pitch + engine::cv() * 12; + + float last_decay = patch.decay; + float last_morph = patch.morph; + // if (!frame.trigger && frame.gate) + // { + // if (is_drum()) + // patch.morph = 1; + // else + // patch.decay = 1; + + // modulations.level = 1.f; + // // modulations.level_patched = true; + // } + modulations.engine = patch.engine; + modulations.trigger = engine::trig() ? 1 : 0; + + if (!is_drum()) + modulations.trigger_patched = patch.decay < 1.f; + + if (!__io->tr) + { + modulations.trigger_patched = false; + modulations.level_patched = true; + modulations.level = patch.decay; + patch.decay = 0.001f; + } + else + { + modulations.trigger_patched = true; + } + + modulations.note = 0; + voice.Render(_plaitsEngine, patch, modulations, bufferOut, bufferAux, FRAME_BUFFER_SIZE); + + patch.decay = last_decay; + patch.morph = last_morph; + + switch (_mode.output) + { + case 0: + std::copy_n(bufferOut, FRAME_BUFFER_SIZE, engine::outputBuffer<0>()); + std::copy_n(bufferOut, FRAME_BUFFER_SIZE, engine::outputBuffer<1>()); + break; + case 1: + std::copy_n(bufferAux, FRAME_BUFFER_SIZE, engine::outputBuffer<0>()); + std::copy_n(bufferAux, FRAME_BUFFER_SIZE, engine::outputBuffer<1>()); + break; + case 2: + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + bufferOut[i] = stmlib::Crossfade(bufferOut[i], bufferAux[i], out_aux_mix); + std::copy_n(bufferOut, FRAME_BUFFER_SIZE, engine::outputBuffer<0>()); + std::copy_n(bufferOut, FRAME_BUFFER_SIZE, engine::outputBuffer<1>()); + break; + case 3: + std::copy_n(bufferOut, FRAME_BUFFER_SIZE, engine::outputBuffer<0>()); + std::copy_n(bufferAux, FRAME_BUFFER_SIZE, engine::outputBuffer<1>()); + break; + } +} + +void engine::draw() +{ + engine::setParamName(&patch.decay, __io->tr ? "Decay" : "Level"); +} + +#include "stmlib/utils/random.cc" +#include "lib/stmlib/dsp/units.cc" + +//${SCRIPT_PATH}/main.cc $(find lib/plaits/ -type f -name "*.cc") + +#include "lib/plaits/resources.cc" +// lib/plaits/dsp/speech/sam_speech_synth.cc +// lib/plaits/dsp/speech/lpc_speech_synth_controller.cc +// lib/plaits/dsp/speech/lpc_speech_synth_words.cc +// lib/plaits/dsp/speech/lpc_speech_synth_phonemes.cc +// lib/plaits/dsp/speech/naive_speech_synth.cc +// lib/plaits/dsp/speech/lpc_speech_synth.cc +#include "lib/plaits/dsp/engine/string_engine.cc" +#include "lib/plaits/dsp/engine/swarm_engine.cc" +#include "lib/plaits/dsp/engine/chord_engine.cc" +#include "lib/plaits/dsp/engine/waveshaping_engine.cc" +#include "lib/plaits/dsp/engine/modal_engine.cc" +#include "lib/plaits/dsp/engine/fm_engine.cc" +#include "lib/plaits/dsp/engine/snare_drum_engine.cc" +// #include "lib/plaits/dsp/engine/speech_engine.cc" +#include "lib/plaits/dsp/engine/grain_engine.cc" +#include "lib/plaits/dsp/engine/virtual_analog_engine.cc" +#include "lib/plaits/dsp/engine/wavetable_engine.cc" +#include "lib/plaits/dsp/engine/additive_engine.cc" +#include "lib/plaits/dsp/engine/noise_engine.cc" +#include "lib/plaits/dsp/engine/hi_hat_engine.cc" +#include "lib/plaits/dsp/engine/particle_engine.cc" +#include "lib/plaits/dsp/engine/bass_drum_engine.cc" +// lib/plaits/dsp/engine2/chiptune_engine.cc +// lib/plaits/dsp/engine2/six_op_engine.cc +// lib/plaits/dsp/engine2/wave_terrain_engine.cc +// lib/plaits/dsp/engine2/string_machine_engine.cc +// lib/plaits/dsp/engine2/phase_distortion_engine.cc +#include "lib/plaits/dsp/engine2/virtual_analog_vcf_engine.cc" +#include "lib/plaits/dsp/chords/chord_bank.cc" +#include "lib/plaits/dsp/physical_modelling/string_voice.cc" +#include "lib/plaits/dsp/physical_modelling/string.cc" +#include "lib/plaits/dsp/physical_modelling/modal_voice.cc" +#include "lib/plaits/dsp/physical_modelling/resonator.cc" +#include "lib/plaits/dsp/fm/algorithms.cc" +#include "lib/plaits/dsp/fm/dx_units.cc" +#include "lib/plaits/dsp/voice.cc" diff --git a/app/build.sh b/app/build.sh index 130c6e7..3aba5a4 100755 --- a/app/build.sh +++ b/app/build.sh @@ -13,6 +13,7 @@ pip install jinja2 pyelftools elf_size_analyze --upgrade pip if [[ "$1" == "--rebuild" ]]; then find "${SCRIPT_PATH}/" -type f -name "*.bin" -print0 -exec touch {} + + rm -f ${SCRIPT_PATH}/apps.txt fi for f in $(find "${SCRIPT_PATH}" -mindepth 2 -maxdepth 2 -type f -name '*.cpp'); do @@ -23,27 +24,29 @@ if [ -f $oo ] && [ "$(date -R -r $X.bin)" = "$(date -R -r $f)" ]; then fi #-fno-rtti -NAME=$(grep "ENGINE_NAME:" $f | cut -d':' -f2) +NAME="$(grep "ENGINE_NAME:" $f | cut -d':' -f2 | sed 's/^ *//g')" +NAME=${NAME//$'\n'/';'} #replace \n with '' NAME=${NAME:-"$(realpath --relative-to=${SCRIPT_PATH} $X)"} echo ----- "$NAME" ----- mkmodule=$(ls lib/udynlink/scripts/mkmodule | head -n1) -BUILD_FLAGS=$(grep "build_flags:" $X.cpp | cut -d':' -f2-) +BUILD_FLAGS=$(grep "build_flags:" $X.cpp | cut -d':' -f2- | xargs) BUILD_FLAGS=${BUILD_FLAGS:-"-mfloat-abi=hard -mfpu=fpv5-d16 -ffast-math"} -echo "BUILD_FLAGS:$BUILD_FLAGS" -CPP_FILES=$(grep "cpp_files:" $X.cpp | cut -d':' -f2-) +echo "BUILD_FLAGS:$BUILD_FLAGS" +SRC_FILES=$(grep "src_files" $X.cpp | cut -d':' -f2 | xargs) +find "$(dirname $X.cpp)" -type f -name '*.o' -delete #--no-opt \ #-felide-constructors -fno-rtti -std=gnu++14 -Wno-error=narrowing -fno-threadsafe-statics -$mkmodule $(realpath $X.cpp --relative-base=.) $CPP_FILES \ +$mkmodule $(realpath $X.cpp --relative-base=.) \ --no-opt \ - --build_flags="-fsingle-precision-constant -DFLASHMEM='__attribute__((section(\".text.flashmem\")))' -DNDEBUG -pedantic -fno-exceptions $BUILD_FLAGS -I. -I./lib/ " \ + --build_flags="-fsingle-precision-constant -DNDEBUG -pedantic -fno-exceptions $BUILD_FLAGS -I. -I./lib/ " \ --public-symbols="setup,process,draw,screensaver,__ui_event_handler,__midi_event_handler" \ - --name="$NAME" > $X.log + --name="$NAME" $SRC_FILES> $X.log sed -i "s|$(realpath .)|.|" $X.log touch -d "$(date -R -r $X.cpp)" $X.bin @@ -52,13 +55,15 @@ touch -d "$(date -R -r $X.cpp)" $X.bin arm-none-eabi-objdump -Dztr --source $X.elf | arm-none-eabi-c++filt -t > $X.elf.txt #arm-none-eabi-nm -l -t d -S -C --size-sort --synthetic --special-syms --with-symbol-versions --reverse-sort ./$X.elf > $X.log which elf-size-analyze >/dev/null && elf-size-analyze -t arm-none-eabi- $(realpath $X.elf --relative-base=.) -F -R --no-color >> $X.log -md5sum $(realpath $X.bin --relative-base=.) | tee -a $X.log -echo "BIN_SIZE $(stat -c %s -- $X.bin)" | tee -a $X.log +${SCRIPT_PATH}/dump.py "$(realpath $X.bin --relative-base=.)" | tee -a $X.log #rm $X.elf +if [[ "$1" == "--rebuild" ]]; then + ${SCRIPT_PATH}/dump.py "$(realpath $X.bin --relative-base=.)" >> ${SCRIPT_PATH}/apps.txt +fi + grep "__aeabi_" $X.log && exit 1 -${SCRIPT_PATH}/dump.py "$X.bin" #xxd -i $X.bin > ./$X.bin.h #sed -i "s/unsigned char/const uint8_t/g" ./$X.bin.h diff --git a/app/dump.py b/app/dump.py index bbe3659..731cab8 100755 --- a/app/dump.py +++ b/app/dump.py @@ -1,11 +1,16 @@ -#!/bin/python3 -u +#!/usr/bin/env python3 -import sys, zlib +import sys, zlib, hashlib + +def md5sum(data): + h = hashlib.md5() + h.update(data) + return h.hexdigest() f = open(sys.argv[1], "rb") data = f.read() f.close() -print(data[0:4]) # sign +#print(data[0:4]) # sign l = int.from_bytes(data[4:6], byteorder='little')#num_lot r = int.from_bytes(data[6:8], byteorder='little'); #num_rels a = int.from_bytes(data[8:12], byteorder='little'); #symt_size @@ -14,11 +19,12 @@ d = int.from_bytes(data[20:24], byteorder='little'); #bss_size h = 24 + (r * 8) + a +print("---------------------------------------------") print("FILE_NAME", f.name) print("RAM_SIZE", (l * 4) + c + d) print("BIN_SIZE", h + b + c) print("FILE_LEN", len(data)) - crc32sum = zlib.crc32(data[0:-1]) print("CRC32 %x" % crc32sum) +print("MD5 %s" % md5sum(data)) diff --git a/app/index.json b/app/index.json index 61a86fc..b72dea7 100644 --- a/app/index.json +++ b/app/index.json @@ -1,6 +1,9 @@ { "apps": [ - "CV/EnvGen_ADSR.bin", + "CV/V_OCT.bin", + "CV/EnvGen.bin", + "CV/LFO.bin", + "CV/EnvFollower.bin", "NOISE/WhitePink.bin", "NOISE/NES.bin", "NOISE/808_squares.bin", @@ -14,6 +17,7 @@ "DRUMS/TR909-HiHat.bin", "DRUMS/TR909-Ride.bin", "DRUMS/TR707.bin", + "DRUMS/Claps.bin", "M-OSC/Waveforms.bin", @@ -42,6 +46,8 @@ "FX/JU60_chorus.bin", "GND/Scope.bin", - "GND/FFT.bin" + "GND/FFT.bin", + + "SYNTH/plaits.bin" ] } \ No newline at end of file diff --git a/app/squares-and-circles-api.h b/app/squares-and-circles-api.h index 1d6a30b..de5dc07 100644 --- a/app/squares-and-circles-api.h +++ b/app/squares-and-circles-api.h @@ -51,6 +51,10 @@ constexpr uint32_t ENGINE_MODE_STEREOLIZED = 1 << 9; #define EXTERN_C extern "C" #endif +#ifndef FLASHMEM +#define FLASHMEM +#endif + #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #endif diff --git a/app/upload.py b/app/upload.py index a5b58d4..0f996b8 100755 --- a/app/upload.py +++ b/app/upload.py @@ -49,7 +49,7 @@ def sendFLASHDATA(name, data0): flush(midiin) data = bytes(name, "utf-8")[:8] + data0 crc32 = zlib.crc32(data) - print(" Flashing", name, crc32) + print(" Flashing", name, crc32, end="") midiout.send_message( [0xF3, 0x7E] ) # midi_out.send(mido.Message('song_select', song=0x7e)) @@ -64,10 +64,10 @@ def sendFLASHDATA(name, data0): msg = midiin.get_message() if msg: ack, t = msg - print(" ACK:", ack) + print(" ACK:", ack, end="") break - print(" sending blob...", len(data)) + print(" sending blob...", len(data), end="") i = 0 time.sleep(1 / 10000) while i < len(data) - 1: @@ -115,24 +115,30 @@ def sendFLASHDATA(name, data0): print(json.dumps(engines, indent=4)) # exit(0) +# del engines[len(engines)-1:] +midiout.send_message([0xF3, ord("U")]) # reset + def get_appid(binfile): with open(binfile, "rb") as f: data = f.read() - l = int.from_bytes(data[4:6], byteorder="little") # num_lot - r = int.from_bytes(data[6:8], byteorder="little") # num_rels + l = int.from_bytes(data[4:6], byteorder="little") # num_lot + r = int.from_bytes(data[6:8], byteorder="little") # num_rels a = int.from_bytes(data[8:12], byteorder="little") # symt_size - b = int.from_bytes(data[12:16], byteorder="little") # code_size - c = int.from_bytes(data[16:20], byteorder="little") # data_size - d = int.from_bytes(data[20:24], byteorder="little") # bss_size + b = int.from_bytes(data[12:16], byteorder="little") # code_size + c = int.from_bytes(data[16:20], byteorder="little") # data_size + d = int.from_bytes(data[20:24], byteorder="little") # bss_size sym_off = int(int(24) + (r * 2 * 4)) name_off = ( int.from_bytes(data[sym_off + 4 : sym_off + 8], "little", signed=False) & 0x0FFFFFFF ) + sym_off - name = data[name_off : name_off + 24].decode("utf-8").split("\0")[0] + name = ( + data[name_off : data.index(0, name_off)].decode("utf-8").split("\0")[0] + ) return name + apps_json = os.path.dirname(__file__) + "/index.json" with open(apps_json) as f: @@ -143,41 +149,45 @@ def get_appid(binfile): if not os.path.exists(bin_file): continue app_id = get_appid(bin_file) # os.path.splitext(file)[0] - print("name:", app_id) bin_size = os.path.getsize(bin_file) with open(bin_file, "rb") as f: crc32sum = zlib.crc32(f.read()) - engine = next( - (e for e in engines if e["id"] == app_id), - None, - ) - - if engine != None and engine["crc32"] == "%x" % crc32sum: - print( - engine["addr"], - os.path.splitext(file)[0], - "%x" % crc32sum, - "OK!", - bin_size - int(engine["size"]), - ) - continue - print("->", file, engine) + engine = next( + (e for e in engines if e["id"] == app_id), + None, + ) if engine == None: offset = int(1024 * 1024 / 2) - if len(engines) > 0: - offset = max((int(e["addr"], 16) + int(e["size"])) for e in engines) - offset += 4096 - (offset % 4096) + for e in engines: + offset = int(e["addr"], 16) + int(e["size"]) + offset += 4096 - (offset % 4096) + print("OFFSET %x" % offset) engine = {} engine["id"] = app_id engine["addr"] = "%x" % offset engine["size"] = "%s" % bin_size - print("TODO - add new engine...", "0x%x" % offset, bin_file) + engine["crc32"] = "%x" % crc32sum engines.append(engine) - # continue - # exit(0) + print("NEW ->", file, engine) + continue + #exit(0) + elif engine["crc32"] == "%x" % crc32sum: + onext = int(engine["addr"], 16) + int(engine["size"]) + onext += 4096 - (onext % 4096) + print( + engine["addr"], engine["size"], + os.path.splitext(file)[0], + "%x" % crc32sum, + "OK!", + bin_size - int(engine["size"]), + "MEM-KB: %d" % ((onext - int(1024 * 1024 / 2)) / 1024) + ) + continue + + print("->", file, engine) print( os.path.splitext(file)[0], "%x" % crc32sum, bin_size - int(engine["size"]) diff --git a/doc/cv_ef.png b/doc/cv_ef.png new file mode 100644 index 0000000..37a9323 Binary files /dev/null and b/doc/cv_ef.png differ diff --git a/doc/engines.png b/doc/engines.png index 574f1c9..dd5e0c4 100644 Binary files a/doc/engines.png and b/doc/engines.png differ diff --git a/doc/seq_tm.png b/doc/seq_tm.png new file mode 100644 index 0000000..48f732f Binary files /dev/null and b/doc/seq_tm.png differ diff --git a/lib/drumsynth/drumsynth.cpp b/lib/drumsynth/drumsynth.cpp index 4272f0a..b45654a 100644 --- a/lib/drumsynth/drumsynth.cpp +++ b/lib/drumsynth/drumsynth.cpp @@ -33,7 +33,9 @@ #include "misc/Biquad.h" #include "drumsynth.h" +#ifndef SAMPLE_RATE constexpr float SAMPLE_RATE = 48000.f; +#endif inline float dB2amp(float dB) { diff --git a/lib/drumsynth/drumsynth.h b/lib/drumsynth/drumsynth.h index 80c0a19..7708079 100644 --- a/lib/drumsynth/drumsynth.h +++ b/lib/drumsynth/drumsynth.h @@ -23,6 +23,8 @@ // See http://creativecommons.org/licenses/MIT/ for more information. // +#pragma once + #include #include #include diff --git a/lib/misc/noise.hxx b/lib/misc/noise.hxx index 072ed25..140c22b 100644 --- a/lib/misc/noise.hxx +++ b/lib/misc/noise.hxx @@ -24,6 +24,7 @@ // See http://creativecommons.org/licenses/MIT/ for more information. // +#pragma once #include // 31-bit Park-Miller-Carta Pseudo-Random Number Generator diff --git a/lib/plaits/resources.cc b/lib/plaits/resources.cc index a7a4c51..9566efa 100644 --- a/lib/plaits/resources.cc +++ b/lib/plaits/resources.cc @@ -33,7 +33,7 @@ #include "plaits/resources.h" #ifndef FLASHMEM -#include "pgmspace.h" +#define FLASHMEM #endif namespace plaits { @@ -4031,10 +4031,8 @@ const int16_t* const lookup_table_i16_table[] FLASHMEM = { lut_ws_double_bump, }; - - -const int32_t* const lookup_table_i32_table[] FLASHMEM = { -}; +// const int32_t* const lookup_table_i32_table[] FLASHMEM = { +// }; const int8_t lut_lpc_excitation_pulse[] FLASHMEM = { 0, 0, 0, 0, diff --git a/lib/streams/audio_cv_meter.h b/lib/streams/audio_cv_meter.h new file mode 100644 index 0000000..e4486bc --- /dev/null +++ b/lib/streams/audio_cv_meter.h @@ -0,0 +1,95 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Discriminate an ADC signal into audio or CV ; and provide RMS stats. + +#ifndef STREAMS_AUDIO_CV_METER_H_ +#define STREAMS_AUDIO_CV_METER_H_ + +#include "stmlib/stmlib.h" + +namespace streams { + +class AudioCvMeter { + public: + AudioCvMeter() { } + ~AudioCvMeter() { } + + void Init() { + peak_ = 0; + + zero_crossing_interval_ = 0; + average_zero_crossing_interval_ = 0; + + previous_sample_ = 0; + cv_ = false; + } + + void Process(int32_t sample) { + if ((sample >> 1) * previous_sample_ < 0 || + zero_crossing_interval_ >= 4096) { + int32_t error = zero_crossing_interval_ - average_zero_crossing_interval_; + average_zero_crossing_interval_ += error >> 3; + zero_crossing_interval_ = 0; + } else { + ++zero_crossing_interval_; + } + + if (cv_ && average_zero_crossing_interval_ < 200) { + cv_ = false; + } else if (!cv_ && average_zero_crossing_interval_ > 400) { + cv_ = true; + } + + previous_sample_ = sample; + + if (sample < 0) { + sample = -sample; + } + int32_t error = sample - peak_; + int32_t coefficient = 33; // 250ms at 1kHz + if (error > 0) { + coefficient = 809; // 10ms at 1kHz + } + peak_ += error * coefficient >> 15; + } + + inline bool cv() const { return cv_; } + inline int32_t peak() const { return peak_; } + + private: + bool cv_; + int32_t peak_; + int32_t zero_crossing_interval_; + int32_t average_zero_crossing_interval_; + int32_t previous_sample_; + + DISALLOW_COPY_AND_ASSIGN(AudioCvMeter); +}; + +} // namespace streams + +#endif // STREAMS_AUDIO_CV_METER_H_ diff --git a/lib/streams/compressor.cc b/lib/streams/compressor.cc new file mode 100644 index 0000000..0e3fc17 --- /dev/null +++ b/lib/streams/compressor.cc @@ -0,0 +1,158 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Compressor. + +#include "streams/compressor.h" + +// #include + +#include "stmlib/utils/dsp.h" + +namespace streams { + +using namespace stmlib; + +// 256 LSB <=> 1.55dB +const int32_t kGainConstant = 1 / (1.55 / 6.0 * 65536.0 / 256.0) * 65536; + +void Compressor::Init() { + detector_ = 0; +} + +/* static */ +int32_t Compressor::Log2(int32_t value) { + if (value <= 0) { + value = 1; + } + int32_t log_value = 0; + while (value >= 512) { + value >>= 1; + log_value += 65536; + } + while (value < 256) { + value <<= 1; + log_value -= 65536; + } + // Value is between 256 and 512, we can use the LUT. + return log_value + lut_log2[value - 256]; +} + +/* static */ +int32_t Compressor::Exp2(int32_t value) { + int32_t num_shifts = 0; + while (value >= 65536) { + ++num_shifts; + value -= 65536; + } + while (value < 0) { + --num_shifts; + value += 65536; + } + + // Value is between 0 and 65535, we can use the LUT. + int32_t a = lut_exp2[value >> 8]; + int32_t b = lut_exp2[(value >> 8) + 1]; + int32_t mantissa = a + ((b - a) * (value & 0xff) >> 8); + return num_shifts >= 0 ? mantissa << num_shifts : mantissa >> -num_shifts; +} + +/* static */ +int32_t Compressor::Compress( + int32_t squared_level, + int32_t threshold, + int32_t ratio, + bool soft_knee) { + int32_t level = (Log2(squared_level) >> 1) - 15 * 65536; // 15-bit peak + int32_t position = level - threshold; + + if (position < 0) { + return 0; + } + + int32_t attenuation = position - (position * ratio >> 8); + if (attenuation < 65535 && soft_knee) { + int32_t a = lut_soft_knee[attenuation >> 8]; + int32_t b = lut_soft_knee[(attenuation >> 8) + 1]; + int32_t soft_knee = a + ((b - a) * (attenuation & 0xff) >> 8); + attenuation += \ + (soft_knee - attenuation) * ((65535 - attenuation) >> 1) >> 15; + } + return -attenuation; +} + +void Compressor::Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + int32_t energy; + int64_t error; + + // Detect the RMS level on the EXCITE input. + energy = excite; + energy *= energy; + error = energy - sidechain_signal_detector_; + if (error > 0) { + sidechain_signal_detector_ += error; + } else { + // Decay time: 5s. + sidechain_signal_detector_ += error * 14174 >> 31; + } + + // If there is no signal on the "excite" input, disable sidechain and + // compress by metering input. + if (sidechain_signal_detector_ < (1024 * 1024)) { + energy = audio; + energy *= energy; + } + + // Detect the RMS level on the EXCITE or AUDIO input - whichever active. + error = energy - detector_; + if (error > 0) { + if (attack_coefficient_ == -1) { + detector_ += error; + } else { + detector_ += error * attack_coefficient_ >> 31; + } + } else { + detector_ += error * decay_coefficient_ >> 31; + } + + int32_t g = Compress(detector_, threshold_, ratio_, soft_knee_); + gain_reduction_ = g >> 3; + g = kUnityGain + ((g + makeup_gain_) * kGainConstant >> 16); + if (g > 65535) { + g = 65535; + } + + *gain = g; + // float ogain = powf(10.0f, 1.55f / 20.0f * (g - kUnityGain) / 256.0f); + // printf("%f %f\n", gain_reduction_ / 32768.0 * 24, 20 * logf(ogain) / logf(10.0f)); + *frequency = 65535; +} + +} // namespace streams diff --git a/lib/streams/compressor.h b/lib/streams/compressor.h new file mode 100644 index 0000000..5fd1702 --- /dev/null +++ b/lib/streams/compressor.h @@ -0,0 +1,133 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Compressor. + +#ifndef STREAMS_COMPRESSOR_H_ +#define STREAMS_COMPRESSOR_H_ + +#include "stmlib/stmlib.h" + +#include + +#include "streams/gain.h" +#include "streams/resources.h" + +namespace streams { + +class Compressor { + public: + Compressor() { } + ~Compressor() { } + + void Init(); + + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency); + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + uint16_t attack_time; + uint16_t decay_time; + uint16_t amount; + uint16_t threshold; + + if (globals) { + attack_time = globals[0] * (128 + 128 + 99) >> 16; // 1ms to 500ms + decay_time = 128 + 99 + (globals[2] >> 8); // 50ms to 5000ms + threshold = globals[1]; + amount = globals[3]; + } else { + attack_time = !alternate ? 1 : 40; // 0.2ms or 2ms; + decay_time = !alternate ? 279 : 236; // 150ms or 70ms; + threshold = parameters[0]; + amount = parameters[1]; + } + + attack_coefficient_ = lut_lp_coefficients[attack_time]; + decay_coefficient_ = lut_lp_coefficients[decay_time]; + soft_knee_ = alternate; + threshold_ = (-1280 + 5 * (threshold >> 8)) << 8; + + if (amount < 32768) { + // Compression with no makeup gain. + ratio_ = lut_compressor_ratio[(32767 - amount) >> 7]; + makeup_gain_ = 0; + } else { + // Adaptive compression with makeup gain. + amount -= 32768; + + int32_t max_gain, knee_gain; + max_gain = kMaxExponentialGain; + makeup_gain_ = amount * (max_gain >> 8) >> 7; + knee_gain = threshold_+ makeup_gain_; + if (knee_gain >= 0) { + makeup_gain_ = -threshold_; + knee_gain = 0; + } + + if (knee_gain > -4096) { + // So intense! Brickwall limiter mode. In this case, we use an + // instant attack to tame transients as soon as they appear. + ratio_ = 0; + attack_coefficient_ = -1; + } else { + ratio_ = knee_gain / (threshold_ >> 8); + } + } + } + + inline int32_t gain_reduction() const { return gain_reduction_; } + + private: + static int32_t Log2(int32_t value); + static int32_t Exp2(int32_t value); + static int32_t Compress( + int32_t squared_level, + int32_t threshold, + int32_t ratio, + bool soft_knee); + + int32_t ratio_; // Reciprocal of the ratio, 8:8 + int32_t threshold_; + int32_t makeup_gain_; + + bool soft_knee_; + + int64_t attack_coefficient_; + int64_t decay_coefficient_; + int64_t detector_; + int64_t sidechain_signal_detector_; + int32_t gain_reduction_; + + DISALLOW_COPY_AND_ASSIGN(Compressor); +}; + +} // namespace streams + +#endif // STREAMS_COMPRESSOR_H_ diff --git a/lib/streams/envelope.cc b/lib/streams/envelope.cc new file mode 100644 index 0000000..0572cca --- /dev/null +++ b/lib/streams/envelope.cc @@ -0,0 +1,128 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Simple AD envelope - adapted from Peaks' multistage envelope. + +#include "streams/envelope.h" + +#include "stmlib/utils/dsp.h" + +#include "streams/resources.h" + +#include "streams/gain.h" + +#include + +namespace streams { + +using namespace std; +using namespace stmlib; + +void Envelope::Init() { + fill(&shape_[0], &shape_[kMaxNumSegments], ENV_SHAPE_LINEAR); + set_ad(0, 8192); + segment_ = num_segments_; + phase_ = 0; + phase_increment_ = 0; + start_value_ = 0; + value_ = 0; + rate_modulation_ = 0; + gate_level_ = 0; + gate_ = false; + hard_reset_ = false; + attack_ = 0; + decay_ = 0; +} + +void Envelope::Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + // Smooth frequency amount parameters. + frequency_amount_ += (target_frequency_amount_ - frequency_amount_) >> 8; + frequency_offset_ += (target_frequency_offset_ - frequency_offset_) >> 8; + + bool trigger = false; + bool release = false; + if (gate_ == false) { + if (excite > kSchmittTriggerThreshold) { + trigger = true; + gate_ = true; + set_hard_reset(false); + } + } else { + if (excite < (kSchmittTriggerThreshold >> 1)) { + gate_ = false; + release = false; + } else { + // Track the level of the signal while the GATE is held. + gate_level_ += (excite - gate_level_) >> 8; + } + } + if (trigger) { + start_value_ = (segment_ == num_segments_ || hard_reset_) + ? level_[0] + : value_; + segment_ = 0; + phase_ = 0; + } else if (release && sustain_point_) { + start_value_ = value_; + segment_ = sustain_point_; + phase_ = 0; + } else if (phase_ < phase_increment_) { + start_value_ = level_[segment_ + 1]; + ++segment_; + phase_ = 0; + } + + bool done = segment_ == num_segments_; + bool sustained = sustain_point_ && segment_ == sustain_point_ && gate_; + uint32_t increment = sustained || done ? 0 : lut_env_increments[time_[segment_] >> 8]; + + // Modulates the envelope rate by the actual excitation pulse. + rate_modulation_ += (static_cast(excite > kSchmittTriggerThreshold ? excite : 0) - rate_modulation_) >> 12; + increment += static_cast(increment >> 7) * (rate_modulation_ >> 7); + + phase_increment_ = increment; + + int32_t a = start_value_; + int32_t b = level_[segment_ + 1]; + uint16_t t = Interpolate824( + lookup_table_table[LUT_ENV_LINEAR + shape_[segment_]], phase_); + value_ = a + ((b - a) * (t >> 1) >> 15); + phase_ += phase_increment_; + + // Applies a variable amount of distortion, depending on the level. + int32_t compressed = 32767 - ((32767 - value_) * (32767 - value_) >> 15); + compressed = 32767 - ((32767 - compressed) * (32767 - compressed) >> 15); + int32_t scaled = value_ + ((compressed - value_) * gate_level_ >> 15); + scaled = scaled * (28672 + (gate_level_ >> 3)) >> 15; + *gain = scaled * kAboveUnityGain >> 15; + *frequency = frequency_offset_ + (scaled * frequency_amount_ >> 15); +} + +} // namespace streams diff --git a/lib/streams/envelope.h b/lib/streams/envelope.h new file mode 100644 index 0000000..5794dd3 --- /dev/null +++ b/lib/streams/envelope.h @@ -0,0 +1,246 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Simple AD envelope - adapted from Peaks' multistage envelope. + +#ifndef STREAMS_ENVELOPE_H_ +#define STREAMS_ENVELOPE_H_ + +#include "stmlib/stmlib.h" + +#include "streams/meta_parameters.h" + +namespace streams { + +enum EnvelopeShape { + ENV_SHAPE_LINEAR, + ENV_SHAPE_EXPONENTIAL, + ENV_SHAPE_QUARTIC +}; + +const uint16_t kMaxNumSegments = 8; + +class Envelope { + public: + Envelope() { } + ~Envelope() { } + + void Init(); + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency); + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + uint16_t a, d; + if (globals) { + a = globals[0]; + d = globals[2]; + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + } else { + ComputeAttackDecay(parameters[0], &a, &d); + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + } + + if (a != attack_ || d != decay_ || alternate != alternate_) { + attack_ = a; + decay_ = d; + alternate_ = alternate; + if (alternate_) { + set_ar(a, d); + } else { + set_ad(a, d); + } + set_hard_reset(true); + } + } + + inline void set_time(uint16_t segment, uint16_t time) { + time_[segment] = time; + } + + inline void set_level(uint16_t segment, int16_t level) { + level_[segment] = level; + } + + inline void set_num_segments(uint16_t num_segments) { + num_segments_ = num_segments; + } + + inline void set_sustain_point(uint16_t sustain_point) { + sustain_point_ = sustain_point; + } + + inline void set_ad(uint16_t attack, uint16_t decay) { + num_segments_ = 2; + sustain_point_ = 0; + + level_[0] = 0; + level_[1] = 32767; + level_[2] = 0; + + time_[0] = attack; + time_[1] = decay; + + shape_[0] = ENV_SHAPE_LINEAR; + shape_[1] = ENV_SHAPE_EXPONENTIAL; + } + + inline void set_adr( + uint16_t attack, + uint16_t decay, + uint16_t sustain, + uint16_t release) { + num_segments_ = 3; + sustain_point_ = 0; + + level_[0] = 0; + level_[1] = 32767; + level_[2] = sustain; + level_[3] = 0; + + time_[0] = attack; + time_[1] = decay; + time_[2] = release; + + shape_[0] = ENV_SHAPE_LINEAR; + shape_[1] = ENV_SHAPE_LINEAR; + shape_[2] = ENV_SHAPE_LINEAR; + } + + inline void set_ar(uint16_t attack, uint16_t decay) { + num_segments_ = 2; + sustain_point_ = 1; + + level_[0] = 0; + level_[1] = 32767; + level_[2] = 0; + + time_[0] = attack; + time_[1] = decay; + + shape_[0] = ENV_SHAPE_LINEAR; + shape_[1] = ENV_SHAPE_LINEAR; + } + + inline void set_adsar( + uint16_t attack, + uint16_t decay, + uint16_t sustain, + uint16_t release) { + num_segments_ = 4; + sustain_point_ = 2; + + level_[0] = 0; + level_[1] = 32767; + level_[2] = sustain; + level_[3] = 32767; + level_[4] = 0; + + time_[0] = attack; + time_[1] = decay; + time_[2] = attack; + time_[3] = release; + + shape_[0] = ENV_SHAPE_LINEAR; + shape_[1] = ENV_SHAPE_LINEAR; + shape_[2] = ENV_SHAPE_LINEAR; + shape_[3] = ENV_SHAPE_LINEAR; + } + + inline void set_adar( + uint16_t attack, + uint16_t decay, + uint16_t sustain, + uint16_t release) { + num_segments_ = 4; + sustain_point_ = 0; + + level_[0] = 0; + level_[1] = 32767; + level_[2] = sustain; + level_[3] = 32767; + level_[4] = 0; + + time_[0] = attack; + time_[1] = decay; + time_[2] = attack; + time_[3] = release; + + shape_[0] = ENV_SHAPE_LINEAR; + shape_[1] = ENV_SHAPE_LINEAR; + shape_[2] = ENV_SHAPE_LINEAR; + shape_[3] = ENV_SHAPE_LINEAR; + } + + inline void set_hard_reset(bool hard_reset) { + hard_reset_ = hard_reset; + } + + private: + bool gate_; + + int16_t level_[kMaxNumSegments]; + uint16_t time_[kMaxNumSegments]; + EnvelopeShape shape_[kMaxNumSegments]; + + int16_t segment_; + int16_t start_value_; + int16_t value_; + + uint32_t phase_; + uint32_t phase_increment_; + + uint16_t num_segments_; + uint16_t sustain_point_; + + int32_t target_frequency_amount_; + int32_t target_frequency_offset_; + int32_t frequency_amount_; + int32_t frequency_offset_; + + uint16_t attack_; + uint16_t decay_; + + bool alternate_; + bool hard_reset_; + + int32_t rate_modulation_; + int32_t gate_level_; + + DISALLOW_COPY_AND_ASSIGN(Envelope); +}; + +} // namespace streams + +#endif // STREAMS_ENVELOPE_H_ diff --git a/lib/streams/filter_controller.h b/lib/streams/filter_controller.h new file mode 100644 index 0000000..1267033 --- /dev/null +++ b/lib/streams/filter_controller.h @@ -0,0 +1,84 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Plain filter. + +#ifndef STREAMS_FILTER_CONTROLLER_H_ +#define STREAMS_FILTER_CONTROLLER_H_ + +#include "stmlib/stmlib.h" + +namespace streams { + +class FilterController { + public: + FilterController() { } + ~FilterController() { } + + void Init() { + frequency_offset_ = 0; + frequency_amount_ = 0; + } + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + // Smooth frequency amount parameters. + frequency_amount_ += (target_frequency_amount_ - frequency_amount_) >> 8; + frequency_offset_ += (target_frequency_offset_ - frequency_offset_) >> 8; + + int32_t f; + f = frequency_offset_ + (excite * frequency_amount_ >> 14); + if (f < 0) { + f = 0; + } else if (f > 65535) { + f = 65535; + } + *gain = 0; + *frequency = f; + } + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + int32_t amount = parameters[1]; + amount -= 32768; + amount = amount * amount >> 15; + target_frequency_amount_ = parameters[1] < 32768 ? -amount : amount; + target_frequency_offset_ = parameters[0]; + } + + private: + int32_t target_frequency_amount_; + int32_t target_frequency_offset_; + int32_t frequency_amount_; + int32_t frequency_offset_; + + DISALLOW_COPY_AND_ASSIGN(FilterController); +}; + +} // namespace streams + +#endif // STREAMS_ENVELOPE_H_ diff --git a/lib/streams/follower.cc b/lib/streams/follower.cc new file mode 100644 index 0000000..98d2863 --- /dev/null +++ b/lib/streams/follower.cc @@ -0,0 +1,137 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Follower. + +#include "streams/follower.h" + +#include "stmlib/utils/dsp.h" + +#include "streams/gain.h" +#include "streams/resources.h" + +namespace streams { + +using namespace stmlib; + +void Follower::Init() { + analysis_low_.Init(); + analysis_low_.set_frequency(45 << 7); + analysis_low_.set_resonance(0); + analysis_medium_.Init(); + analysis_medium_.set_frequency(86 << 7); + analysis_medium_.set_resonance(0); + + for (uint8_t i = 0; i < 3; ++i) { + energy_[i][0] = energy_[i][1] = 0; + follower_[i] = 0; + follower_lp_[i] = 0; + spectrum_[i] = 0; + } + centroid_ = 0; +} + +void Follower::Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + // Smooth frequency amount parameters. + frequency_amount_ += (target_frequency_amount_ - frequency_amount_) >> 8; + frequency_offset_ += (target_frequency_offset_ - frequency_offset_) >> 8; + + analysis_low_.Process(excite); + analysis_medium_.Process(analysis_low_.hp()); + + int32_t channel[3]; + channel[0] = analysis_low_.lp(); + channel[1] = analysis_medium_.lp(); + channel[2] = analysis_medium_.hp(); + + int32_t envelope = 0; + int32_t centroid_numerator = 0; + int32_t centroid_denominator = 0; + for (int32_t i = 0; i < 3; ++i) { + int32_t energy = channel[i]; + energy *= energy; + + // Ride an ascending peak. + if (energy_[i][0] < energy_[i][1] && energy_[i][1] < energy && + energy > follower_[i]) { + follower_[i] = energy; + } + // Otherwise, hold and snap on local maxima. + if (energy_[i][0] <= energy_[i][1] && energy_[i][1] >= energy) { + follower_[i] = energy_[i][1]; + } + energy_[i][0] = energy_[i][1]; + energy_[i][1] = energy; + + // Then let a low-pass filter smooth things out. + int64_t error = follower_[i] - follower_lp_[i]; + if (error > 0) { + follower_lp_[i] += error * attack_coefficient_[i] >> 31; + } else { + follower_lp_[i] += error * decay_coefficient_[i] >> 31; + } + envelope += follower_lp_[i] >> 13; + + // Integrate more slowly for spectrum estimation. + if (only_filter_) { + error = follower_lp_[i] - spectrum_[i]; + spectrum_[i] += error >> 6; + } else { + error = follower_[i] - spectrum_[i]; + spectrum_[i] += error >> 10; + } + centroid_numerator += i * (spectrum_[i] >> 1) >> 16; + centroid_denominator += spectrum_[i] >> 16; + } + + if (envelope > 65535) { + envelope = 65535; + } else if (envelope < 0) { + envelope = 0; + } + + uint16_t gain_mod = Interpolate824(lut_square_root, envelope << 16) >> 1; + int32_t centroid = (centroid_numerator << 15) / (centroid_denominator + 1); + if (gain_mod > 4096) { + centroid_ = centroid; + } else if (gain_mod > 2048) { + centroid_ += (centroid - centroid_) >> 8; + } + + *gain = gain_mod * kUnityGain >> 15; + *frequency = frequency_offset_ + (centroid_ * frequency_amount_ >> 15); + + if (only_filter_) { + *gain = *frequency; + *frequency = 65535; + } +} + +} // namespace streams diff --git a/lib/streams/follower.h b/lib/streams/follower.h new file mode 100644 index 0000000..a6af6f8 --- /dev/null +++ b/lib/streams/follower.h @@ -0,0 +1,131 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Follower. + +#ifndef STREAMS_FOLLOWER_H_ +#define STREAMS_FOLLOWER_H_ + +#include "stmlib/stmlib.h" + +#include "streams/meta_parameters.h" +#include "streams/resources.h" +#include "streams/svf.h" + +namespace streams { + +const uint16_t kNumBands = 3; + +class Follower { + public: + Follower() { } + ~Follower() { } + + void Init(); + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency); + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + uint16_t attack_time; + uint16_t decay_time; + + if (globals) { + // Attack: 1ms to 100ms + attack_time = globals[0] >> 8; + + // Decay: 10ms to 1000ms + decay_time = 128 + (globals[2] >> 8); + + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + } else { + uint16_t shape = parameters[0]; + if (shape < 32768) { + // attack: 1ms to 2ms. + attack_time = (shape * 39 >> 15); + // decay: 10ms to 100ms. + decay_time = 128 + (shape * 128 >> 15); + } else { + shape -= 32768; + // attack: 2ms to 20ms. + attack_time = 39 + (shape * 128 >> 15); + // decay: 100ms to 200ms. + decay_time = 128 + 128 + (shape * 39 >> 15); + } + + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + } + + // Slow down the attack detection on low frequencies. + attack_coefficient_[0] = lut_lp_coefficients[attack_time + 39]; + attack_coefficient_[1] = lut_lp_coefficients[attack_time + 19]; + attack_coefficient_[2] = lut_lp_coefficients[attack_time + 0]; + + // Slow down the decay detection on high frequencies as there is more noise. + decay_coefficient_[0] = lut_lp_coefficients[decay_time + 39]; + decay_coefficient_[1] = lut_lp_coefficients[decay_time + 19]; + decay_coefficient_[2] = lut_lp_coefficients[decay_time + 99]; + + only_filter_ = alternate; + } + + private: + Svf analysis_low_; + Svf analysis_medium_; + int32_t energy_[kNumBands][2]; + int64_t follower_[kNumBands]; + + int64_t attack_coefficient_[kNumBands]; + int64_t decay_coefficient_[kNumBands]; + int64_t follower_lp_[kNumBands]; + + int32_t spectrum_[kNumBands]; + + int32_t centroid_; + + int32_t frequency_offset_; + int32_t frequency_amount_; + int32_t target_frequency_offset_; + int32_t target_frequency_amount_; + + int32_t naive_; + + bool only_filter_; + + DISALLOW_COPY_AND_ASSIGN(Follower); +}; + +} // namespace streams + +#endif // STREAMS_FOLLOWER_H_ diff --git a/lib/streams/gain.h b/lib/streams/gain.h new file mode 100644 index 0000000..a5ac597 --- /dev/null +++ b/lib/streams/gain.h @@ -0,0 +1,56 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Value to output on the DAC to get unitary gain. + +#ifndef STREAMS_GAIN_H_ +#define STREAMS_GAIN_H_ + +namespace streams { + +// The DAC sends up to 2.5V through 25k = 0.1mA over the range of the DAC. +// The offness compensation resistor sends -10V through 10M = 0.001mA. +// Assuming the op-amp offset is negligible, the two balance for a DAC code of +// 65536 / 100.0 + +const int32_t kDefaultOffset = 655; + +// DAC code giving a unitary gain. +const int32_t kUnityGain = 32767; + +// Slightly above unitary gain. +const int32_t kAboveUnityGain = 32896; + +// Maximum gain in dB in lin mode with a DAC code of 65535 (6 dB). +const int32_t kMaxLinearGain = 65536; +// Maximum gain in dB in lin mode with a DAC code of 65535 (18 dB). +const int32_t kMaxExponentialGain = 218453; + +const uint16_t kSchmittTriggerThreshold = 32768 * 5 * 2 / 3 / 8; + +} // namespace streams + +#endif // STREAMS_GAIN_H_ \ No newline at end of file diff --git a/lib/streams/lorenz_generator.cc b/lib/streams/lorenz_generator.cc new file mode 100644 index 0000000..7076acb --- /dev/null +++ b/lib/streams/lorenz_generator.cc @@ -0,0 +1,82 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Lorenz system. + +#include "streams/lorenz_generator.h" + +#include "streams/resources.h" + +namespace streams { + +using namespace stmlib; + +const int64_t sigma = 10.0 * (1 << 24); +const int64_t rho = 28.0 * (1 << 24); +const int64_t beta = 8.0 / 3.0 * (1 << 24); + +void LorenzGenerator::Init() { + x_ = 0.1 * (1 << 24); + y_ = 0; + z_ = 0; + vcf_amount_ = 0; + vca_amount_ = 0; +} + +void LorenzGenerator::Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + vcf_amount_ += (target_vcf_amount_ - vcf_amount_) >> 8; + vca_amount_ += (target_vca_amount_ - vca_amount_) >> 8; + int32_t rate = rate_ + (excite >> 8); + CONSTRAIN(rate, 0, 256); + int64_t dt = static_cast(lut_lorenz_rate[rate]); + + int32_t x = x_ + (dt * ((sigma * (y_ - x_)) >> 24) >> 24); + int32_t y = y_ + (dt * ((x_ * (rho - z_) >> 24) - y_) >> 24); + int32_t z = z_ + (dt * ((x_ * int64_t(y_) >> 24) - (beta * z_ >> 24)) >> 24); + + x_ = x; + y_ = y; + z_ = z; + + int32_t z_scaled = z >> 14; + int32_t x_scaled = (x >> 14) + 32768; + + if (index_) { + // On channel 2, z and y are inverted to get more variety! + z = z_scaled; + z_scaled = x_scaled; + x_scaled = z; + } + + *gain = z_scaled * vca_amount_ >> 15; + *frequency = 65535 + ((x_scaled - 65535) * vcf_amount_ >> 15); +} + +} // namespace streams diff --git a/lib/streams/lorenz_generator.h b/lib/streams/lorenz_generator.h new file mode 100644 index 0000000..c3331da --- /dev/null +++ b/lib/streams/lorenz_generator.h @@ -0,0 +1,80 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Lorenz system. + +#ifndef STREAMS_LORENZ_GENERATOR_H_ +#define STREAMS_LORENZ_GENERATOR_H_ + +#include "stmlib/stmlib.h" + +#include "streams/meta_parameters.h" + +namespace streams { + +class LorenzGenerator { + public: + LorenzGenerator() { } + ~LorenzGenerator() { } + + void Init(); + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency); + + void set_index(uint8_t index) { + index_ = index; + } + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + rate_ = parameters[0] >> 8; + int32_t vcf_amount = 65535 - parameters[1]; + int32_t vca_amount = parameters[1]; + if (vcf_amount >= 32767) vcf_amount = 32767; + if (vca_amount >= 32767) vca_amount = 32767; + target_vcf_amount_ = vcf_amount; + target_vca_amount_ = vca_amount; + } + + + private: + int32_t x_, y_, z_; + int32_t rate_; + int32_t vcf_amount_; + int32_t vca_amount_; + int32_t target_vcf_amount_; + int32_t target_vca_amount_; + + uint8_t index_; + + DISALLOW_COPY_AND_ASSIGN(LorenzGenerator); +}; + +} // namespace streams + +#endif // STREAMS_LORENZ_GENERATOR_H_ diff --git a/lib/streams/meta_parameters.h b/lib/streams/meta_parameters.h new file mode 100644 index 0000000..1c1e793 --- /dev/null +++ b/lib/streams/meta_parameters.h @@ -0,0 +1,66 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Control of several parameters from one single knob. + +#ifndef STREAMS_META_PARAMETERS_H_ +#define STREAMS_META_PARAMETERS_H_ + +#include "stmlib/stmlib.h" + +namespace streams { + +inline void ComputeAmountOffset( + int32_t value, + int32_t* amount, + int32_t* offset) { + if (value < 32768) { + value = 32767 - value; + value = value * value >> 15; + *amount = (32767 - value) << 1; + *offset = 0; + } else { + *amount = 65535 - ((value - 32768) << 1); + *offset = (value - 32768) << 1; + } +} + +inline void ComputeAttackDecay(int32_t shape, uint16_t* a, uint16_t* d) { + if (shape < 32768) { + *a = 0; + *d = 13 * (shape >> 3) + 12288; + } else if (shape < 49152) { + *a = (shape - 32768) << 1; + *d = 65535 - ((shape - 32768) >> 1) * 3; + } else { + *a = 32768 - ((shape - 49152) >> 2) * 5; + *d = 65535 - ((shape - 32768) >> 1) * 3; + } +} + +} // namespace streams + +#endif // STREAMS_META_PARAMETERS_H_ diff --git a/lib/streams/resources.cc b/lib/streams/resources.cc new file mode 100644 index 0000000..14c458e --- /dev/null +++ b/lib/streams/resources.cc @@ -0,0 +1,1435 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Resources definitions. +// +// Automatically generated with: +// make resources + + +#include "streams/resources.h" + +namespace streams { + +static const char str_dummy[] = "dummy"; + + +const char* string_table[] = { + str_dummy, +}; + +const int16_t wav_gompertz[] = { + 0, 12, 24, 36, + 48, 60, 72, 84, + 96, 108, 120, 132, + 144, 156, 168, 179, + 191, 203, 215, 227, + 238, 250, 262, 274, + 286, 298, 310, 323, + 335, 348, 360, 373, + 386, 399, 412, 426, + 439, 453, 467, 481, + 496, 511, 526, 542, + 558, 574, 591, 608, + 625, 643, 662, 681, + 700, 720, 741, 762, + 784, 807, 830, 854, + 878, 903, 930, 956, + 984, 1013, 1042, 1072, + 1104, 1136, 1169, 1203, + 1238, 1275, 1312, 1350, + 1390, 1430, 1472, 1515, + 1559, 1605, 1651, 1699, + 1749, 1799, 1851, 1904, + 1959, 2015, 2072, 2131, + 2191, 2252, 2315, 2380, + 2446, 2513, 2582, 2652, + 2724, 2798, 2873, 2949, + 3027, 3106, 3187, 3270, + 3354, 3439, 3526, 3615, + 3705, 3796, 3889, 3984, + 4080, 4177, 4276, 4377, + 4479, 4582, 4686, 4793, + 4900, 5009, 5119, 5231, + 5344, 5458, 5574, 5690, + 5808, 5928, 6048, 6170, + 6293, 6417, 6542, 6668, + 6796, 6924, 7053, 7184, + 7315, 7448, 7581, 7715, + 7850, 7986, 8123, 8261, + 8399, 8538, 8678, 8819, + 8960, 9102, 9244, 9387, + 9531, 9675, 9820, 9965, + 10110, 10256, 10403, 10550, + 10697, 10844, 10992, 11140, + 11288, 11436, 11585, 11734, + 11882, 12031, 12181, 12330, + 12479, 12628, 12777, 12926, + 13075, 13224, 13373, 13522, + 13670, 13819, 13967, 14115, + 14263, 14410, 14558, 14705, + 14851, 14997, 15143, 15289, + 15434, 15579, 15723, 15867, + 16011, 16154, 16296, 16438, + 16580, 16721, 16861, 17001, + 17141, 17280, 17418, 17555, + 17692, 17829, 17964, 18099, + 18234, 18367, 18500, 18633, + 18764, 18895, 19026, 19155, + 19284, 19412, 19539, 19666, + 19792, 19917, 20041, 20165, + 20287, 20409, 20530, 20651, + 20770, 20889, 21007, 21124, + 21241, 21356, 21471, 21585, + 21698, 21810, 21922, 22032, + 22142, 22251, 22359, 22466, + 22573, 22679, 22783, 22887, + 22991, 23093, 23195, 23295, + 23395, 23494, 23592, 23690, + 23786, 23882, 23977, 24071, + 24165, 24257, 24349, 24440, + 24530, 24619, 24708, 24795, + 24882, 24969, 25054, 25139, + 25222, 25305, 25388, 25469, + 25550, 25630, 25709, 25788, + 25865, 25942, 26019, 26094, + 26169, 26243, 26316, 26389, + 26461, 26532, 26603, 26672, + 26741, 26810, 26878, 26945, + 27011, 27077, 27142, 27206, + 27270, 27333, 27395, 27457, + 27518, 27579, 27639, 27698, + 27756, 27814, 27872, 27929, + 27985, 28041, 28096, 28150, + 28204, 28257, 28310, 28362, + 28414, 28465, 28515, 28565, + 28614, 28663, 28712, 28759, + 28807, 28853, 28900, 28945, + 28991, 29035, 29080, 29123, + 29167, 29209, 29252, 29294, + 29335, 29376, 29416, 29456, + 29496, 29535, 29574, 29612, + 29650, 29687, 29724, 29760, + 29796, 29832, 29867, 29902, + 29937, 29971, 30005, 30038, + 30071, 30103, 30136, 30167, + 30199, 30230, 30261, 30291, + 30321, 30351, 30380, 30409, + 30438, 30466, 30494, 30521, + 30549, 30576, 30602, 30629, + 30655, 30681, 30706, 30731, + 30756, 30781, 30805, 30829, + 30853, 30876, 30899, 30922, + 30945, 30967, 30989, 31011, + 31032, 31054, 31075, 31096, + 31116, 31136, 31156, 31176, + 31196, 31215, 31234, 31253, + 31272, 31290, 31308, 31326, + 31344, 31362, 31379, 31396, + 31413, 31430, 31446, 31463, + 31479, 31495, 31510, 31526, + 31541, 31556, 31571, 31586, + 31601, 31615, 31630, 31644, + 31658, 31671, 31685, 31698, + 31712, 31725, 31738, 31750, + 31763, 31775, 31788, 31800, + 31812, 31824, 31836, 31847, + 31859, 31870, 31881, 31892, + 31903, 31914, 31924, 31935, + 31945, 31955, 31966, 31976, + 31985, 31995, 32005, 32014, + 32024, 32033, 32042, 32051, + 32060, 32069, 32078, 32086, + 32095, 32103, 32111, 32120, + 32128, 32136, 32144, 32151, + 32159, 32167, 32174, 32182, + 32189, 32196, 32203, 32210, + 32217, 32224, 32231, 32238, + 32244, 32251, 32257, 32264, + 32270, 32276, 32282, 32288, + 32294, 32300, 32306, 32312, + 32318, 32323, 32329, 32334, + 32340, 32345, 32350, 32356, + 32361, 32366, 32371, 32376, + 32381, 32386, 32390, 32395, + 32400, 32404, 32409, 32413, + 32418, 32422, 32427, 32431, + 32435, 32439, 32443, 32447, + 32451, 32455, 32459, 32463, + 32467, 32471, 32475, 32478, + 32482, 32485, 32489, 32492, + 32496, 32499, 32503, 32506, + 32509, 32513, 32516, 32519, + 32522, 32525, 32528, 32531, + 32534, 32537, 32540, 32543, + 32546, 32548, 32551, 32554, + 32557, 32559, 32562, 32564, + 32567, 32569, 32572, 32574, + 32577, 32579, 32582, 32584, + 32586, 32588, 32591, 32593, + 32595, 32597, 32599, 32602, + 32604, 32606, 32608, 32610, + 32612, 32614, 32616, 32618, + 32619, 32621, 32623, 32625, + 32627, 32628, 32630, 32632, + 32634, 32635, 32637, 32639, + 32640, 32642, 32643, 32645, + 32647, 32648, 32650, 32651, + 32652, 32654, 32655, 32657, + 32658, 32660, 32661, 32662, + 32664, 32665, 32666, 32667, + 32669, 32670, 32671, 32672, + 32674, 32675, 32676, 32677, + 32678, 32679, 32680, 32682, + 32683, 32684, 32685, 32686, + 32687, 32688, 32689, 32690, + 32691, 32692, 32693, 32694, + 32695, 32695, 32696, 32697, + 32698, 32699, 32700, 32701, + 32702, 32702, 32703, 32704, + 32705, 32706, 32706, 32707, + 32708, 32709, 32709, 32710, + 32711, 32712, 32712, 32713, + 32714, 32714, 32715, 32716, + 32716, 32717, 32718, 32718, + 32719, 32719, 32720, 32721, + 32721, 32722, 32722, 32723, + 32723, 32724, 32725, 32725, + 32726, 32726, 32727, 32727, + 32728, 32728, 32729, 32729, + 32730, 32730, 32731, 32731, + 32731, 32732, 32732, 32733, + 32733, 32734, 32734, 32735, + 32735, 32735, 32736, 32736, + 32737, 32737, 32737, 32738, + 32738, 32738, 32739, 32739, + 32739, 32740, 32740, 32741, + 32741, 32741, 32742, 32742, + 32742, 32742, 32743, 32743, + 32743, 32744, 32744, 32744, + 32745, 32745, 32745, 32745, + 32746, 32746, 32746, 32747, + 32747, 32747, 32747, 32748, + 32748, 32748, 32748, 32749, + 32749, 32749, 32749, 32749, + 32750, 32750, 32750, 32750, + 32751, 32751, 32751, 32751, + 32751, 32752, 32752, 32752, + 32752, 32752, 32753, 32753, + 32753, 32753, 32753, 32753, + 32754, 32754, 32754, 32754, + 32754, 32754, 32755, 32755, + 32755, 32755, 32755, 32755, + 32756, 32756, 32756, 32756, + 32756, 32756, 32756, 32757, + 32757, 32757, 32757, 32757, + 32757, 32757, 32757, 32758, + 32758, 32758, 32758, 32758, + 32758, 32758, 32758, 32758, + 32759, 32759, 32759, 32759, + 32759, 32759, 32759, 32759, + 32759, 32760, 32760, 32760, + 32760, 32760, 32760, 32760, + 32760, 32760, 32760, 32760, + 32761, 32761, 32761, 32761, + 32761, 32761, 32761, 32761, + 32761, 32761, 32761, 32761, + 32761, 32762, 32762, 32762, + 32762, 32762, 32762, 32762, + 32762, 32762, 32762, 32762, + 32762, 32762, 32762, 32762, + 32763, 32763, 32763, 32763, + 32763, 32763, 32763, 32763, + 32763, 32763, 32763, 32763, + 32763, 32763, 32763, 32763, + 32763, 32763, 32763, 32764, + 32764, 32764, 32764, 32764, + 32764, 32764, 32764, 32764, + 32764, 32764, 32764, 32764, + 32764, 32764, 32764, 32764, + 32764, 32764, 32764, 32764, + 32764, 32764, 32764, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32767, +}; +const int16_t wav_db[] = { + -32768, -32768, -24576, -19783, + -16384, -13746, -11591, -9770, + -8192, -6799, -5554, -4428, + -3399, -2453, -1578, -762, + 0, 716, 1392, 2031, + 2637, 3213, 3763, 4289, + 4792, 5274, 5738, 6184, + 6613, 7028, 7429, 7816, + 8192, 8555, 8908, 9251, + 9584, 9907, 10223, 10530, + 10829, 11121, 11405, 11683, + 11955, 12221, 12481, 12735, + 12984, 13227, 13466, 13700, + 13930, 14155, 14376, 14592, + 14805, 15015, 15220, 15422, + 15621, 15816, 16008, 16197, + 16384, 16567, 16747, 16925, + 17100, 17273, 17443, 17610, + 17776, 17939, 18099, 18258, + 18415, 18569, 18722, 18872, + 19021, 19168, 19313, 19456, + 19597, 19737, 19875, 20012, + 20147, 20281, 20413, 20543, + 20673, 20800, 20927, 21052, + 21176, 21298, 21419, 21539, + 21658, 21776, 21892, 22007, + 22122, 22235, 22347, 22458, + 22568, 22676, 22784, 22891, + 22997, 23102, 23207, 23310, + 23412, 23514, 23614, 23714, + 23813, 23911, 24008, 24105, + 24200, 24295, 24389, 24483, + 24576, 24667, 24759, 24849, + 24939, 25028, 25117, 25205, + 25292, 25379, 25465, 25550, + 25635, 25719, 25802, 25885, + 25968, 26049, 26131, 26211, + 26291, 26371, 26450, 26529, + 26607, 26684, 26761, 26838, + 26914, 26989, 27064, 27139, + 27213, 27286, 27360, 27432, + 27505, 27576, 27648, 27719, + 27789, 27860, 27929, 27999, + 28067, 28136, 28204, 28272, + 28339, 28406, 28473, 28539, + 28605, 28670, 28735, 28800, + 28865, 28929, 28992, 29056, + 29119, 29181, 29244, 29306, + 29368, 29429, 29490, 29551, + 29611, 29671, 29731, 29791, + 29850, 29909, 29968, 30026, + 30084, 30142, 30199, 30257, + 30314, 30370, 30427, 30483, + 30539, 30594, 30650, 30705, + 30760, 30814, 30868, 30923, + 30976, 31030, 31083, 31136, + 31189, 31242, 31294, 31347, + 31399, 31450, 31502, 31553, + 31604, 31655, 31706, 31756, + 31806, 31856, 31906, 31955, + 32005, 32054, 32103, 32152, + 32200, 32248, 32297, 32345, + 32392, 32440, 32487, 32534, + 32581, 32628, 32675, 32721, + 32721, +}; + + +const int16_t* waveforms_table[] = { + wav_gompertz, + wav_db, +}; + +const uint16_t lut_env_linear[] = { + 0, 257, 514, 771, + 1028, 1285, 1542, 1799, + 2056, 2313, 2570, 2827, + 3084, 3341, 3598, 3855, + 4112, 4369, 4626, 4883, + 5140, 5397, 5654, 5911, + 6168, 6425, 6682, 6939, + 7196, 7453, 7710, 7967, + 8224, 8481, 8738, 8995, + 9252, 9509, 9766, 10023, + 10280, 10537, 10794, 11051, + 11308, 11565, 11822, 12079, + 12336, 12593, 12850, 13107, + 13364, 13621, 13878, 14135, + 14392, 14649, 14906, 15163, + 15420, 15677, 15934, 16191, + 16448, 16705, 16962, 17219, + 17476, 17733, 17990, 18247, + 18504, 18761, 19018, 19275, + 19532, 19789, 20046, 20303, + 20560, 20817, 21074, 21331, + 21588, 21845, 22102, 22359, + 22616, 22873, 23130, 23387, + 23644, 23901, 24158, 24415, + 24672, 24929, 25186, 25443, + 25700, 25957, 26214, 26471, + 26728, 26985, 27242, 27499, + 27756, 28013, 28270, 28527, + 28784, 29041, 29298, 29555, + 29812, 30069, 30326, 30583, + 30840, 31097, 31354, 31611, + 31868, 32125, 32382, 32639, + 32896, 33153, 33410, 33667, + 33924, 34181, 34438, 34695, + 34952, 35209, 35466, 35723, + 35980, 36237, 36494, 36751, + 37008, 37265, 37522, 37779, + 38036, 38293, 38550, 38807, + 39064, 39321, 39578, 39835, + 40092, 40349, 40606, 40863, + 41120, 41377, 41634, 41891, + 42148, 42405, 42662, 42919, + 43176, 43433, 43690, 43947, + 44204, 44461, 44718, 44975, + 45232, 45489, 45746, 46003, + 46260, 46517, 46774, 47031, + 47288, 47545, 47802, 48059, + 48316, 48573, 48830, 49087, + 49344, 49601, 49858, 50115, + 50372, 50629, 50886, 51143, + 51400, 51657, 51914, 52171, + 52428, 52685, 52942, 53199, + 53456, 53713, 53970, 54227, + 54484, 54741, 54998, 55255, + 55512, 55769, 56026, 56283, + 56540, 56797, 57054, 57311, + 57568, 57825, 58082, 58339, + 58596, 58853, 59110, 59367, + 59624, 59881, 60138, 60395, + 60652, 60909, 61166, 61423, + 61680, 61937, 62194, 62451, + 62708, 62965, 63222, 63479, + 63736, 63993, 64250, 64507, + 64764, 65021, 65278, 65535, + 65535, +}; +const uint16_t lut_env_expo[] = { + 0, 1035, 2054, 3057, + 4045, 5018, 5975, 6918, + 7846, 8760, 9659, 10545, + 11416, 12275, 13120, 13952, + 14771, 15577, 16371, 17152, + 17921, 18679, 19425, 20159, + 20881, 21593, 22294, 22983, + 23662, 24331, 24989, 25637, + 26274, 26902, 27520, 28129, + 28728, 29318, 29899, 30471, + 31034, 31588, 32133, 32670, + 33199, 33720, 34232, 34737, + 35233, 35722, 36204, 36678, + 37145, 37604, 38056, 38502, + 38940, 39371, 39796, 40215, + 40626, 41032, 41431, 41824, + 42211, 42592, 42967, 43336, + 43699, 44057, 44409, 44756, + 45097, 45434, 45764, 46090, + 46411, 46727, 47037, 47344, + 47645, 47941, 48233, 48521, + 48804, 49083, 49357, 49627, + 49893, 50155, 50412, 50666, + 50916, 51162, 51404, 51642, + 51877, 52108, 52335, 52559, + 52780, 52997, 53210, 53421, + 53628, 53831, 54032, 54230, + 54424, 54616, 54804, 54990, + 55173, 55353, 55530, 55704, + 55876, 56045, 56211, 56375, + 56536, 56695, 56851, 57005, + 57157, 57306, 57453, 57597, + 57740, 57880, 58018, 58153, + 58287, 58419, 58548, 58676, + 58801, 58925, 59047, 59167, + 59285, 59401, 59515, 59628, + 59739, 59848, 59955, 60061, + 60165, 60267, 60368, 60468, + 60566, 60662, 60757, 60850, + 60942, 61032, 61121, 61209, + 61295, 61380, 61464, 61546, + 61628, 61707, 61786, 61863, + 61939, 62014, 62088, 62161, + 62233, 62303, 62372, 62441, + 62508, 62574, 62639, 62703, + 62767, 62829, 62890, 62950, + 63010, 63068, 63125, 63182, + 63238, 63293, 63347, 63400, + 63452, 63504, 63554, 63604, + 63654, 63702, 63750, 63797, + 63843, 63888, 63933, 63977, + 64021, 64063, 64105, 64147, + 64188, 64228, 64267, 64306, + 64344, 64382, 64419, 64456, + 64492, 64527, 64562, 64596, + 64630, 64664, 64696, 64729, + 64760, 64792, 64822, 64853, + 64883, 64912, 64941, 64969, + 64997, 65025, 65052, 65079, + 65105, 65131, 65157, 65182, + 65206, 65231, 65255, 65278, + 65302, 65324, 65347, 65369, + 65391, 65412, 65434, 65454, + 65475, 65495, 65515, 65535, + 65535, +}; +const uint16_t lut_env_quartic[] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 1, + 2, 3, 4, 5, + 6, 8, 9, 11, + 14, 16, 19, 22, + 25, 29, 33, 37, + 42, 48, 53, 59, + 66, 73, 81, 89, + 98, 107, 117, 128, + 139, 151, 164, 177, + 191, 206, 222, 238, + 256, 274, 293, 313, + 334, 355, 378, 402, + 427, 453, 480, 508, + 537, 567, 599, 631, + 665, 700, 737, 775, + 814, 854, 896, 939, + 984, 1030, 1077, 1127, + 1177, 1230, 1283, 1339, + 1396, 1455, 1515, 1577, + 1641, 1707, 1775, 1844, + 1916, 1989, 2064, 2141, + 2220, 2302, 2385, 2470, + 2557, 2647, 2739, 2833, + 2929, 3027, 3128, 3231, + 3336, 3444, 3554, 3667, + 3782, 3899, 4019, 4142, + 4267, 4395, 4525, 4658, + 4794, 4933, 5074, 5218, + 5365, 5515, 5668, 5824, + 5983, 6144, 6309, 6477, + 6648, 6822, 6999, 7179, + 7363, 7550, 7740, 7933, + 8130, 8330, 8534, 8741, + 8951, 9165, 9383, 9604, + 9829, 10057, 10289, 10525, + 10765, 11008, 11255, 11507, + 11761, 12020, 12283, 12550, + 12821, 13096, 13375, 13658, + 13945, 14237, 14532, 14832, + 15137, 15445, 15758, 16076, + 16397, 16724, 17054, 17390, + 17730, 18074, 18423, 18777, + 19136, 19499, 19868, 20241, + 20618, 21001, 21389, 21781, + 22179, 22582, 22990, 23403, + 23821, 24244, 24672, 25106, + 25545, 25990, 26440, 26895, + 27355, 27821, 28293, 28770, + 29253, 29742, 30236, 30735, + 31241, 31752, 32270, 32793, + 33321, 33856, 34397, 34944, + 35497, 36056, 36621, 37192, + 37769, 38353, 38943, 39539, + 40142, 40751, 41366, 41988, + 42617, 43251, 43893, 44541, + 45196, 45857, 46526, 47201, + 47882, 48571, 49267, 49969, + 50678, 51395, 52118, 52849, + 53587, 54332, 55084, 55843, + 56610, 57384, 58165, 58954, + 59750, 60553, 61364, 62183, + 63010, 63843, 64685, 65535, + 65535, +}; +const uint16_t lut_square_root[] = { + 0, 4095, 5792, 7094, + 8191, 9158, 10032, 10836, + 11585, 12287, 12952, 13584, + 14188, 14768, 15325, 15863, + 16383, 16887, 17377, 17853, + 18317, 18769, 19211, 19643, + 20065, 20479, 20885, 21283, + 21673, 22057, 22434, 22805, + 23170, 23529, 23883, 24231, + 24575, 24914, 25249, 25579, + 25904, 26226, 26544, 26858, + 27169, 27476, 27779, 28080, + 28377, 28671, 28962, 29250, + 29536, 29818, 30098, 30376, + 30651, 30923, 31193, 31461, + 31726, 31990, 32251, 32510, + 32767, 33022, 33275, 33526, + 33775, 34023, 34269, 34512, + 34755, 34995, 35234, 35471, + 35707, 35941, 36174, 36405, + 36635, 36863, 37090, 37315, + 37539, 37762, 37984, 38204, + 38423, 38640, 38857, 39072, + 39286, 39499, 39711, 39922, + 40131, 40340, 40547, 40754, + 40959, 41163, 41366, 41569, + 41770, 41970, 42170, 42368, + 42566, 42762, 42958, 43153, + 43347, 43540, 43732, 43924, + 44114, 44304, 44493, 44681, + 44868, 45055, 45241, 45426, + 45610, 45793, 45976, 46158, + 46340, 46520, 46700, 46880, + 47058, 47236, 47413, 47590, + 47766, 47941, 48116, 48290, + 48463, 48636, 48808, 48980, + 49151, 49321, 49491, 49660, + 49829, 49997, 50164, 50331, + 50498, 50663, 50829, 50994, + 51158, 51321, 51485, 51647, + 51809, 51971, 52132, 52293, + 52453, 52613, 52772, 52931, + 53089, 53247, 53404, 53561, + 53717, 53873, 54029, 54184, + 54338, 54492, 54646, 54799, + 54952, 55105, 55257, 55408, + 55559, 55710, 55861, 56011, + 56160, 56309, 56458, 56606, + 56754, 56902, 57049, 57196, + 57343, 57489, 57634, 57780, + 57925, 58069, 58214, 58358, + 58501, 58644, 58787, 58930, + 59072, 59214, 59355, 59496, + 59637, 59778, 59918, 60058, + 60197, 60336, 60475, 60614, + 60752, 60890, 61028, 61165, + 61302, 61439, 61575, 61711, + 61847, 61982, 62117, 62252, + 62387, 62521, 62655, 62789, + 62922, 63056, 63189, 63321, + 63453, 63586, 63717, 63849, + 63980, 64111, 64242, 64372, + 64502, 64632, 64762, 64891, + 65020, 65149, 65278, 65406, + 65406, +}; +const uint16_t lut_svf_cutoff[] = { + 54, 57, 60, 64, + 68, 72, 76, 81, + 85, 91, 96, 102, + 108, 114, 121, 128, + 136, 144, 153, 162, + 171, 182, 192, 204, + 216, 229, 243, 257, + 272, 289, 306, 324, + 343, 364, 385, 408, + 433, 458, 486, 515, + 545, 578, 612, 648, + 687, 728, 771, 817, + 866, 917, 972, 1030, + 1091, 1156, 1225, 1297, + 1375, 1456, 1543, 1635, + 1732, 1835, 1944, 2060, + 2182, 2312, 2449, 2595, + 2749, 2912, 3085, 3269, + 3463, 3669, 3887, 4118, + 4362, 4621, 4895, 5186, + 5494, 5819, 6165, 6530, + 6917, 7327, 7760, 8219, + 8705, 9220, 9764, 10340, + 10949, 11593, 12275, 12995, + 13757, 14562, 15412, 16309, + 17257, 18256, 19310, 20421, + 21591, 22822, 24116, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, +}; +const uint16_t lut_svf_damp[] = { + 65534, 49166, 46069, 43993, + 42386, 41058, 39917, 38910, + 38007, 37184, 36427, 35726, + 35070, 34454, 33873, 33322, + 32798, 32299, 31820, 31361, + 30920, 30496, 30086, 29690, + 29306, 28935, 28574, 28224, + 27883, 27551, 27228, 26912, + 26605, 26304, 26010, 25723, + 25441, 25166, 24896, 24631, + 24371, 24116, 23866, 23620, + 23379, 23141, 22908, 22678, + 22452, 22229, 22010, 21794, + 21581, 21371, 21164, 20960, + 20759, 20560, 20365, 20171, + 19980, 19791, 19605, 19421, + 19239, 19059, 18882, 18706, + 18532, 18360, 18190, 18022, + 17856, 17691, 17528, 17367, + 17207, 17049, 16892, 16737, + 16583, 16431, 16280, 16131, + 15982, 15836, 15690, 15546, + 15403, 15261, 15120, 14981, + 14843, 14705, 14569, 14434, + 14300, 14167, 14036, 13905, + 13775, 13646, 13518, 13391, + 13265, 13140, 13015, 12892, + 12769, 12648, 12527, 12407, + 12287, 12169, 12051, 11934, + 11818, 11703, 11588, 11474, + 11361, 11249, 11137, 11026, + 10915, 10805, 10696, 10588, + 10480, 10373, 10266, 10160, + 10055, 9950, 9846, 9742, + 9639, 9537, 9435, 9333, + 9233, 9132, 9033, 8933, + 8835, 8737, 8639, 8542, + 8445, 8349, 8253, 8158, + 8063, 7969, 7875, 7782, + 7689, 7596, 7504, 7413, + 7321, 7231, 7140, 7050, + 6961, 6872, 6783, 6695, + 6607, 6519, 6432, 6346, + 6259, 6173, 6088, 6003, + 5918, 5833, 5749, 5665, + 5582, 5499, 5416, 5334, + 5251, 5170, 5088, 5007, + 4926, 4846, 4766, 4686, + 4607, 4527, 4449, 4370, + 4292, 4214, 4136, 4059, + 3982, 3905, 3828, 3752, + 3676, 3601, 3525, 3450, + 3375, 3301, 3226, 3152, + 3078, 3005, 2932, 2859, + 2786, 2713, 2641, 2569, + 2497, 2426, 2355, 2284, + 2213, 2142, 2072, 2002, + 1932, 1862, 1793, 1724, + 1655, 1586, 1518, 1449, + 1381, 1313, 1246, 1178, + 1111, 1044, 977, 911, + 844, 778, 712, 647, + 581, 516, 450, 385, + 321, 256, 192, 127, + 63, +}; +const uint16_t lut_2164_gain[] = { + 32767, 31340, 29975, 28670, + 27421, 26227, 25085, 23993, + 22948, 21948, 20993, 20078, + 19204, 18368, 17568, 16803, + 16071, 15371, 14702, 14062, + 13449, 12864, 12303, 11768, + 11255, 10765, 10296, 9848, + 9419, 9009, 8617, 8241, + 7882, 7539, 7211, 6897, + 6596, 6309, 6034, 5772, + 5520, 5280, 5050, 4830, + 4620, 4418, 4226, 4042, + 3866, 3698, 3537, 3383, + 3235, 3094, 2960, 2831, + 2707, 2589, 2477, 2369, + 2266, 2167, 2073, 1982, + 1896, 1813, 1734, 1659, + 1587, 1517, 1451, 1388, + 1328, 1270, 1215, 1162, + 1111, 1063, 1016, 972, + 930, 889, 850, 813, + 778, 744, 712, 681, + 651, 623, 595, 569, + 545, 521, 498, 477, + 456, 436, 417, 399, + 381, 365, 349, 334, + 319, 305, 292, 279, + 267, 255, 244, 233, + 223, 214, 204, 195, + 187, 179, 171, 163, + 156, 149, 143, 137, + 131, 125, 119, 114, + 109, 104, 100, 96, + 91, 87, 84, 80, + 76, 73, 70, 67, + 64, 61, 58, 56, + 53, 51, 49, 47, + 45, 43, 41, 39, + 37, 36, 34, 32, + 31, 30, 28, 27, + 26, 25, 24, 23, + 22, 21, 20, 19, + 18, 17, 16, 16, + 15, 14, 14, 13, + 12, 12, 11, 11, + 10, 10, 9, 9, + 9, 8, 8, 7, + 7, 7, 6, 6, + 6, 6, 5, 5, + 5, 5, 4, 4, + 4, 4, 4, 3, + 3, 3, 3, 3, + 3, 2, 2, 2, + 2, 2, 2, 2, + 2, 2, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, +}; +const uint16_t lut_compressor_ratio[] = { + 256, 255, 255, 255, + 254, 253, 252, 251, + 250, 248, 246, 245, + 243, 241, 238, 236, + 234, 231, 228, 226, + 223, 220, 217, 214, + 211, 208, 205, 202, + 198, 195, 192, 189, + 186, 183, 179, 176, + 173, 170, 167, 164, + 161, 158, 155, 152, + 149, 146, 144, 141, + 138, 136, 133, 131, + 128, 126, 123, 121, + 119, 116, 114, 112, + 110, 108, 106, 104, + 102, 100, 98, 96, + 95, 93, 91, 89, + 88, 86, 85, 83, + 82, 80, 79, 77, + 76, 75, 73, 72, + 71, 70, 69, 67, + 66, 65, 64, 63, + 62, 61, 60, 59, + 58, 57, 56, 55, + 54, 54, 53, 52, + 51, 50, 50, 49, + 48, 47, 47, 46, + 45, 45, 44, 43, + 43, 42, 41, 41, + 40, 40, 39, 39, + 38, 38, 37, 37, + 36, 36, 35, 35, + 34, 34, 33, 33, + 32, 32, 32, 31, + 31, 30, 30, 30, + 29, 29, 29, 28, + 28, 28, 27, 27, + 27, 26, 26, 26, + 25, 25, 25, 24, + 24, 24, 24, 23, + 23, 23, 23, 22, + 22, 22, 22, 21, + 21, 21, 21, 20, + 20, 20, 20, 20, + 19, 19, 19, 19, + 19, 18, 18, 18, + 18, 18, 18, 17, + 17, 17, 17, 17, + 16, 16, 16, 16, + 16, 16, 16, 15, + 15, 15, 15, 15, + 15, 15, 14, 14, + 14, 14, 14, 14, + 14, 14, 13, 13, + 13, 13, 13, 13, + 13, 13, 12, 12, + 12, 12, 12, 12, + 12, 12, 12, 12, + 11, 11, 11, 11, + 11, 11, 11, 11, + 11, 11, 11, 10, + 10, 10, 10, 10, + 10, 10, 10, 10, + 10, +}; +const uint16_t lut_soft_knee[] = { + 0, 0, 0, 0, + 0, 0, 0, 1, + 1, 2, 3, 5, + 6, 8, 10, 13, + 15, 19, 22, 26, + 31, 36, 41, 47, + 53, 61, 68, 76, + 85, 95, 105, 116, + 127, 140, 153, 167, + 182, 197, 214, 231, + 249, 269, 289, 310, + 332, 355, 380, 405, + 431, 459, 488, 518, + 549, 581, 615, 649, + 685, 723, 762, 802, + 843, 886, 930, 976, + 1023, 1072, 1123, 1174, + 1228, 1283, 1339, 1398, + 1457, 1519, 1582, 1647, + 1714, 1783, 1853, 1925, + 1999, 2075, 2153, 2233, + 2315, 2398, 2484, 2572, + 2661, 2753, 2847, 2943, + 3041, 3141, 3244, 3349, + 3455, 3565, 3676, 3790, + 3906, 4024, 4145, 4268, + 4393, 4521, 4652, 4785, + 4920, 5058, 5199, 5342, + 5487, 5636, 5787, 5940, + 6097, 6256, 6417, 6582, + 6749, 6920, 7093, 7268, + 7447, 7629, 7813, 8001, + 8191, 8385, 8581, 8781, + 8984, 9189, 9398, 9610, + 9825, 10044, 10265, 10490, + 10718, 10949, 11184, 11422, + 11663, 11908, 12156, 12408, + 12663, 12921, 13183, 13448, + 13717, 13990, 14266, 14546, + 14829, 15116, 15407, 15701, + 15999, 16301, 16607, 16916, + 17229, 17547, 17868, 18192, + 18521, 18854, 19191, 19531, + 19876, 20225, 20577, 20934, + 21295, 21660, 22029, 22403, + 22780, 23162, 23548, 23939, + 24333, 24732, 25135, 25543, + 25955, 26371, 26792, 27217, + 27647, 28081, 28520, 28963, + 29411, 29864, 30321, 30783, + 31249, 31720, 32196, 32676, + 33162, 33652, 34147, 34646, + 35151, 35660, 36175, 36694, + 37218, 37747, 38282, 38821, + 39365, 39914, 40469, 41028, + 41593, 42162, 42737, 43317, + 43903, 44493, 45089, 45691, + 46297, 46909, 47526, 48149, + 48777, 49410, 50049, 50694, + 51343, 51999, 52660, 53326, + 53999, 54676, 55360, 56049, + 56744, 57444, 58151, 58863, + 59581, 60304, 61034, 61769, + 62510, 63257, 64010, 64770, + 65535, +}; + + +const uint16_t* lookup_table_table[] = { + lut_env_linear, + lut_env_expo, + lut_env_quartic, + lut_square_root, + lut_svf_cutoff, + lut_svf_damp, + lut_2164_gain, + lut_compressor_ratio, + lut_soft_knee, +}; + +const uint32_t lut_env_increments[] = { + 276301411, 231949934, 196150997, 166999666, + 143068141, 123273939, 106787653, 92967541, + 81312526, 71428035, 63000899, 55780710, + 49565850, 44192924, 39528695, 35463892, + 31908401, 28787528, 26039050, 23610894, + 21459288, 19547282, 17843559, 16321476, + 14958281, 13734481, 12633316, 11640330, + 10743016, 9930523, 9193410, 8523437, + 7913397, 7356972, 6848604, 6383397, + 5957029, 5565672, 5205932, 4874792, + 4569569, 4287864, 4027536, 3786669, + 3563542, 3356609, 3164482, 2985906, + 2819752, 2664995, 2520711, 2386061, + 2260283, 2142684, 2032635, 1929561, + 1832939, 1742290, 1657176, 1577196, + 1501984, 1431202, 1364541, 1301717, + 1242466, 1186549, 1133742, 1083841, + 1036655, 992009, 949741, 909701, + 871748, 835755, 801600, 769172, + 738367, 709089, 681248, 654760, + 629547, 605536, 582659, 560852, + 540056, 520215, 501277, 483193, + 465917, 449406, 433620, 418521, + 404074, 390245, 377002, 364316, + 352160, 340506, 329331, 318610, + 308322, 298445, 288962, 279851, + 271097, 262683, 254593, 246811, + 239325, 232121, 225185, 218507, + 212074, 205876, 199903, 194146, + 188594, 183239, 178072, 173087, + 168275, 163628, 159142, 154807, + 150620, 146573, 142661, 138879, + 135221, 131683, 128260, 124947, + 121741, 118636, 115630, 112719, + 109899, 107166, 104518, 101951, + 99463, 97050, 94709, 92439, + 90236, 88099, 86025, 84011, + 82056, 80157, 78313, 76521, + 74781, 73090, 71446, 69848, + 68295, 66785, 65316, 63887, + 62497, 61145, 59829, 58549, + 57302, 56089, 54907, 53756, + 52636, 51544, 50480, 49444, + 48434, 47450, 46491, 45556, + 44644, 43755, 42888, 42043, + 41218, 40413, 39628, 38862, + 38114, 37384, 36671, 35976, + 35296, 34633, 33985, 33353, + 32735, 32131, 31541, 30965, + 30401, 29851, 29313, 28786, + 28272, 27769, 27277, 26796, + 26326, 25866, 25416, 24975, + 24545, 24123, 23710, 23307, + 22911, 22524, 22146, 21775, + 21412, 21056, 20708, 20367, + 20033, 19705, 19385, 19071, + 18763, 18461, 18166, 17876, + 17592, 17314, 17041, 16774, + 16512, 16254, 16002, 15755, + 15513, 15275, 15041, 14812, + 14588, 14368, 14151, 13939, + 13731, 13527, 13326, 13130, + 12936, 12747, 12561, 12378, + 12198, 12022, 11849, 11679, + 11512, +}; +const uint32_t lut_lp_coefficients[] = { + 590672516, 319034455, 133800766, 67976239, + 63327094, 62214607, 61121376, 60047077, + 58991393, 57954009, 56934619, 55932918, + 54948609, 53981397, 53030993, 52097114, + 51179478, 50277811, 49391841, 48521302, + 47665932, 46825472, 45999668, 45188271, + 44391035, 43607717, 42838081, 42081892, + 41338919, 40608937, 39891723, 39187058, + 38494727, 37814517, 37146221, 36489633, + 35844551, 35210779, 34588120, 33976383, + 33375380, 32784926, 32204838, 31634936, + 31075046, 30524993, 29984607, 29453721, + 28932170, 28419793, 27916429, 27421923, + 26936121, 26458872, 25990026, 25529439, + 25076965, 24632464, 24195797, 23766828, + 23345422, 22931447, 22524774, 22125276, + 21732827, 21347304, 20968586, 20596554, + 20231092, 19872084, 19519417, 19172981, + 18832666, 18498365, 18169974, 17847387, + 17530504, 17219225, 16913451, 16613085, + 16318033, 16028202, 15743500, 15463836, + 15189122, 14919272, 14654199, 14393820, + 14138052, 13886814, 13640026, 13397610, + 13159489, 12925588, 12695832, 12470147, + 12248464, 12030709, 11816816, 11606715, + 11400339, 11197623, 10998503, 10802914, + 10610795, 10422085, 10236722, 10054649, + 9875806, 9700137, 9527587, 9358098, + 9191619, 9028094, 8867473, 8709704, + 8554736, 8402520, 8253007, 8106150, + 7961901, 7820214, 7681044, 7544346, + 7410077, 7278193, 7148653, 7021415, + 6896437, 6773681, 6653106, 6534675, + 6418348, 6304089, 6191861, 6081629, + 5973356, 5867008, 5762550, 5659950, + 5559175, 5460191, 5362968, 5267474, + 5173678, 5081550, 4991061, 4902182, + 4814883, 4729137, 4644917, 4562195, + 4480945, 4401140, 4322755, 4245764, + 4170144, 4095869, 4022916, 3951261, + 3880881, 3811754, 3743857, 3677168, + 3611666, 3547330, 3484139, 3422073, + 3361112, 3301236, 3242425, 3184662, + 3127927, 3072202, 3017468, 2963710, + 2910908, 2859047, 2808109, 2758078, + 2708937, 2660672, 2613266, 2566704, + 2520972, 2476054, 2431935, 2388602, + 2346041, 2304238, 2263180, 2222853, + 2183243, 2144340, 2106129, 2068599, + 2031737, 1995532, 1959971, 1925044, + 1890740, 1857046, 1823952, 1791448, + 1759523, 1728167, 1697369, 1667120, + 1637410, 1608229, 1579568, 1551417, + 1523768, 1496612, 1469939, 1443741, + 1418011, 1392739, 1367917, 1343537, + 1319591, 1296073, 1272973, 1250285, + 1228001, 1206114, 1184617, 1163504, + 1142766, 1122398, 1102393, 1082744, + 1063446, 1044491, 1025874, 1007589, + 989630, 971991, 954666, 937650, + 920937, 904521, 888399, 872564, + 857011, 841735, 826731, 811995, + 797521, 783305, 769343, 755630, + 742160, 728931, 715938, 703176, + 690642, 678331, 666240, 654364, + 642699, 631243, 619991, 608939, + 598084, 587423, 576952, 566667, + 556566, 546644, 536900, 527329, + 517929, 508696, 499628, 490722, + 481974, 473383, 464944, 456656, + 448515, 440520, 432667, 424954, + 417379, 409938, 402631, 395453, + 388404, 381480, 374679, 368000, + 361440, 354997, 348668, 342453, + 336348, 330352, 324463, 318678, + 312997, 307418, 301937, 296555, + 291268, 286076, 280976, 275967, + 271047, 266215, 261469, 256808, + 252230, 247733, 243317, 238979, + 234719, 230535, 226425, 222388, + 218424, 214530, 210705, 206949, + 203260, 199636, 196077, 192582, + 189148, 185776, 182465, 179212, + 176017, 172879, 169797, 166770, + 163797, 160877, 158009, 155192, + 152425, 149708, 147039, 144417, + 141843, 139314, 136830, 134391, + 131995, 129642, 127331, 125061, + 122831, 120641, 118491, 116378, + 114304, 112266, 110264, 108299, + 106368, 104472, 102609, 100780, + 98983, 97218, 95485, 93783, + 92111, 90469, 88856, 87272, + 85716, 84188, 82687, 81213, + 79765, 78343, 76946, 75574, + 74227, 72904, 71604, 70328, + 69074, 67842, 66633, 65445, + 64278, 63132, 62007, 60901, + 59815, 58749, 57702, 56673, + 55663, 54670, 53696, 52738, + 51798, 50875, 49968, 49077, + 48202, 47343, 46498, 45669, + 44855, 44056, 43270, 42499, + 41741, 40997, 40266, 39548, + 38843, 38151, 37470, 36802, + 36146, 35502, 34869, 34247, + 33637, 33037, 32448, 31870, + 31301, 30743, 30195, 29657, + 29128, 28609, 28099, 27598, + 27106, 26623, 26148, 25682, + 25224, 24774, 24332, 23899, + 23473, 23054, 22643, 22239, + 21843, 21454, 21071, 20695, + 20326, 19964, 19608, 19258, + 18915, 18578, 18247, 17921, + 17602, 17288, 16980, 16677, + 16380, 16088, 15801, 15519, + 15243, 14971, 14704, 14442, + 14184, 13931, 13683, 13439, + 13199, 12964, 12733, 12506, + 12283, 12064, 11849, 11638, + 11430, 11226, 11026, 10830, + 10637, 10447, 10261, 10078, + 9898, 9722, 9548, 9378, + 9211, 9047, 8885, 8727, + 8571, 8418, 8268, 8121, + 7976, 7834, 7694, 7557, + 7422, 7290, 7160, 7032, + 6907, 6784, 6663, 6544, + 6427, 6313, 6200, 6090, + 5981, 5875, 5770, 5667, + 5566, 5467, 5369, 5273, + 5179, 5087, 4996, 4907, + 4820, 4734, 4649, 4567, + 4485, 4405, 4327, 4249, + 4174, 4099, 4026, 3954, + 3884, 3815, 3747, 3680, + 3614, 3550, 3486, 3424, + 3363, 3303, 3244, 3187, + 3130, 3074, 3019, 2965, + 2912, 2860, 2809, 2759, + 2710, 2662, 2614, 2568, + 2522, 2477, 2433, 2389, + 2347, 2305, 2264, 2224, + 2184, 2145, 2107, 2069, + 2032, 1996, 1960, 1925, + 1891, 1857, 1824, 1792, + 1760, 1728, 1698, 1667, + 1638, 1608, 1580, 1551, + 1524, 1497, 1470, 1444, + 1418, 1393, 1368, 1343, + 1319, 1296, 1273, 1250, + 1228, 1206, 1184, 1163, + 1143, 1122, 1102, 1083, + 1063, 1044, 1026, 1007, + 989, 972, 954, 937, + 921, 904, 888, 872, + 857, 841, 826, 812, + 797, 783, 769, 755, + 742, 729, 716, 703, +}; +const uint32_t lut_exp2[] = { + 65536, 65713, 65891, 66070, + 66249, 66429, 66609, 66789, + 66971, 67152, 67334, 67517, + 67700, 67883, 68067, 68252, + 68437, 68623, 68809, 68995, + 69182, 69370, 69558, 69747, + 69936, 70125, 70315, 70506, + 70697, 70889, 71081, 71274, + 71467, 71661, 71855, 72050, + 72245, 72441, 72638, 72834, + 73032, 73230, 73429, 73628, + 73827, 74027, 74228, 74429, + 74631, 74833, 75036, 75240, + 75444, 75648, 75853, 76059, + 76265, 76472, 76679, 76887, + 77096, 77305, 77514, 77725, + 77935, 78147, 78359, 78571, + 78784, 78998, 79212, 79427, + 79642, 79858, 80074, 80292, + 80509, 80727, 80946, 81166, + 81386, 81607, 81828, 82050, + 82272, 82495, 82719, 82943, + 83168, 83394, 83620, 83846, + 84074, 84302, 84530, 84759, + 84989, 85220, 85451, 85682, + 85915, 86148, 86381, 86615, + 86850, 87086, 87322, 87559, + 87796, 88034, 88273, 88512, + 88752, 88993, 89234, 89476, + 89718, 89962, 90206, 90450, + 90695, 90941, 91188, 91435, + 91683, 91932, 92181, 92431, + 92681, 92933, 93185, 93437, + 93691, 93945, 94199, 94455, + 94711, 94968, 95225, 95483, + 95742, 96002, 96262, 96523, + 96785, 97047, 97310, 97574, + 97839, 98104, 98370, 98637, + 98904, 99172, 99441, 99711, + 99981, 100252, 100524, 100797, + 101070, 101344, 101619, 101894, + 102170, 102447, 102725, 103004, + 103283, 103563, 103844, 104125, + 104408, 104691, 104975, 105259, + 105545, 105831, 106118, 106405, + 106694, 106983, 107273, 107564, + 107856, 108148, 108441, 108735, + 109030, 109326, 109622, 109919, + 110217, 110516, 110816, 111116, + 111418, 111720, 112023, 112326, + 112631, 112936, 113243, 113550, + 113857, 114166, 114476, 114786, + 115097, 115409, 115722, 116036, + 116351, 116666, 116982, 117300, + 117618, 117936, 118256, 118577, + 118898, 119221, 119544, 119868, + 120193, 120519, 120846, 121173, + 121502, 121831, 122162, 122493, + 122825, 123158, 123492, 123827, + 124162, 124499, 124837, 125175, + 125514, 125855, 126196, 126538, + 126881, 127225, 127570, 127916, + 128263, 128611, 128959, 129309, + 129660, 130011, 130364, 130717, + 131072, +}; +const uint32_t lut_log2[] = { + 524288, 524656, 525023, 525389, + 525753, 526116, 526478, 526838, + 527197, 527554, 527910, 528265, + 528619, 528971, 529322, 529671, + 530019, 530366, 530712, 531057, + 531400, 531742, 532082, 532422, + 532760, 533097, 533433, 533768, + 534101, 534434, 534765, 535095, + 535424, 535751, 536078, 536403, + 536728, 537051, 537373, 537694, + 538014, 538333, 538651, 538968, + 539283, 539598, 539912, 540224, + 540536, 540846, 541156, 541464, + 541772, 542078, 542384, 542688, + 542992, 543294, 543596, 543896, + 544196, 544495, 544793, 545089, + 545385, 545680, 545974, 546268, + 546560, 546851, 547142, 547431, + 547720, 548008, 548295, 548581, + 548866, 549150, 549434, 549717, + 549998, 550279, 550560, 550839, + 551117, 551395, 551672, 551948, + 552223, 552498, 552771, 553044, + 553316, 553588, 553858, 554128, + 554397, 554665, 554932, 555199, + 555465, 555730, 555995, 556259, + 556522, 556784, 557045, 557306, + 557566, 557826, 558084, 558342, + 558600, 558856, 559112, 559367, + 559622, 559876, 560129, 560381, + 560633, 560884, 561135, 561384, + 561634, 561882, 562130, 562377, + 562624, 562870, 563115, 563359, + 563603, 563847, 564089, 564332, + 564573, 564814, 565054, 565294, + 565533, 565771, 566009, 566247, + 566483, 566719, 566955, 567190, + 567424, 567658, 567891, 568124, + 568356, 568587, 568818, 569048, + 569278, 569507, 569736, 569964, + 570192, 570419, 570645, 570871, + 571096, 571321, 571545, 571769, + 571992, 572215, 572437, 572659, + 572880, 573101, 573321, 573541, + 573760, 573978, 574197, 574414, + 574631, 574848, 575064, 575280, + 575495, 575709, 575923, 576137, + 576350, 576563, 576775, 576987, + 577198, 577409, 577619, 577829, + 578039, 578248, 578456, 578664, + 578872, 579079, 579286, 579492, + 579698, 579903, 580108, 580312, + 580516, 580720, 580923, 581125, + 581328, 581530, 581731, 581932, + 582132, 582332, 582532, 582731, + 582930, 583129, 583327, 583524, + 583721, 583918, 584115, 584311, + 584506, 584701, 584896, 585090, + 585284, 585478, 585671, 585864, + 586056, 586248, 586440, 586631, + 586822, 587012, 587202, 587392, + 587581, 587770, 587959, 588147, + 588335, 588522, 588709, 588896, + 589082, 589268, 589453, 589639, + 589824, +}; +const uint32_t lut_lorenz_rate[] = { + 3, 3, 3, 4, + 4, 4, 4, 4, + 5, 5, 5, 5, + 6, 6, 6, 7, + 7, 7, 8, 8, + 8, 9, 9, 10, + 10, 11, 11, 12, + 12, 13, 13, 14, + 15, 15, 16, 17, + 18, 18, 19, 20, + 21, 22, 23, 24, + 25, 27, 28, 29, + 30, 32, 33, 35, + 36, 38, 40, 42, + 44, 46, 48, 50, + 52, 55, 57, 60, + 63, 66, 69, 72, + 75, 78, 82, 86, + 90, 94, 98, 103, + 107, 112, 118, 123, + 129, 135, 141, 147, + 154, 161, 168, 176, + 184, 193, 201, 211, + 220, 230, 241, 252, + 263, 275, 288, 301, + 315, 329, 344, 360, + 377, 394, 412, 431, + 451, 471, 493, 515, + 539, 563, 589, 616, + 644, 674, 705, 737, + 770, 806, 843, 881, + 921, 963, 1007, 1054, + 1102, 1152, 1205, 1260, + 1317, 1378, 1441, 1506, + 1575, 1647, 1722, 1801, + 1883, 1970, 2060, 2154, + 2252, 2355, 2463, 2575, + 2693, 2816, 2945, 3079, + 3220, 3367, 3521, 3682, + 3850, 4026, 4210, 4402, + 4603, 4814, 5034, 5264, + 5504, 5756, 6019, 6294, + 6581, 6882, 7196, 7525, + 7869, 8229, 8605, 8998, + 9409, 9839, 10288, 10758, + 11250, 11764, 12302, 12864, + 13451, 14066, 14709, 15381, + 16083, 16818, 17587, 18390, + 19230, 20109, 21028, 21989, + 22993, 24044, 25142, 26291, + 27492, 28748, 30062, 31435, + 32872, 34374, 35944, 37586, + 39304, 41099, 42977, 44941, + 46994, 49141, 51386, 53734, + 56189, 58756, 61441, 64248, + 67184, 70253, 73463, 76819, + 80329, 83999, 87837, 91850, + 96047, 100435, 105024, 109822, + 114840, 120087, 125573, 131310, + 137310, 143583, 150144, 157003, + 164177, 171678, 179521, 187723, + 196300, 205269, 214647, 224454, + 234709, 245433, 256646, 268372, + 280634, 293455, 306863, 320883, + 335544, +}; + + +const uint32_t* lookup_table_32_table[] = { + lut_env_increments, + lut_lp_coefficients, + lut_exp2, + lut_log2, + lut_lorenz_rate, +}; + + +} // namespace streams diff --git a/lib/streams/resources.h b/lib/streams/resources.h new file mode 100644 index 0000000..1f464f7 --- /dev/null +++ b/lib/streams/resources.h @@ -0,0 +1,105 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Resources definitions. +// +// Automatically generated with: +// make resources + + +#ifndef STREAMS_RESOURCES_H_ +#define STREAMS_RESOURCES_H_ + + +#include "stmlib/stmlib.h" + + + +namespace streams { + +typedef uint8_t ResourceId; + +extern const char* string_table[]; + +extern const int16_t* waveforms_table[]; + +extern const uint16_t* lookup_table_table[]; + +extern const uint32_t* lookup_table_32_table[]; + +extern const int16_t wav_gompertz[]; +extern const int16_t wav_db[]; +extern const uint16_t lut_env_linear[]; +extern const uint16_t lut_env_expo[]; +extern const uint16_t lut_env_quartic[]; +extern const uint16_t lut_square_root[]; +extern const uint16_t lut_svf_cutoff[]; +extern const uint16_t lut_svf_damp[]; +extern const uint16_t lut_2164_gain[]; +extern const uint16_t lut_compressor_ratio[]; +extern const uint16_t lut_soft_knee[]; +extern const uint32_t lut_env_increments[]; +extern const uint32_t lut_lp_coefficients[]; +extern const uint32_t lut_exp2[]; +extern const uint32_t lut_log2[]; +extern const uint32_t lut_lorenz_rate[]; +#define STR_DUMMY 0 // dummy +#define WAV_GOMPERTZ 0 +#define WAV_GOMPERTZ_SIZE 1025 +#define WAV_DB 1 +#define WAV_DB_SIZE 257 +#define LUT_ENV_LINEAR 0 +#define LUT_ENV_LINEAR_SIZE 257 +#define LUT_ENV_EXPO 1 +#define LUT_ENV_EXPO_SIZE 257 +#define LUT_ENV_QUARTIC 2 +#define LUT_ENV_QUARTIC_SIZE 257 +#define LUT_SQUARE_ROOT 3 +#define LUT_SQUARE_ROOT_SIZE 257 +#define LUT_SVF_CUTOFF 4 +#define LUT_SVF_CUTOFF_SIZE 257 +#define LUT_SVF_DAMP 5 +#define LUT_SVF_DAMP_SIZE 257 +#define LUT_2164_GAIN 6 +#define LUT_2164_GAIN_SIZE 257 +#define LUT_COMPRESSOR_RATIO 7 +#define LUT_COMPRESSOR_RATIO_SIZE 257 +#define LUT_SOFT_KNEE 8 +#define LUT_SOFT_KNEE_SIZE 257 +#define LUT_ENV_INCREMENTS 0 +#define LUT_ENV_INCREMENTS_SIZE 257 +#define LUT_LP_COEFFICIENTS 1 +#define LUT_LP_COEFFICIENTS_SIZE 640 +#define LUT_EXP2 2 +#define LUT_EXP2_SIZE 257 +#define LUT_LOG2 3 +#define LUT_LOG2_SIZE 257 +#define LUT_LORENZ_RATE 4 +#define LUT_LORENZ_RATE_SIZE 257 + +} // namespace streams + +#endif // STREAMS_RESOURCES_H_ diff --git a/lib/streams/svf.cc b/lib/streams/svf.cc new file mode 100644 index 0000000..3206e6c --- /dev/null +++ b/lib/streams/svf.cc @@ -0,0 +1,65 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// SVF used for modeling the bridged T-networks. + +#include "streams/svf.h" + +#include "stmlib/utils/dsp.h" + +#include "streams/resources.h" + +namespace streams { + +using namespace stmlib; + +void Svf::Init() { + lp_ = 0; + bp_ = 0; + frequency_ = 33 << 7; + resonance_ = 16384; + dirty_ = true; +} + +void Svf::Process(int32_t in) { + if (dirty_) { + f_ = Interpolate824(lut_svf_cutoff, frequency_ << 17); + damp_ = Interpolate824(lut_svf_damp, resonance_ << 17); + dirty_ = false; + } + int32_t f = f_; + int32_t damp = damp_; + int32_t notch = in - (bp_ * damp >> 15); + lp_ += f * bp_ >> 15; + CLIP(lp_) + hp_ = notch - lp_; + bp_ += f * hp_ >> 15; + CLIP(bp_) + CLIP(hp_) +} + + +} // namespace streams diff --git a/lib/streams/svf.h b/lib/streams/svf.h new file mode 100644 index 0000000..9806803 --- /dev/null +++ b/lib/streams/svf.h @@ -0,0 +1,76 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// SVF used for the envelope follower filter bank. + +#ifndef STREAMS_SVF_H_ +#define STREAMS_SVF_H_ + +#include "stmlib/stmlib.h" + +namespace streams { + +class Svf { + public: + Svf() { } + ~Svf() { } + + void Init(); + + void set_frequency(int16_t frequency) { + dirty_ = dirty_ || (frequency_ != frequency); + frequency_ = frequency; + } + + void set_resonance(int16_t resonance) { + resonance_ = resonance; + dirty_ = true; + } + + void Process(int32_t sample); + inline int32_t lp() const { return lp_; } + inline int32_t bp() const { return bp_; } + inline int32_t hp() const { return hp_; } + + private: + bool dirty_; + + int16_t frequency_; + int16_t resonance_; + + int32_t f_; + int32_t damp_; + + int32_t lp_; + int32_t bp_; + int32_t hp_; + + DISALLOW_COPY_AND_ASSIGN(Svf); +}; + +} // namespace streams + +#endif // STREAMS_SVF_H_ diff --git a/lib/streams/vactrol.cc b/lib/streams/vactrol.cc new file mode 100644 index 0000000..21ddce7 --- /dev/null +++ b/lib/streams/vactrol.cc @@ -0,0 +1,186 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Vactrol. + +#include "streams/vactrol.h" + +#include "stmlib/utils/dsp.h" + +#include "streams/gain.h" +#include "streams/resources.h" + +namespace streams { + +using namespace stmlib; + +void Vactrol::Init() { + state_[0] = 0; + state_[1] = 0; + state_[2] = 0; + state_[3] = 0; + + excite_ = 0; +} + +void Vactrol::Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency) { + // Smooth frequency amount parameters. + frequency_amount_ += (target_frequency_amount_ - frequency_amount_) >> 8; + frequency_offset_ += (target_frequency_offset_ - frequency_offset_) >> 8; + + int32_t input; + int32_t error; + int64_t coefficient = 0; + + if (excite < 0) { + excite = 0; + } + + // Simple plucked mode. + if (plucked_) { + if (gate_ == false) { + if (excite > kSchmittTriggerThreshold) { + gate_ = true; + state_[0] = 32767 << 16; + state_[1] = 32767 << 16; + } + } else { + if (excite < (kSchmittTriggerThreshold >> 1)) { + gate_ = false; + } + } + + // Filter the excitation pulses. + state_[0] -= static_cast( + state_[0]) * fast_decay_coefficient_ >> 31; + state_[1] -= static_cast( + state_[1]) * decay_coefficient_ >> 31; + + // VCF envelope. + error = state_[0] - state_[2]; + coefficient = error > 0 + ? fast_attack_coefficient_ : fast_decay_coefficient_; + state_[2] += static_cast(error) * coefficient >> 31; + + // VCA envelope. + error = state_[1] - state_[3]; + coefficient = error > 0 ? fast_attack_coefficient_ : decay_coefficient_; + // Increase the duration of the tail + int64_t strength = error > 0 ? error : -error; + coefficient = (coefficient >> 1) + (coefficient * strength >> 31); + state_[3] += static_cast(error) * coefficient >> 31; + + uint16_t vcf_amount = state_[2] >> 16; + uint16_t vca_mount = Interpolate1022(wav_gompertz, (state_[3] >> 2) * 3); + + *gain = kAboveUnityGain * vca_mount >> 15; + *frequency = frequency_offset_ + \ + (frequency_amount_ * vcf_amount >> 15); + + return; + } + + // Low-pass filter the negative edges to prevent fast pulse to immediately + // decay before the vactrol has started reacting. This allows the EXCITE + // input to be used for both controlling the vactrol or just plucking it + // from a trigger. + error = excite - excite_; + coefficient = error > 0 ? (1 << 30) : (decay_coefficient_ << 1); + excite_ += static_cast(error) * coefficient >> 31; + excite = excite_; + + input = frequency_offset_; + input += frequency_amount_ >> 1; + input = (65535 + input) >> 1; + input *= excite; + + state_[3] += static_cast(input - state_[3]) * 67976239 >> 31; + + error = input - state_[0]; + coefficient = 0; + if (error > 0) { + if (state_[1] > 0) { + coefficient = attack_coefficient_; + // Increase attack time when the photocell has been desensitized. + coefficient += coefficient * (255 - (state_[2] >> 23)) >> 6; + } else { + coefficient = fast_attack_coefficient_; + } + } else { + if (state_[1] < 0) { + coefficient = decay_coefficient_; + } else { + coefficient = fast_decay_coefficient_; + } + } + // First order. + state_[0] += static_cast(error) * coefficient >> 31; + + // Second order. + state_[1] += static_cast(error - state_[1]) * coefficient >> 31; + + // Memory effect. + int32_t sensitivity = state_[0]; + if (sensitivity > (1 << 28)) { + sensitivity = 1 << 31; + } else { + sensitivity <<= 3; + } + error = sensitivity - state_[2]; + if (error > 0) { + // Get into the "sensitized" state in 1s. + state_[2] += static_cast(error) * 138132 >> 31; + } else { + // Get out of the "sensitized" state in 60s. + state_[2] += static_cast(error) * 1151 >> 31; + } + + // Apply non-linearity. + int32_t index = state_[0] >> 1; + + // A little hack to add overshoot... + index += (state_[3] >> 15) * (state_[1] >> 15) >> 1; + if (index < 0) { + index = 0; + } else if (index >= (1 << 30)) { + index = (1 << 30) - 1; + } + uint16_t amplitude = index < 536870912 + ? Interpolate1022(wav_gompertz, static_cast(index) << 3) + : 32767; + uint16_t cutoff = index >> 14; + if (cutoff >= 32767) cutoff = 32767; + cutoff = cutoff * cutoff >> 15; + *gain = kAboveUnityGain * amplitude >> 15; + *frequency = frequency_offset_ + \ + (frequency_amount_ * cutoff >> 15); +} + +} // namespace streams diff --git a/lib/streams/vactrol.h b/lib/streams/vactrol.h new file mode 100644 index 0000000..81d9457 --- /dev/null +++ b/lib/streams/vactrol.h @@ -0,0 +1,139 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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 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. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Vactrol. + +#ifndef STREAMS_VACTROL_H_ +#define STREAMS_VACTROL_H_ + +#include "stmlib/stmlib.h" + +#include "streams/meta_parameters.h" +#include "streams/resources.h" + +namespace streams { + +class Vactrol { + public: + Vactrol() { } + ~Vactrol() { } + + void Init(); + void Process( + int16_t audio, + int16_t excite, + uint16_t* gain, + uint16_t* frequency); + + void Configure(bool alternate, int32_t* parameters, int32_t* globals) { + uint16_t attack_time; + uint16_t decay_time; + + if (globals) { + // Attack: 10ms to 1000ms + attack_time = 128 + (globals[0] >> 8); + // Decay: 10ms to 5000ms + decay_time = 128 + (globals[2] * 355 >> 16); + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + } else { + uint16_t shape = parameters[0]; + ComputeAmountOffset( + parameters[1], + &target_frequency_amount_, + &target_frequency_offset_); + + if (shape < 32768) { + // attack: 10ms + attack_time = 128; + // decay: 50ms to 2000ms + decay_time = 227 + (shape * 196 >> 15); + } else if (shape < 49512) { + shape -= 32768; + // attack: 10ms to 500ms. + attack_time = 128 + (shape * 227 >> 15); + // decay: 2000ms to 1000ms. + decay_time = 423 - (89 * shape >> 15); + } else { + shape -= 49512; + // attack: 500ms to 50ms. + attack_time = 355 - (shape >> 7); + // decay: 1000ms to 100ms. + decay_time = 384 - (128 * shape >> 15); + } + } + + attack_coefficient_ = lut_lp_coefficients[attack_time]; + fast_attack_coefficient_ = lut_lp_coefficients[attack_time - 128]; + decay_coefficient_ = lut_lp_coefficients[decay_time]; + fast_decay_coefficient_ = lut_lp_coefficients[decay_time - 128]; + + plucked_ = alternate; + if (alternate) { + fast_attack_coefficient_ <<= 4; + } else { + decay_coefficient_ >>= 1; + } + + int32_t ringing_tail = 8192; + int32_t headroom = 65535 - target_frequency_offset_; + if (ringing_tail > headroom) { + ringing_tail = headroom; + } + if (ringing_tail > target_frequency_amount_) { + ringing_tail = target_frequency_amount_; + } + + target_frequency_offset_ += ringing_tail; + target_frequency_amount_ -= ringing_tail; + } + + + private: + int32_t target_frequency_amount_; + int32_t target_frequency_offset_; + int32_t frequency_amount_; + int32_t frequency_offset_; + + int32_t attack_coefficient_; + int32_t decay_coefficient_; + int32_t fast_attack_coefficient_; + int32_t fast_decay_coefficient_; + + int32_t state_[4]; + int32_t excite_; + + bool gate_; + bool plucked_; + + DISALLOW_COPY_AND_ASSIGN(Vactrol); +}; + +} // namespace streams + +#endif // STREAMS_VACTROL_H_ diff --git a/lib/udynlink b/lib/udynlink index 7337f22..c8773d2 160000 --- a/lib/udynlink +++ b/lib/udynlink @@ -1 +1 @@ -Subproject commit 7337f22fd7995540b102cbe44fe6b4ffccd58200 +Subproject commit c8773d288f73285bd6eef0a72ecebc9716ad0f3d diff --git a/platformio.ini b/platformio.ini index c8cf4f9..03f42d8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,5 +9,5 @@ [env:squares-and-circles] apps_json = ./app/index.json -squares_and_circles_loader = 6e9bfa8 ; minimum loader version -platform = ./.pio/ +squares_and_circles_loader = 5e1e08e ; minimum loader version +platform = .pio/ \ No newline at end of file