| @@ -0,0 +1,7 @@ | |||
| Copyright (c) 2016 Andrew Belt | |||
| 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. | |||
| @@ -0,0 +1,80 @@ | |||
| ARCH ?= linux | |||
| CXXFLAGS = -MMD -fPIC -g -Wall -std=c++11 -O3 -ffast-math -DTEST \ | |||
| -I./src -I../../include -I./eurorack \ | |||
| -fasm \ | |||
| -finline \ | |||
| -fshort-enums | |||
| LDFLAGS = | |||
| SOURCES = $(wildcard src/*.cpp) \ | |||
| eurorack/stmlib/utils/random.cc \ | |||
| eurorack/stmlib/dsp/atan.cc \ | |||
| eurorack/stmlib/dsp/units.cc \ | |||
| eurorack/braids/macro_oscillator.cc \ | |||
| eurorack/braids/analog_oscillator.cc \ | |||
| eurorack/braids/digital_oscillator.cc \ | |||
| eurorack/braids/quantizer.cc \ | |||
| eurorack/braids/resources.cc \ | |||
| eurorack/clouds/dsp/correlator.cc \ | |||
| eurorack/clouds/dsp/granular_processor.cc \ | |||
| eurorack/clouds/dsp/mu_law.cc \ | |||
| eurorack/clouds/dsp/pvoc/frame_transformation.cc \ | |||
| eurorack/clouds/dsp/pvoc/phase_vocoder.cc \ | |||
| eurorack/clouds/dsp/pvoc/stft.cc \ | |||
| eurorack/clouds/resources.cc \ | |||
| eurorack/elements/dsp/exciter.cc \ | |||
| eurorack/elements/dsp/ominous_voice.cc \ | |||
| eurorack/elements/dsp/resonator.cc \ | |||
| eurorack/elements/dsp/tube.cc \ | |||
| eurorack/elements/dsp/multistage_envelope.cc \ | |||
| eurorack/elements/dsp/part.cc \ | |||
| eurorack/elements/dsp/string.cc \ | |||
| eurorack/elements/dsp/voice.cc \ | |||
| eurorack/elements/resources.cc \ | |||
| eurorack/rings/dsp/fm_voice.cc \ | |||
| eurorack/rings/dsp/part.cc \ | |||
| eurorack/rings/dsp/string_synth_part.cc \ | |||
| eurorack/rings/dsp/string.cc \ | |||
| eurorack/rings/dsp/resonator.cc \ | |||
| eurorack/rings/resources.cc \ | |||
| eurorack/tides/generator.cc \ | |||
| eurorack/tides/resources.cc \ | |||
| eurorack/warps/dsp/modulator.cc \ | |||
| eurorack/warps/dsp/oscillator.cc \ | |||
| eurorack/warps/dsp/vocoder.cc \ | |||
| eurorack/warps/dsp/filter_bank.cc \ | |||
| eurorack/warps/resources.cc | |||
| # Linux | |||
| ifeq ($(ARCH), linux) | |||
| CC = gcc | |||
| CXX = g++ | |||
| CXXFLAGS += -Wno-unused-local-typedefs | |||
| LDFLAGS += -shared | |||
| TARGET = plugin.so | |||
| endif | |||
| # Apple | |||
| ifeq ($(ARCH), apple) | |||
| CC = clang | |||
| CXX = clang++ | |||
| CXXFLAGS += -stdlib=libc++ | |||
| LDFLAGS += -stdlib=libc++ -shared -undefined dynamic_lookup | |||
| TARGET = plugin.dylib | |||
| endif | |||
| # Windows | |||
| ifeq ($(ARCH), windows) | |||
| CC = x86_64-w64-mingw32-gcc | |||
| CXX = x86_64-w64-mingw32-g++ | |||
| CXXFLAGS += -D_USE_MATH_DEFINES -Wno-unused-local-typedefs | |||
| SOURCES += | |||
| LDFLAGS += -shared -L../../ -lRack | |||
| TARGET = plugin.dll | |||
| endif | |||
| include ../../Makefile.inc | |||
| @@ -0,0 +1,46 @@ | |||
| # Audible Instruments | |||
| Ports of [Mutable Instruments](http://mutable-instruments.net/modules) modules to Virtuoso Rack | |||
| ## TODO | |||
| Percentages are progress amounts, X means won't port | |||
| [90%] Braids (Macro Oscillator) | |||
| - sample rate converter | |||
| [X] Edges (Chiptune Generator) | |||
| - GPL, will not port | |||
| [70%] Elements (Modal Synthesizer) | |||
| - fix weird audio stability bug | |||
| - sample rate converter | |||
| [100%] Tides (Tidal Modulator) | |||
| [X] Sheep (Wavetable Oscillator) | |||
| - based on Tides | |||
| - cannot find source, will not port | |||
| [0%] Peaks | |||
| [X] Ripples | |||
| - analog, will not port unless I buy/borrow one or someone contributes a technical model | |||
| [X] Shelves | |||
| - analog, will not port unless I buy/borrow one or someone contributes a technical model | |||
| [10%] Streams | |||
| - analog, but it's possible to fake the filter with schematic analysis | |||
| [70%] Clouds (Texture Synthesizer) | |||
| - edit buttons and lights | |||
| [100%] Warps (Meta Modulator) | |||
| [90%] Rings (Resonator) | |||
| - performance issue with first mode | |||
| [X] Grids (Drum Sequencer) | |||
| - GPL, will not port | |||
| [0%] Frames | |||
| [X] Yarns | |||
| - functionality covered by the MIDI Interface from core, will not port | |||
| [X] Ears | |||
| - a microphone, will not port | |||
| [100%] Links (Multiples) | |||
| [100%] Kinks (Utilities) | |||
| [100%] Shades (Mixer) | |||
| [100%] Branches (Bernoulli Gate) | |||
| [100%] Blinds (Quad VC-polarizer) | |||
| [100%] Veils (Quad VCA) | |||
| @@ -0,0 +1,48 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| void ValueLight::step() { | |||
| float v = getf(value); | |||
| if (v > 0) { | |||
| color = nvgHSL(0.36, 0.7, 0.7); | |||
| color.a = v; // May be larger than 1 | |||
| } | |||
| else if (v < 0) { | |||
| color = nvgHSL(0.0, 0.7, 0.7); | |||
| color.a = -v; | |||
| } | |||
| else { | |||
| color = nvgRGBAf(1.0, 1.0, 1.0, 0.0); | |||
| } | |||
| } | |||
| void ModeLight::step() { | |||
| int mode = (int) roundf(getf(value)); | |||
| switch (mode) { | |||
| case 0: color = nvgHSL(0.36, 0.7, 0.7); break; | |||
| case 1: color = nvgHSL(0.18, 0.7, 0.7); break; | |||
| case 2: color = nvgHSL(0.0, 0.7, 0.7); break; | |||
| default: color = nvgRGBAf(0.0, 0.0, 0.0, 0.0); break; | |||
| } | |||
| } | |||
| Plugin *init() { | |||
| Plugin *plugin = createPlugin("Audible Instruments", "Audible Instruments"); | |||
| createModel<BraidsWidget>(plugin, "Braids", "Macro Oscillator"); | |||
| createModel<ElementsWidget>(plugin, "Elements", "Modal Synthesizer"); | |||
| createModel<TidesWidget>(plugin, "Tides", "Tidal Modulator"); | |||
| // createModel<StreamsWidget>(plugin, "Streams", "Dual Dynamics Gate"); | |||
| createModel<CloudsWidget>(plugin, "Clouds", "Texture Synthesizer"); | |||
| createModel<WarpsWidget>(plugin, "Warps", "Meta Modulator"); | |||
| createModel<RingsWidget>(plugin, "Rings", "Resonator"); | |||
| createModel<LinksWidget>(plugin, "Links", "Multiples"); | |||
| createModel<KinksWidget>(plugin, "Kinks", "Utilities"); | |||
| createModel<ShadesWidget>(plugin, "Shades", "Mixer"); | |||
| createModel<BranchesWidget>(plugin, "Branches", "Bernoulli Gate"); | |||
| createModel<BlindsWidget>(plugin, "Blinds", "Quad VC-polarizer"); | |||
| createModel<VeilsWidget>(plugin, "Veils", "Quad VCA"); | |||
| return plugin; | |||
| } | |||
| @@ -0,0 +1,275 @@ | |||
| #include "Rack.hpp" | |||
| using namespace rack; | |||
| //////////////////// | |||
| // helpers | |||
| //////////////////// | |||
| struct AudiblePanel : ModulePanel { | |||
| AudiblePanel() { | |||
| backgroundColor = nvgRGBf(0.85, 0.85, 0.85); | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // knobs | |||
| //////////////////// | |||
| struct AudibleKnob : Knob { | |||
| AudibleKnob() { | |||
| minIndex = 44; | |||
| maxIndex = -46; | |||
| spriteCount = 120; | |||
| } | |||
| }; | |||
| struct HugeGlowKnob : AudibleKnob { | |||
| HugeGlowKnob() { | |||
| box.size = Vec(91, 91); | |||
| spriteOffset = Vec(-10, -9); | |||
| spriteSize = Vec(110, 110); | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_huge_glow.png"; | |||
| minIndex = 44+5; | |||
| maxIndex = -46-5; | |||
| } | |||
| }; | |||
| struct LargeKnob : AudibleKnob { | |||
| LargeKnob() { | |||
| box.size = Vec(52, 52); | |||
| spriteOffset = Vec(-5, -4); | |||
| spriteSize = Vec(65, 66); | |||
| } | |||
| }; | |||
| struct LargeWhiteKnob : LargeKnob { | |||
| LargeWhiteKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_large_white.png"; | |||
| } | |||
| }; | |||
| struct LargeRedKnob : LargeKnob { | |||
| LargeRedKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_large_red.png"; | |||
| } | |||
| }; | |||
| struct LargeGreenKnob : LargeKnob { | |||
| LargeGreenKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_large_green.png"; | |||
| } | |||
| }; | |||
| struct MediumKnob : AudibleKnob { | |||
| MediumKnob() { | |||
| box.size = Vec(44, 44); | |||
| spriteOffset = Vec(-5, -4); | |||
| spriteSize = Vec(57, 58); | |||
| } | |||
| }; | |||
| struct MediumWhiteKnob : MediumKnob { | |||
| MediumWhiteKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_medium_white.png"; | |||
| } | |||
| }; | |||
| struct MediumRedKnob : MediumKnob { | |||
| MediumRedKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_medium_red.png"; | |||
| } | |||
| }; | |||
| struct MediumGreenKnob : MediumKnob { | |||
| MediumGreenKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_medium_green.png"; | |||
| } | |||
| }; | |||
| struct SmallKnob : AudibleKnob { | |||
| SmallKnob() { | |||
| box.size = Vec(40, 40); | |||
| spriteOffset = Vec(-5, -4); | |||
| spriteSize = Vec(53, 54); | |||
| } | |||
| }; | |||
| struct SmallWhiteKnob : SmallKnob { | |||
| SmallWhiteKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_small_white.png"; | |||
| } | |||
| }; | |||
| struct SmallRedKnob : SmallKnob { | |||
| SmallRedKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_small_red.png"; | |||
| } | |||
| }; | |||
| struct SmallGreenKnob : SmallKnob { | |||
| SmallGreenKnob() { | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_small_green.png"; | |||
| } | |||
| }; | |||
| struct TinyBlackKnob : AudibleKnob { | |||
| TinyBlackKnob() { | |||
| box.size = Vec(18, 18); | |||
| spriteOffset = Vec(-5, -3); | |||
| spriteSize = Vec(31, 30); | |||
| spriteFilename = "plugins/AudibleInstruments/res/knob_tiny_black.png"; | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // switches | |||
| //////////////////// | |||
| struct LargeSwitch : virtual Switch { | |||
| LargeSwitch() { | |||
| box.size = Vec(27, 27); | |||
| spriteOffset = Vec(-3, -2); | |||
| spriteSize = Vec(36, 36); | |||
| spriteFilename = "plugins/AudibleInstruments/res/button_large_black.png"; | |||
| } | |||
| }; | |||
| struct MediumSwitch : virtual Switch { | |||
| MediumSwitch() { | |||
| box.size = Vec(15, 15); | |||
| spriteOffset = Vec(-4, -2); | |||
| spriteSize = Vec(25, 25); | |||
| spriteFilename = "plugins/AudibleInstruments/res/button_medium_black.png"; | |||
| } | |||
| }; | |||
| struct LargeMomentarySwitch : LargeSwitch, MomentarySwitch {}; | |||
| struct MediumMomentarySwitch : MediumSwitch, MomentarySwitch {}; | |||
| struct LargeToggleSwitch : LargeSwitch, ToggleSwitch {}; | |||
| struct MediumToggleSwitch : MediumSwitch, ToggleSwitch {}; | |||
| struct SlideSwitch : Switch { | |||
| SlideSwitch() { | |||
| box.size = Vec(11, 21); | |||
| spriteOffset = Vec(-1, -1); | |||
| spriteSize = Vec(12, 22); | |||
| spriteFilename = "plugins/AudibleInstruments/res/slide_switch.png"; | |||
| } | |||
| void step() { | |||
| index = (value == minValue) ? 0 : 1; | |||
| } | |||
| void onDragDrop(Widget *origin) { | |||
| if (origin != this) | |||
| return; | |||
| if (value == minValue) { | |||
| setValue(maxValue); | |||
| } | |||
| else { | |||
| setValue(minValue); | |||
| } | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // lights | |||
| //////////////////// | |||
| struct ValueLight : virtual Light { | |||
| float *value = NULL; | |||
| void step(); | |||
| }; | |||
| struct ModeLight : ValueLight { | |||
| void step(); | |||
| }; | |||
| struct SmallLight : virtual Light { | |||
| SmallLight() { | |||
| box.size = Vec(7, 7); | |||
| spriteOffset = Vec(-16, -16); | |||
| spriteSize = Vec(38, 38); | |||
| spriteFilename = "plugins/AudibleInstruments/res/light_small.png"; | |||
| } | |||
| }; | |||
| struct MediumLight : virtual Light { | |||
| MediumLight() { | |||
| box.size = Vec(14, 14); | |||
| spriteOffset = Vec(-16, -15); | |||
| spriteSize = Vec(45, 45); | |||
| spriteFilename = "plugins/AudibleInstruments/res/light_medium.png"; | |||
| } | |||
| }; | |||
| struct SmallValueLight : SmallLight, ValueLight {}; | |||
| struct MediumValueLight : MediumLight, ValueLight {}; | |||
| struct SmallModeLight : SmallLight, ModeLight {}; | |||
| template <class TLight> | |||
| ValueLight *createValueLight(Vec pos, float *value) { | |||
| ValueLight *light = new TLight(); | |||
| light->box.pos = pos; | |||
| light->value = value; | |||
| return light; | |||
| } | |||
| //////////////////// | |||
| // module widgets | |||
| //////////////////// | |||
| struct BraidsWidget : ModuleWidget { | |||
| BraidsWidget(); | |||
| }; | |||
| struct ElementsWidget : ModuleWidget { | |||
| ElementsWidget(); | |||
| }; | |||
| struct TidesWidget : ModuleWidget { | |||
| TidesWidget(); | |||
| }; | |||
| struct StreamsWidget : ModuleWidget { | |||
| StreamsWidget(); | |||
| }; | |||
| struct CloudsWidget : ModuleWidget { | |||
| CloudsWidget(); | |||
| }; | |||
| struct WarpsWidget : ModuleWidget { | |||
| WarpsWidget(); | |||
| }; | |||
| struct RingsWidget : ModuleWidget { | |||
| RingsWidget(); | |||
| }; | |||
| struct LinksWidget : ModuleWidget { | |||
| LinksWidget(); | |||
| }; | |||
| struct KinksWidget : ModuleWidget { | |||
| KinksWidget(); | |||
| }; | |||
| struct ShadesWidget : ModuleWidget { | |||
| ShadesWidget(); | |||
| }; | |||
| struct BranchesWidget : ModuleWidget { | |||
| BranchesWidget(); | |||
| }; | |||
| struct BlindsWidget : ModuleWidget { | |||
| BlindsWidget(); | |||
| }; | |||
| struct VeilsWidget : ModuleWidget { | |||
| VeilsWidget(); | |||
| }; | |||
| @@ -0,0 +1,137 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| struct Blinds : Module { | |||
| enum ParamIds { | |||
| GAIN1_PARAM, | |||
| GAIN2_PARAM, | |||
| GAIN3_PARAM, | |||
| GAIN4_PARAM, | |||
| MOD1_PARAM, | |||
| MOD2_PARAM, | |||
| MOD3_PARAM, | |||
| MOD4_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| IN1_INPUT, | |||
| IN2_INPUT, | |||
| IN3_INPUT, | |||
| IN4_INPUT, | |||
| CV1_INPUT, | |||
| CV2_INPUT, | |||
| CV3_INPUT, | |||
| CV4_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT1_OUTPUT, | |||
| OUT2_OUTPUT, | |||
| OUT3_OUTPUT, | |||
| OUT4_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| float lights[4] = {}; | |||
| float gainLights[4] = {}; | |||
| Blinds(); | |||
| void step(); | |||
| }; | |||
| Blinds::Blinds() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| static float getChannelOutput(const float *in, float gain, const float *cv, float mod, float *light) { | |||
| gain += mod * getf(cv) / 5.0; | |||
| *light = gain * 5.0; | |||
| return gain * getf(in, 5.0); | |||
| } | |||
| void Blinds::step() { | |||
| float out = 0.0; | |||
| out += getChannelOutput(inputs[IN1_INPUT], params[GAIN1_PARAM], inputs[CV1_INPUT], params[MOD1_PARAM], &gainLights[0]); | |||
| lights[0] = out; | |||
| if (outputs[OUT1_OUTPUT]) { | |||
| *outputs[OUT1_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN2_INPUT], params[GAIN2_PARAM], inputs[CV2_INPUT], params[MOD2_PARAM], &gainLights[1]); | |||
| lights[1] = out; | |||
| if (outputs[OUT2_OUTPUT]) { | |||
| *outputs[OUT2_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN3_INPUT], params[GAIN3_PARAM], inputs[CV3_INPUT], params[MOD3_PARAM], &gainLights[2]); | |||
| lights[2] = out; | |||
| if (outputs[OUT3_OUTPUT]) { | |||
| *outputs[OUT3_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN4_INPUT], params[GAIN4_PARAM], inputs[CV4_INPUT], params[MOD4_PARAM], &gainLights[3]); | |||
| lights[3] = out; | |||
| if (outputs[OUT4_OUTPUT]) { | |||
| *outputs[OUT4_OUTPUT] = out; | |||
| } | |||
| } | |||
| BlindsWidget::BlindsWidget() : ModuleWidget(new Blinds()) { | |||
| box.size = Vec(15*12, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Blinds.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(150, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(150, 365))); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 52), module, Blinds::GAIN1_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 131), module, Blinds::GAIN2_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 210), module, Blinds::GAIN3_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 288), module, Blinds::GAIN4_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 63), module, Blinds::MOD1_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 142), module, Blinds::MOD2_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 221), module, Blinds::MOD3_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 300), module, Blinds::MOD4_PARAM, -1.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(112, 43), module, Blinds::IN1_INPUT)); | |||
| addInput(createInput(Vec(112, 122), module, Blinds::IN2_INPUT)); | |||
| addInput(createInput(Vec(112, 200), module, Blinds::IN3_INPUT)); | |||
| addInput(createInput(Vec(112, 279), module, Blinds::IN4_INPUT)); | |||
| addInput(createInput(Vec(112, 82), module, Blinds::CV1_INPUT)); | |||
| addInput(createInput(Vec(112, 161), module, Blinds::CV2_INPUT)); | |||
| addInput(createInput(Vec(112, 240), module, Blinds::CV3_INPUT)); | |||
| addInput(createInput(Vec(112, 318), module, Blinds::CV4_INPUT)); | |||
| addOutput(createOutput(Vec(146, 43), module, Blinds::OUT1_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 122), module, Blinds::OUT2_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 200), module, Blinds::OUT3_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 279), module, Blinds::OUT4_OUTPUT)); | |||
| Blinds *blinds = dynamic_cast<Blinds*>(module); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 86), &blinds->lights[0])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 165), &blinds->lights[1])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 244), &blinds->lights[2])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 323), &blinds->lights[3])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(78, 97), &blinds->gainLights[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(78, 176), &blinds->gainLights[1])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(78, 255), &blinds->gainLights[2])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(78, 334), &blinds->gainLights[3])); | |||
| } | |||
| @@ -0,0 +1,197 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| #include "braids/macro_oscillator.h" | |||
| struct Braids : Module { | |||
| enum ParamIds { | |||
| FINE_PARAM, | |||
| COARSE_PARAM, | |||
| FM_PARAM, | |||
| TIMBRE_PARAM, | |||
| MODULATION_PARAM, | |||
| COLOR_PARAM, | |||
| SHAPE_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| TRIG_INPUT, | |||
| PITCH_INPUT, | |||
| FM_INPUT, | |||
| TIMBRE_INPUT, | |||
| COLOR_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| braids::MacroOscillator *osc; | |||
| int bufferFrame = 0; | |||
| int16_t buffer[24] = {}; | |||
| bool lastTrig = false; | |||
| Braids(); | |||
| ~Braids(); | |||
| void step(); | |||
| void setShape(int shape); | |||
| }; | |||
| Braids::Braids() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| osc = new braids::MacroOscillator(); | |||
| memset(osc, 0, sizeof(*osc)); | |||
| osc->Init(); | |||
| } | |||
| Braids::~Braids() { | |||
| delete osc; | |||
| } | |||
| void Braids::step() { | |||
| // TODO Sample rate convert from 96000Hz | |||
| setf(outputs[OUT_OUTPUT], 5.0*(buffer[bufferFrame] / 32768.0)); | |||
| // Trigger | |||
| bool trig = getf(inputs[TRIG_INPUT]) >= 1.0; | |||
| if (!lastTrig && trig) { | |||
| osc->Strike(); | |||
| } | |||
| lastTrig = trig; | |||
| if (++bufferFrame >= 24) { | |||
| bufferFrame = 0; | |||
| // Set shape | |||
| int shape = roundf(params[SHAPE_PARAM]); | |||
| osc->set_shape((braids::MacroOscillatorShape) shape); | |||
| // Set timbre/modulation | |||
| float timbre = params[TIMBRE_PARAM] + params[MODULATION_PARAM] * getf(inputs[TIMBRE_INPUT]) / 5.0; | |||
| float modulation = params[COLOR_PARAM] + getf(inputs[COLOR_INPUT]) / 5.0; | |||
| int16_t param1 = mapf(clampf(timbre, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX); | |||
| int16_t param2 = mapf(clampf(modulation, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX); | |||
| osc->set_parameters(param1, param2); | |||
| // Set pitch | |||
| float pitch = getf(inputs[PITCH_INPUT]) + params[COARSE_PARAM] + params[FINE_PARAM] / 12.0 + params[FM_PARAM] * getf(inputs[FM_INPUT]); | |||
| int16_t p = clampf((pitch * 12.0 + 60) * 128, 0, INT16_MAX); | |||
| osc->set_pitch(p); | |||
| uint8_t sync_buffer[24] = {}; | |||
| osc->Render(sync_buffer, buffer, 24); | |||
| } | |||
| } | |||
| static const char *algo_values[] = { | |||
| "CSAW", | |||
| "/\\-_", | |||
| "//-_", | |||
| "FOLD", | |||
| "uuuu", | |||
| "SYN-", | |||
| "SYN/", | |||
| "//x3", | |||
| "-_x3", | |||
| "/\\x3", | |||
| "SIx3", | |||
| "RING", | |||
| "////", | |||
| "//uu", | |||
| "TOY*", | |||
| "ZLPF", | |||
| "ZPKF", | |||
| "ZBPF", | |||
| "ZHPF", | |||
| "VOSM", | |||
| "VOWL", | |||
| "VFOF", | |||
| "HARM", | |||
| "FM ", | |||
| "FBFM", | |||
| "WTFM", | |||
| "PLUK", | |||
| "BOWD", | |||
| "BLOW", | |||
| "FLUT", | |||
| "BELL", | |||
| "DRUM", | |||
| "KICK", | |||
| "CYMB", | |||
| "SNAR", | |||
| "WTBL", | |||
| "WMAP", | |||
| "WLIN", | |||
| "WTx4", | |||
| "NOIS", | |||
| "TWNQ", | |||
| "CLKN", | |||
| "CLOU", | |||
| "PRTC", | |||
| "QPSK", | |||
| " ", | |||
| }; | |||
| struct BraidsDisplay : TransparentWidget { | |||
| float *value; | |||
| void draw(NVGcontext *vg) { | |||
| int shape = roundf(getf(value)); | |||
| int font = loadFont("plugins/AudibleInstruments/res/hdad-segment14-1.002/Segment14.ttf"); | |||
| nvgFontSize(vg, 36); | |||
| nvgFontFaceId(vg, font); | |||
| nvgTextLetterSpacing(vg, 2.5); | |||
| NVGcolor color = nvgRGB(0xaf, 0xd2, 0x2c); | |||
| nvgFillColor(vg, nvgTransRGBA(color, 16)); | |||
| nvgText(vg, box.pos.x, box.pos.y, "~~~~", NULL); | |||
| nvgFillColor(vg, color); | |||
| nvgText(vg, box.pos.x, box.pos.y, algo_values[shape], NULL); | |||
| } | |||
| }; | |||
| BraidsWidget::BraidsWidget() : ModuleWidget(new Braids()) { | |||
| box.size = Vec(15*16, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Braids.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| { | |||
| BraidsDisplay *display = new BraidsDisplay(); | |||
| display->box.pos = Vec(24, 101); | |||
| display->value = &module->params[Braids::SHAPE_PARAM]; | |||
| addChild(display); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(210, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(210, 365))); | |||
| addParam(createParam<MediumWhiteKnob>(Vec(187-10, 71-11), module, Braids::SHAPE_PARAM, 0.0, braids::MACRO_OSC_SHAPE_LAST-2, 0.0)); | |||
| addParam(createParam<MediumWhiteKnob>(Vec(30-10, 150-11), module, Braids::FINE_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<MediumWhiteKnob>(Vec(108-10, 150-11), module, Braids::COARSE_PARAM, -2.0, 2.0, 0.0)); | |||
| addParam(createParam<MediumWhiteKnob>(Vec(187-10, 150-11), module, Braids::FM_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<MediumGreenKnob>(Vec(30-10, 229-11), module, Braids::TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<MediumGreenKnob>(Vec(108-10, 229-11), module, Braids::MODULATION_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<MediumRedKnob>(Vec(187-10, 229-11), module, Braids::COLOR_PARAM, 0.0, 1.0, 0.5)); | |||
| addInput(createInput(Vec(12, 318), module, Braids::TRIG_INPUT)); | |||
| addInput(createInput(Vec(50, 318), module, Braids::PITCH_INPUT)); | |||
| addInput(createInput(Vec(87, 318), module, Braids::FM_INPUT)); | |||
| addInput(createInput(Vec(125, 318), module, Braids::TIMBRE_INPUT)); | |||
| addInput(createInput(Vec(162, 318), module, Braids::COLOR_INPUT)); | |||
| addOutput(createOutput(Vec(207, 318), module, Braids::OUT_OUTPUT)); | |||
| } | |||
| @@ -0,0 +1,106 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| struct Branches : Module { | |||
| enum ParamIds { | |||
| THRESHOLD1_PARAM, | |||
| THRESHOLD2_PARAM, | |||
| MODE1_PARAM, | |||
| MODE2_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| IN1_INPUT, | |||
| P1_INPUT, | |||
| IN2_INPUT, | |||
| P2_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT1A_OUTPUT, | |||
| OUT1B_OUTPUT, | |||
| OUT2A_OUTPUT, | |||
| OUT2B_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| bool lastGate[2] = {}; | |||
| bool outcome[2] = {}; | |||
| float light[2] = {}; | |||
| Branches(); | |||
| void step(); | |||
| float getOutput(int outputId); | |||
| }; | |||
| Branches::Branches() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| static void computeChannel(const float *in, const float *p, float threshold, float mode, bool *lastGate, bool *outcome, float *out1, float *out2, float *light) { | |||
| float out = getf(in); | |||
| bool gate = (out >= 1.0); | |||
| if (gate && !*lastGate) { | |||
| // trigger | |||
| std::uniform_real_distribution<float> dist(0.0, 1.0); | |||
| bool toss = (dist(rng) < threshold + getf(p)); | |||
| if (mode < 0.5) { | |||
| // direct mode | |||
| *outcome = toss; | |||
| } | |||
| else { | |||
| // toggle mode | |||
| *outcome = *outcome != toss; | |||
| } | |||
| } | |||
| *lastGate = gate; | |||
| *light = *outcome ? out : -out; | |||
| if (out1) { | |||
| *out1 = *outcome ? 0.0 : out; | |||
| } | |||
| if (out2) { | |||
| *out2 = *outcome ? out : 0.0; | |||
| } | |||
| } | |||
| void Branches::step() { | |||
| computeChannel(inputs[IN1_INPUT], inputs[P1_INPUT], params[THRESHOLD1_PARAM], params[MODE1_PARAM], &lastGate[0], &outcome[0], outputs[OUT1A_OUTPUT], outputs[OUT1B_OUTPUT], &light[0]); | |||
| computeChannel(inputs[IN2_INPUT], inputs[P2_INPUT], params[THRESHOLD2_PARAM], params[MODE2_PARAM], &lastGate[1], &outcome[1], outputs[OUT2A_OUTPUT], outputs[OUT2B_OUTPUT], &light[1]); | |||
| } | |||
| BranchesWidget::BranchesWidget() : ModuleWidget(new Branches()) { | |||
| box.size = Vec(15*6, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Branches.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addParam(createParam<SmallRedKnob>(Vec(44-20, 84-20), module, Branches::THRESHOLD1_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<MediumToggleSwitch>(Vec(69, 58), module, Branches::MODE1_PARAM, 0.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(11, 125-1), module, Branches::IN1_INPUT)); | |||
| addInput(createInput(Vec(58, 125-1), module, Branches::P1_INPUT)); | |||
| addOutput(createOutput(Vec(11, 163-1), module, Branches::OUT1A_OUTPUT)); | |||
| addOutput(createOutput(Vec(58, 163-1), module, Branches::OUT1B_OUTPUT)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(44-20, 240-20), module, Branches::THRESHOLD2_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<MediumToggleSwitch>(Vec(69, 214), module, Branches::MODE2_PARAM, 0.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(11, 281-1), module, Branches::IN2_INPUT)); | |||
| addInput(createInput(Vec(58, 281-1), module, Branches::P2_INPUT)); | |||
| addOutput(createOutput(Vec(11, 319-1), module, Branches::OUT2A_OUTPUT)); | |||
| addOutput(createOutput(Vec(58, 319-1), module, Branches::OUT2B_OUTPUT)); | |||
| Branches *branches = dynamic_cast<Branches*>(module); | |||
| addChild(createValueLight<SmallValueLight>(Vec(42, 170), &branches->light[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(42, 326), &branches->light[1])); | |||
| } | |||
| @@ -0,0 +1,168 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| #include "clouds/dsp/granular_processor.h" | |||
| struct Clouds : Module { | |||
| enum ParamIds { | |||
| POSITION_PARAM, | |||
| SIZE_PARAM, | |||
| PITCH_PARAM, | |||
| IN_GAIN_PARAM, | |||
| DENSITY_PARAM, | |||
| TEXTURE_PARAM, | |||
| BLEND_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| FREEZE_INPUT, | |||
| TRIG_INPUT, | |||
| POSITION_INPUT, | |||
| SIZE_INPUT, | |||
| PITCH_INPUT, | |||
| BLEND_INPUT, | |||
| IN_L_INPUT, | |||
| IN_R_INPUT, | |||
| DENSITY_INPUT, | |||
| TEXTURE_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT_L_OUTPUT, | |||
| OUT_R_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| uint8_t *block_mem; | |||
| uint8_t *block_ccm; | |||
| clouds::GranularProcessor *processor; | |||
| int bufferFrame = 0; | |||
| float inL[32] = {}; | |||
| float inR[32] = {}; | |||
| float outL[32] = {}; | |||
| float outR[32] = {}; | |||
| bool triggered = false; | |||
| Clouds(); | |||
| ~Clouds(); | |||
| void step(); | |||
| }; | |||
| Clouds::Clouds() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| const int memLen = 118784; | |||
| const int ccmLen = 65536 - 128; | |||
| block_mem = new uint8_t[memLen]; | |||
| memset(block_mem, 0, memLen); | |||
| block_ccm = new uint8_t[ccmLen]; | |||
| memset(block_ccm, 0, ccmLen); | |||
| processor = new clouds::GranularProcessor(); | |||
| memset(processor, 0, sizeof(*processor)); | |||
| processor->Init(block_mem, memLen, block_ccm, ccmLen); | |||
| } | |||
| Clouds::~Clouds() { | |||
| delete processor; | |||
| delete[] block_mem; | |||
| delete[] block_ccm; | |||
| } | |||
| void Clouds::step() { | |||
| // TODO Sample rate conversion from 32000 Hz | |||
| inL[bufferFrame] = getf(inputs[IN_L_INPUT]); | |||
| inR[bufferFrame] = getf(inputs[IN_R_INPUT]); | |||
| setf(outputs[OUT_L_OUTPUT], outL[bufferFrame]); | |||
| setf(outputs[OUT_R_OUTPUT], outR[bufferFrame]); | |||
| // Trigger | |||
| if (getf(inputs[TRIG_INPUT]) >= 1.0) { | |||
| triggered = true; | |||
| } | |||
| if (++bufferFrame >= 32) { | |||
| bufferFrame = 0; | |||
| processor->set_num_channels(2); | |||
| processor->set_low_fidelity(false); | |||
| processor->set_playback_mode(clouds::PLAYBACK_MODE_GRANULAR); | |||
| processor->Prepare(); | |||
| clouds::Parameters* p = processor->mutable_parameters(); | |||
| p->trigger = triggered; | |||
| p->freeze = (getf(inputs[FREEZE_INPUT]) >= 1.0); | |||
| p->position = clampf(params[POSITION_PARAM] + getf(inputs[POSITION_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->size = clampf(params[SIZE_PARAM] + getf(inputs[SIZE_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->pitch = clampf((params[PITCH_PARAM] + getf(inputs[PITCH_INPUT])) * 12.0, -48.0, 48.0); | |||
| p->density = clampf(params[DENSITY_PARAM] + getf(inputs[DENSITY_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->texture = clampf(params[TEXTURE_PARAM] + getf(inputs[TEXTURE_INPUT]) / 5.0, 0.0, 1.0); | |||
| float blend = clampf(params[BLEND_PARAM] + getf(inputs[BLEND_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->dry_wet = blend; | |||
| p->stereo_spread = 0.0f; | |||
| p->feedback = 0.0f; | |||
| p->reverb = 0.0f; | |||
| clouds::ShortFrame input[32]; | |||
| clouds::ShortFrame output[32]; | |||
| for (int j = 0; j < 32; j++) { | |||
| input[j].l = clampf(inL[j] * params[IN_GAIN_PARAM] / 5.0, -1.0, 1.0) * 32767; | |||
| input[j].r = clampf(inR[j] * params[IN_GAIN_PARAM] / 5.0, -1.0, 1.0) * 32767; | |||
| } | |||
| processor->Process(input, output, 32); | |||
| for (int j = 0; j < 32; j++) { | |||
| outL[j] = (float)output[j].l / 32767 * 5.0; | |||
| outR[j] = (float)output[j].r / 32767 * 5.0; | |||
| } | |||
| triggered = false; | |||
| } | |||
| } | |||
| CloudsWidget::CloudsWidget() : ModuleWidget(new Clouds()) { | |||
| box.size = Vec(15*18, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Clouds.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(240, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(240, 365))); | |||
| // TODO | |||
| // addParam(createParam<MediumMomentarySwitch>(Vec(211, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); | |||
| // addParam(createParam<MediumMomentarySwitch>(Vec(239, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeRedKnob>(Vec(42-14, 108-14), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeGreenKnob>(Vec(123-14, 108-14), module, Clouds::SIZE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeWhiteKnob>(Vec(205-14, 108-14), module, Clouds::PITCH_PARAM, -2.0, 2.0, 0.0)); | |||
| addParam(createParam<SmallRedKnob>(Vec(25-10, 191-10), module, Clouds::IN_GAIN_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallRedKnob>(Vec(92-10, 191-10), module, Clouds::DENSITY_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(157-10, 191-10), module, Clouds::TEXTURE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(224-10, 191-10), module, Clouds::BLEND_PARAM, 0.0, 1.0, 0.5)); | |||
| addInput(createInput(Vec(17, 275), module, Clouds::FREEZE_INPUT)); | |||
| addInput(createInput(Vec(60, 275), module, Clouds::TRIG_INPUT)); | |||
| addInput(createInput(Vec(103, 275), module, Clouds::POSITION_INPUT)); | |||
| addInput(createInput(Vec(146, 275), module, Clouds::SIZE_INPUT)); | |||
| addInput(createInput(Vec(190, 275), module, Clouds::PITCH_INPUT)); | |||
| addInput(createInput(Vec(233, 275), module, Clouds::BLEND_INPUT)); | |||
| addInput(createInput(Vec(17, 318), module, Clouds::IN_L_INPUT)); | |||
| addInput(createInput(Vec(60, 318), module, Clouds::IN_R_INPUT)); | |||
| addInput(createInput(Vec(103, 318), module, Clouds::DENSITY_INPUT)); | |||
| addInput(createInput(Vec(146, 318), module, Clouds::TEXTURE_INPUT)); | |||
| addOutput(createOutput(Vec(190, 318), module, Clouds::OUT_L_OUTPUT)); | |||
| addOutput(createOutput(Vec(233, 318), module, Clouds::OUT_R_OUTPUT)); | |||
| } | |||
| @@ -0,0 +1,222 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| #include "elements/dsp/part.h" | |||
| struct Elements : Module { | |||
| enum ParamIds { | |||
| CONTOUR_PARAM, | |||
| BOW_PARAM, | |||
| BLOW_PARAM, | |||
| STRIKE_PARAM, | |||
| COARSE_PARAM, | |||
| FINE_PARAM, | |||
| FM_PARAM, | |||
| FLOW_PARAM, | |||
| MALLET_PARAM, | |||
| GEOMETRY_PARAM, | |||
| BRIGHTNESS_PARAM, | |||
| BOW_TIMBRE_PARAM, | |||
| BLOW_TIMBRE_PARAM, | |||
| STRIKE_TIMBRE_PARAM, | |||
| DAMPING_PARAM, | |||
| POSITION_PARAM, | |||
| SPACE_PARAM, | |||
| BOW_TIMBRE_MOD_PARAM, | |||
| FLOW_MOD_PARAM, | |||
| BLOW_TIMBRE_MOD_PARAM, | |||
| MALLET_MOD_PARAM, | |||
| STRIKE_TIMBRE_MOD_PARAM, | |||
| DAMPING_MOD_PARAM, | |||
| GEOMETRY_MOD_PARAM, | |||
| POSITION_MOD_PARAM, | |||
| BRIGHTNESS_MOD_PARAM, | |||
| SPACE_MOD_PARAM, | |||
| PLAY_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| NOTE_INPUT, | |||
| FM_INPUT, | |||
| GATE_INPUT, | |||
| STRENGTH_INPUT, | |||
| BLOW_INPUT, | |||
| STRIKE_INPUT, | |||
| BOW_TIMBRE_MOD_INPUT, | |||
| FLOW_MOD_INPUT, | |||
| BLOW_TIMBRE_MOD_INPUT, | |||
| MALLET_MOD_INPUT, | |||
| STRIKE_TIMBRE_MOD_INPUT, | |||
| DAMPING_MOD_INPUT, | |||
| GEOMETRY_MOD_INPUT, | |||
| POSITION_MOD_INPUT, | |||
| BRIGHTNESS_MOD_INPUT, | |||
| SPACE_MOD_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| AUX_OUTPUT, | |||
| MAIN_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| uint16_t reverb_buffer[32768] = {}; | |||
| elements::Part *part; | |||
| int bufferFrame = 0; | |||
| float blow[16] = {}; | |||
| float strike[16] = {}; | |||
| float main[16] = {}; | |||
| float aux[16] = {}; | |||
| float lights[2] = {}; | |||
| Elements(); | |||
| ~Elements(); | |||
| void step(); | |||
| }; | |||
| Elements::Elements() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| part = new elements::Part(); | |||
| // In the Mutable Instruments code, Part doesn't initialize itself, so zero it here. | |||
| memset(part, 0, sizeof(*part)); | |||
| part->Init(reverb_buffer); | |||
| // Just some random numbers | |||
| uint32_t seed[3] = {1, 2, 3}; | |||
| part->Seed(seed, 3); | |||
| } | |||
| Elements::~Elements() { | |||
| delete part; | |||
| } | |||
| void Elements::step() { | |||
| // TODO Sample rate convert from 32000Hz | |||
| blow[bufferFrame] = getf(inputs[BLOW_INPUT]); | |||
| strike[bufferFrame] = getf(inputs[STRIKE_INPUT]); | |||
| setf(outputs[AUX_OUTPUT], 5.0*aux[bufferFrame]); | |||
| setf(outputs[MAIN_OUTPUT], 5.0*main[bufferFrame]); | |||
| if (++bufferFrame >= 16) { | |||
| bufferFrame = 0; | |||
| // Set patch from parameters | |||
| elements::Patch* p = part->mutable_patch(); | |||
| p->exciter_envelope_shape = params[CONTOUR_PARAM]; | |||
| p->exciter_bow_level = params[BOW_PARAM]; | |||
| p->exciter_blow_level = params[BLOW_PARAM]; | |||
| p->exciter_strike_level = params[STRIKE_PARAM]; | |||
| #define BIND(_p, _m, _i) clampf(params[_p] + 3.3*quadraticBipolar(params[_m])*getf(inputs[_i])/5.0, 0.0, 0.9995) | |||
| p->exciter_bow_timbre = BIND(BOW_TIMBRE_PARAM, BOW_TIMBRE_MOD_PARAM, BOW_TIMBRE_MOD_INPUT); | |||
| p->exciter_blow_meta = BIND(FLOW_PARAM, FLOW_MOD_PARAM, FLOW_MOD_INPUT); | |||
| p->exciter_blow_timbre = BIND(BLOW_TIMBRE_PARAM, BLOW_TIMBRE_MOD_PARAM, BLOW_TIMBRE_MOD_INPUT); | |||
| p->exciter_strike_meta = BIND(MALLET_PARAM, MALLET_MOD_PARAM, MALLET_MOD_INPUT); | |||
| p->exciter_strike_timbre = BIND(STRIKE_TIMBRE_PARAM, STRIKE_TIMBRE_MOD_PARAM, STRIKE_TIMBRE_MOD_INPUT); | |||
| p->resonator_geometry = BIND(GEOMETRY_PARAM, GEOMETRY_MOD_PARAM, GEOMETRY_MOD_INPUT); | |||
| p->resonator_brightness = BIND(BRIGHTNESS_PARAM, BRIGHTNESS_MOD_PARAM, BRIGHTNESS_MOD_INPUT); | |||
| p->resonator_damping = BIND(DAMPING_PARAM, DAMPING_MOD_PARAM, DAMPING_MOD_INPUT); | |||
| p->resonator_position = BIND(POSITION_PARAM, POSITION_MOD_PARAM, POSITION_MOD_INPUT); | |||
| p->space = clampf(params[SPACE_PARAM] + params[SPACE_MOD_PARAM]*getf(inputs[SPACE_MOD_INPUT])/5.0, 0.0, 2.0); | |||
| // Get performance inputs | |||
| elements::PerformanceState performance; | |||
| performance.note = 12.0*getf(inputs[NOTE_INPUT]) + roundf(params[COARSE_PARAM]) + 3.3*quadraticBipolar(params[FINE_PARAM]) + 69.0; | |||
| performance.modulation = 3.3*quarticBipolar(params[FM_PARAM]) * 49.5 * getf(inputs[FM_INPUT])/5.0; | |||
| performance.gate = params[PLAY_PARAM] >= 1.0 || getf(inputs[GATE_INPUT]) >= 1.0; | |||
| performance.strength = clampf(1.0 - getf(inputs[STRENGTH_INPUT])/5.0, 0.0, 1.0); | |||
| // Generate audio | |||
| part->Process(performance, blow, strike, main, aux, 16); | |||
| // Set lights | |||
| lights[0] = part->exciter_level(); | |||
| lights[1] = part->resonator_level(); | |||
| } | |||
| } | |||
| ElementsWidget::ElementsWidget() : ModuleWidget(new Elements()) { | |||
| box.size = Vec(15*34, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Elements.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(480, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(480, 365))); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(49-20, 63-20), module, Elements::CONTOUR_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(120-20, 63-20), module, Elements::BOW_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallRedKnob>(Vec(190-20, 63-20), module, Elements::BLOW_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(260-20, 63-20), module, Elements::STRIKE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(331-20, 63-20), module, Elements::COARSE_PARAM, -30.0, 30.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(402-20, 63-20), module, Elements::FINE_PARAM, -2.0, 2.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(472-20, 63-20), module, Elements::FM_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<LargeRedKnob>(Vec(142-26, 143-26), module, Elements::FLOW_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeGreenKnob>(Vec(239-26, 143-26), module, Elements::MALLET_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeWhiteKnob>(Vec(353-26, 143-26), module, Elements::GEOMETRY_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<LargeWhiteKnob>(Vec(450-26, 143-26), module, Elements::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(120-20, 223-20), module, Elements::BOW_TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallRedKnob>(Vec(191-20, 223-20), module, Elements::BLOW_TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(260-20, 223-20), module, Elements::STRIKE_TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(331-20, 223-20), module, Elements::DAMPING_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(401-20, 223-20), module, Elements::POSITION_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(472-20, 223-20), module, Elements::SPACE_PARAM, 0.0, 2.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(113-9, 283-9), module, Elements::BOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(152-9, 283-9), module, Elements::FLOW_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(190-9, 283-9), module, Elements::BLOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(229-9, 283-9), module, Elements::MALLET_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(267-9, 283-9), module, Elements::STRIKE_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(325-9, 283-9), module, Elements::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(363-9, 283-9), module, Elements::GEOMETRY_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(402-9, 283-9), module, Elements::POSITION_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(440-9, 283-9), module, Elements::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(479-9, 283-9), module, Elements::SPACE_MOD_PARAM, -2.0, 2.0, 0.0)); | |||
| addInput(createInput(Vec(32-10, 190-10), module, Elements::NOTE_INPUT)); | |||
| addInput(createInput(Vec(68-10, 190-10), module, Elements::FM_INPUT)); | |||
| addInput(createInput(Vec(32-10, 236-10), module, Elements::GATE_INPUT)); | |||
| addInput(createInput(Vec(68-10, 236-10), module, Elements::STRENGTH_INPUT)); | |||
| addInput(createInput(Vec(32-10, 282-10), module, Elements::BLOW_INPUT)); | |||
| addInput(createInput(Vec(68-10, 282-10), module, Elements::STRIKE_INPUT)); | |||
| addOutput(createOutput(Vec(32-10, 328-10), module, Elements::AUX_OUTPUT)); | |||
| addOutput(createOutput(Vec(68-10, 328-10), module, Elements::MAIN_OUTPUT)); | |||
| addInput(createInput(Vec(113-10, 328-10), module, Elements::BOW_TIMBRE_MOD_INPUT)); | |||
| addInput(createInput(Vec(152-10, 328-10), module, Elements::FLOW_MOD_INPUT)); | |||
| addInput(createInput(Vec(190-10, 328-10), module, Elements::BLOW_TIMBRE_MOD_INPUT)); | |||
| addInput(createInput(Vec(229-10, 328-10), module, Elements::MALLET_MOD_INPUT)); | |||
| addInput(createInput(Vec(267-10, 328-10), module, Elements::STRIKE_TIMBRE_MOD_INPUT)); | |||
| addInput(createInput(Vec(325-10, 328-10), module, Elements::DAMPING_MOD_INPUT)); | |||
| addInput(createInput(Vec(363-10, 328-10), module, Elements::GEOMETRY_MOD_INPUT)); | |||
| addInput(createInput(Vec(402-10, 328-10), module, Elements::POSITION_MOD_INPUT)); | |||
| addInput(createInput(Vec(440-10, 328-10), module, Elements::BRIGHTNESS_MOD_INPUT)); | |||
| addInput(createInput(Vec(479-10, 328-10), module, Elements::SPACE_MOD_INPUT)); | |||
| // addInputPort(createInputPort(Vec(479-10, 328-10), module, Elements::SPACE_MOD_INPUT)); | |||
| addParam(createParam<LargeMomentarySwitch>(Vec(36, 116), module, Elements::PLAY_PARAM, 0.0, 2.0, 0.0)); | |||
| Elements *elements = dynamic_cast<Elements*>(module); | |||
| addChild(createValueLight<MediumValueLight>(Vec(184, 168), &elements->lights[0])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(395, 168), &elements->lights[1])); | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| // If the trigger input is rising at a rate of at least DTRIG, the S&H will be triggered | |||
| #define DTRIG 5000.0 | |||
| struct Kinks : Module { | |||
| enum ParamIds { | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| SIGN_INPUT, | |||
| LOGIC_A_INPUT, | |||
| LOGIC_B_INPUT, | |||
| SH_INPUT, | |||
| TRIG_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| INVERT_OUTPUT, | |||
| HALF_RECTIFY_OUTPUT, | |||
| FULL_RECTIFY_OUTPUT, | |||
| MAX_OUTPUT, | |||
| MIN_OUTPUT, | |||
| NOISE_OUTPUT, | |||
| SH_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| std::normal_distribution<float> dist; | |||
| float lastTrig = 0.0; | |||
| float sample = 0.0; | |||
| float lights[3] = {}; | |||
| Kinks(); | |||
| void step(); | |||
| }; | |||
| Kinks::Kinks() : dist(0.0, 1.0) { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| void Kinks::step() { | |||
| // Gaussian noise generator | |||
| float noise = 2.0 * dist(rng); | |||
| // S&H | |||
| float trig = getf(inputs[TRIG_INPUT]); | |||
| float dtrig = (trig - lastTrig) * SAMPLE_RATE; | |||
| if (dtrig > DTRIG) { | |||
| sample = getf(inputs[SH_INPUT], noise); | |||
| } | |||
| lastTrig = trig; | |||
| // lights | |||
| lights[0] = getf(inputs[SIGN_INPUT]); | |||
| lights[1] = getf(inputs[LOGIC_A_INPUT]) + getf(inputs[LOGIC_B_INPUT]); | |||
| lights[2] = sample; | |||
| // outputs | |||
| if (outputs[INVERT_OUTPUT]) { | |||
| *outputs[INVERT_OUTPUT] = -getf(inputs[SIGN_INPUT]); | |||
| } | |||
| if (outputs[HALF_RECTIFY_OUTPUT]) { | |||
| *outputs[HALF_RECTIFY_OUTPUT] = fmaxf(0.0, getf(inputs[SIGN_INPUT])); | |||
| } | |||
| if (outputs[FULL_RECTIFY_OUTPUT]) { | |||
| *outputs[FULL_RECTIFY_OUTPUT] = fabsf(getf(inputs[SIGN_INPUT])); | |||
| } | |||
| if (outputs[MAX_OUTPUT]) { | |||
| *outputs[MAX_OUTPUT] = fmaxf(getf(inputs[LOGIC_A_INPUT]), getf(inputs[LOGIC_B_INPUT])); | |||
| } | |||
| if (outputs[MIN_OUTPUT]) { | |||
| *outputs[MIN_OUTPUT] = fminf(getf(inputs[LOGIC_A_INPUT]), getf(inputs[LOGIC_B_INPUT])); | |||
| } | |||
| if (outputs[NOISE_OUTPUT]) { | |||
| *outputs[NOISE_OUTPUT] = noise; | |||
| } | |||
| if (outputs[SH_OUTPUT]) { | |||
| *outputs[SH_OUTPUT] = sample; | |||
| } | |||
| } | |||
| KinksWidget::KinksWidget() : ModuleWidget(new Kinks()) { | |||
| box.size = Vec(15*4, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Kinks.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addInput(createInput(Vec(6-1, 78-1), module, Kinks::SIGN_INPUT)); | |||
| addOutput(createOutput(Vec(34-1, 78-1), module, Kinks::INVERT_OUTPUT)); | |||
| addOutput(createOutput(Vec(6-1, 116-1), module, Kinks::HALF_RECTIFY_OUTPUT)); | |||
| addOutput(createOutput(Vec(34-1, 116-1), module, Kinks::FULL_RECTIFY_OUTPUT)); | |||
| addInput(createInput(Vec(6-1, 180-1), module, Kinks::LOGIC_A_INPUT)); | |||
| addInput(createInput(Vec(34-1, 180-1), module, Kinks::LOGIC_B_INPUT)); | |||
| addOutput(createOutput(Vec(6-1, 217-1), module, Kinks::MAX_OUTPUT)); | |||
| addOutput(createOutput(Vec(34-1, 217-1), module, Kinks::MIN_OUTPUT)); | |||
| addInput(createInput(Vec(6-1, 281-1), module, Kinks::SH_INPUT)); | |||
| addInput(createInput(Vec(34-1, 281-1), module, Kinks::TRIG_INPUT)); | |||
| addOutput(createOutput(Vec(6-1, 319-1), module, Kinks::NOISE_OUTPUT)); | |||
| addOutput(createOutput(Vec(34-1, 319-1), module, Kinks::SH_OUTPUT)); | |||
| Kinks *kinks = dynamic_cast<Kinks*>(module); | |||
| addChild(createValueLight<SmallValueLight>(Vec(12, 61), &kinks->lights[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(12, 164), &kinks->lights[1])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(12, 264), &kinks->lights[2])); | |||
| } | |||
| @@ -0,0 +1,89 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| struct Links : Module { | |||
| enum ParamIds { | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| A1_INPUT, | |||
| B1_INPUT, | |||
| B2_INPUT, | |||
| C1_INPUT, | |||
| C2_INPUT, | |||
| C3_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| A1_OUTPUT, | |||
| A2_OUTPUT, | |||
| A3_OUTPUT, | |||
| B1_OUTPUT, | |||
| B2_OUTPUT, | |||
| C1_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| float lights[3] = {}; | |||
| Links(); | |||
| void step(); | |||
| }; | |||
| Links::Links() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| void Links::step() { | |||
| float in1 = getf(inputs[A1_INPUT]); | |||
| float in2 = getf(inputs[B1_INPUT]) + getf(inputs[B2_INPUT]); | |||
| float in3 = getf(inputs[C1_INPUT]) + getf(inputs[C2_INPUT]) + getf(inputs[C3_INPUT]); | |||
| setf(outputs[A1_OUTPUT], in1); | |||
| setf(outputs[A2_OUTPUT], in1); | |||
| setf(outputs[A3_OUTPUT], in1); | |||
| setf(outputs[B1_OUTPUT], in2); | |||
| setf(outputs[B2_OUTPUT], in2); | |||
| setf(outputs[C1_OUTPUT], in3); | |||
| lights[0] = in1; | |||
| lights[1] = in2; | |||
| lights[2] = in3; | |||
| } | |||
| LinksWidget::LinksWidget() : ModuleWidget(new Links()) { | |||
| box.size = Vec(15*4, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Links.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addInput(createInput(Vec(6-1, 78-1), module, Links::A1_INPUT)); | |||
| addOutput(createOutput(Vec(34-1, 78-1), module, Links::A1_OUTPUT)); | |||
| addOutput(createOutput(Vec(6-1, 116-1), module, Links::A2_OUTPUT)); | |||
| addOutput(createOutput(Vec(34-1, 116-1), module, Links::A3_OUTPUT)); | |||
| addInput(createInput(Vec(6-1, 180-1), module, Links::B1_INPUT)); | |||
| addInput(createInput(Vec(34-1, 180-1), module, Links::B2_INPUT)); | |||
| addOutput(createOutput(Vec(6-1, 217-1), module, Links::B1_OUTPUT)); | |||
| addOutput(createOutput(Vec(34-1, 217-1), module, Links::B2_OUTPUT)); | |||
| addInput(createInput(Vec(6-1, 281-1), module, Links::C1_INPUT)); | |||
| addInput(createInput(Vec(34-1, 281-1), module, Links::C2_INPUT)); | |||
| addInput(createInput(Vec(6-1, 319-1), module, Links::C3_INPUT)); | |||
| addOutput(createOutput(Vec(34-1, 319-1), module, Links::C1_OUTPUT)); | |||
| Links *links = dynamic_cast<Links*>(module); | |||
| addChild(createValueLight<SmallValueLight>(Vec(26, 61), &links->lights[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(26, 164), &links->lights[1])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(26, 264), &links->lights[2])); | |||
| } | |||
| @@ -0,0 +1,206 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| #include "rings/dsp/part.h" | |||
| #include "rings/dsp/strummer.h" | |||
| #include "rings/dsp/string_synth_part.h" | |||
| struct Rings : Module { | |||
| enum ParamIds { | |||
| POLYPHONY_PARAM, | |||
| RESONATOR_PARAM, | |||
| FREQUENCY_PARAM, | |||
| STRUCTURE_PARAM, | |||
| BRIGHTNESS_PARAM, | |||
| DAMPING_PARAM, | |||
| POSITION_PARAM, | |||
| BRIGHTNESS_MOD_PARAM, | |||
| FREQUENCY_MOD_PARAM, | |||
| DAMPING_MOD_PARAM, | |||
| STRUCTURE_MOD_PARAM, | |||
| POSITION_MOD_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| BRIGHTNESS_MOD_INPUT, | |||
| FREQUENCY_MOD_INPUT, | |||
| DAMPING_MOD_INPUT, | |||
| STRUCTURE_MOD_INPUT, | |||
| POSITION_MOD_INPUT, | |||
| STRUM_INPUT, | |||
| PITCH_INPUT, | |||
| IN_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| ODD_OUTPUT, | |||
| EVEN_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| uint16_t reverb_buffer[32768] = {}; | |||
| int bufferFrame = 0; | |||
| float in[24] = {}; | |||
| float out[24] = {}; | |||
| float aux[24] = {}; | |||
| rings::Part part; | |||
| rings::StringSynthPart string_synth; | |||
| rings::Strummer strummer; | |||
| bool strum = false; | |||
| bool lastStrum = false; | |||
| Rings(); | |||
| ~Rings(); | |||
| void step(); | |||
| }; | |||
| Rings::Rings() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| memset(&strummer, 0, sizeof(strummer)); | |||
| memset(&part, 0, sizeof(part)); | |||
| memset(&string_synth, 0, sizeof(string_synth)); | |||
| strummer.Init(0.01, 44100.0 / 24); | |||
| part.Init(reverb_buffer); | |||
| string_synth.Init(reverb_buffer); | |||
| } | |||
| Rings::~Rings() { | |||
| } | |||
| void Rings::step() { | |||
| // TODO Sample rate conversion from 48000 Hz | |||
| // TODO | |||
| // "Normalized to a pulse/burst generator that reacts to note changes on the V/OCT input." | |||
| in[bufferFrame] = clampf(getf(inputs[IN_INPUT])/5.0, -1.0, 1.0); | |||
| // "Note that you need to insert a jack into each output to split the signals: when only one jack is inserted, both signals are mixed together." | |||
| if (outputs[ODD_OUTPUT] && outputs[EVEN_OUTPUT]) { | |||
| setf(outputs[ODD_OUTPUT], clampf(out[bufferFrame], -1.0, 1.0)*5.0); | |||
| setf(outputs[EVEN_OUTPUT], clampf(aux[bufferFrame], -1.0, 1.0)*5.0); | |||
| } | |||
| else { | |||
| float v = clampf(out[bufferFrame] + aux[bufferFrame], -1.0, 1.0)*5.0; | |||
| setf(outputs[ODD_OUTPUT], v); | |||
| setf(outputs[EVEN_OUTPUT], v); | |||
| } | |||
| if (!strum) { | |||
| strum = getf(inputs[STRUM_INPUT]) >= 1.0; | |||
| } | |||
| if (++bufferFrame >= 24) { | |||
| bufferFrame = 0; | |||
| // modes | |||
| int polyphony = 1; | |||
| switch ((int) roundf(params[POLYPHONY_PARAM])) { | |||
| case 1: polyphony = 2; break; | |||
| case 2: polyphony = 4; break; | |||
| } | |||
| if (polyphony != part.polyphony()) { | |||
| part.set_polyphony(polyphony); | |||
| } | |||
| int model = (int) roundf(params[RESONATOR_PARAM]); | |||
| if (0 <= model && model < rings::RESONATOR_MODEL_LAST) { | |||
| part.set_model((rings::ResonatorModel) model); | |||
| } | |||
| // Patch | |||
| rings::Patch patch; | |||
| float structure = params[STRUCTURE_PARAM] + 3.3*quadraticBipolar(params[STRUCTURE_MOD_PARAM])*getf(inputs[STRUCTURE_MOD_INPUT])/5.0; | |||
| patch.structure = clampf(structure, 0.0, 0.9995); | |||
| patch.brightness = clampf(params[BRIGHTNESS_PARAM] + 3.3*quadraticBipolar(params[BRIGHTNESS_MOD_PARAM])*getf(inputs[BRIGHTNESS_MOD_INPUT])/5.0, 0.0, 1.0); | |||
| patch.damping = clampf(params[DAMPING_PARAM] + 3.3*quadraticBipolar(params[DAMPING_MOD_PARAM])*getf(inputs[DAMPING_MOD_INPUT])/5.0, 0.0, 0.9995); | |||
| patch.position = clampf(params[POSITION_PARAM] + 3.3*quadraticBipolar(params[POSITION_MOD_PARAM])*getf(inputs[POSITION_MOD_INPUT])/5.0, 0.0, 0.9995); | |||
| // Performance | |||
| rings::PerformanceState performance_state; | |||
| performance_state.note = 12.0*getf(inputs[PITCH_INPUT], 1/12.0); | |||
| float transpose = params[FREQUENCY_PARAM]; | |||
| // Quantize transpose if pitch input is connected | |||
| if (inputs[PITCH_INPUT]) { | |||
| transpose = roundf(transpose); | |||
| } | |||
| performance_state.tonic = 12.0 + clampf(transpose, 0, 60.0); | |||
| performance_state.fm = clampf(48.0 * 3.3*quarticBipolar(params[FREQUENCY_MOD_PARAM]) * getf(inputs[FREQUENCY_MOD_INPUT], 1.0)/5.0, -48.0, 48.0); | |||
| performance_state.internal_exciter = !inputs[IN_INPUT]; | |||
| performance_state.internal_strum = !inputs[STRUM_INPUT]; | |||
| performance_state.internal_note = !inputs[PITCH_INPUT]; | |||
| // TODO | |||
| // "Normalized to a step detector on the V/OCT input and a transient detector on the IN input." | |||
| performance_state.strum = strum && !lastStrum; | |||
| lastStrum = strum; | |||
| strum = false; | |||
| performance_state.chord = clampf(roundf(structure * (rings::kNumChords - 1)), 0, rings::kNumChords - 1); | |||
| // Process audio | |||
| if (0) { | |||
| // strummer.Process(NULL, 24, &performance_state); | |||
| // string_synth.Process(performance_state, patch, in, out, aux, 24); | |||
| } | |||
| else { | |||
| strummer.Process(in, 24, &performance_state); | |||
| part.Process(performance_state, patch, in, out, aux, 24); | |||
| } | |||
| } | |||
| } | |||
| RingsWidget::RingsWidget() : ModuleWidget(new Rings()) { | |||
| box.size = Vec(15*14, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Rings.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(180, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(180, 365))); | |||
| addParam(createParam<MediumToggleSwitch>(Vec(14, 40), module, Rings::POLYPHONY_PARAM, 0.0, 2.0, 0.0)); | |||
| addParam(createParam<MediumToggleSwitch>(Vec(179, 40), module, Rings::RESONATOR_PARAM, 0.0, 2.0, 0.0)); | |||
| addParam(createParam<LargeWhiteKnob>(Vec(30, 73), module, Rings::FREQUENCY_PARAM, 0.0, 60.0, 30.0)); | |||
| addParam(createParam<LargeWhiteKnob>(Vec(127, 73), module, Rings::STRUCTURE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(14, 159), module, Rings::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(84, 159), module, Rings::DAMPING_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(155, 159), module, Rings::POSITION_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(19, 229), module, Rings::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(57, 229), module, Rings::FREQUENCY_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(95, 229), module, Rings::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(134, 229), module, Rings::STRUCTURE_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(172, 229), module, Rings::POSITION_MOD_PARAM, -1.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(18, 275), module, Rings::BRIGHTNESS_MOD_INPUT)); | |||
| addInput(createInput(Vec(56, 275), module, Rings::FREQUENCY_MOD_INPUT)); | |||
| addInput(createInput(Vec(95, 275), module, Rings::DAMPING_MOD_INPUT)); | |||
| addInput(createInput(Vec(133, 275), module, Rings::STRUCTURE_MOD_INPUT)); | |||
| addInput(createInput(Vec(171, 275), module, Rings::POSITION_MOD_INPUT)); | |||
| addInput(createInput(Vec(18, 318), module, Rings::STRUM_INPUT)); | |||
| addInput(createInput(Vec(56, 318), module, Rings::PITCH_INPUT)); | |||
| addInput(createInput(Vec(95, 318), module, Rings::IN_INPUT)); | |||
| addOutput(createOutput(Vec(133, 318), module, Rings::ODD_OUTPUT)); | |||
| addOutput(createOutput(Vec(171, 318), module, Rings::EVEN_OUTPUT)); | |||
| Rings *rings = dynamic_cast<Rings*>(module); | |||
| addChild(createValueLight<SmallModeLight>(Vec(39, 45), &rings->params[Rings::POLYPHONY_PARAM])); | |||
| addChild(createValueLight<SmallModeLight>(Vec(164, 45), &rings->params[Rings::RESONATOR_PARAM])); | |||
| } | |||
| @@ -0,0 +1,111 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| struct Shades : Module { | |||
| enum ParamIds { | |||
| GAIN1_PARAM, | |||
| GAIN2_PARAM, | |||
| GAIN3_PARAM, | |||
| MODE1_PARAM, | |||
| MODE2_PARAM, | |||
| MODE3_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| IN1_INPUT, | |||
| IN2_INPUT, | |||
| IN3_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT1_OUTPUT, | |||
| OUT2_OUTPUT, | |||
| OUT3_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| float lights[3] = {}; | |||
| Shades(); | |||
| void step(); | |||
| }; | |||
| Shades::Shades() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| static float getChannelOutput(const float *in, float gain, float mode) { | |||
| float out = getf(in, 5.0); | |||
| if (mode < 0.5) { | |||
| // attenuverter | |||
| out *= 2.0*gain - 1.0; | |||
| } | |||
| else { | |||
| // attenuator | |||
| out *= gain; | |||
| } | |||
| return out; | |||
| } | |||
| void Shades::step() { | |||
| float out = 0.0; | |||
| out += getChannelOutput(inputs[IN1_INPUT], params[GAIN1_PARAM], params[MODE1_PARAM]); | |||
| lights[0] = out; | |||
| if (outputs[OUT1_OUTPUT]) { | |||
| *outputs[OUT1_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN2_INPUT], params[GAIN2_PARAM], params[MODE2_PARAM]); | |||
| lights[1] = out; | |||
| if (outputs[OUT2_OUTPUT]) { | |||
| *outputs[OUT2_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN3_INPUT], params[GAIN3_PARAM], params[MODE3_PARAM]); | |||
| lights[2] = out; | |||
| if (outputs[OUT3_OUTPUT]) { | |||
| *outputs[OUT3_OUTPUT] = out; | |||
| } | |||
| } | |||
| ShadesWidget::ShadesWidget() : ModuleWidget(new Shades()) { | |||
| box.size = Vec(15*6, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Shades.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addParam(createParam<SmallRedKnob>(Vec(40, 41), module, Shades::GAIN1_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(40, 107), module, Shades::GAIN2_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(40, 173), module, Shades::GAIN3_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SlideSwitch>(Vec(11, 52), module, Shades::MODE1_PARAM, 0.0, 1.0, 0.0)); | |||
| addParam(createParam<SlideSwitch>(Vec(11, 118), module, Shades::MODE2_PARAM, 0.0, 1.0, 0.0)); | |||
| addParam(createParam<SlideSwitch>(Vec(11, 184), module, Shades::MODE3_PARAM, 0.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(11, 247), module, Shades::IN1_INPUT)); | |||
| addInput(createInput(Vec(11, 283), module, Shades::IN2_INPUT)); | |||
| addInput(createInput(Vec(11, 319), module, Shades::IN3_INPUT)); | |||
| addOutput(createOutput(Vec(58, 247), module, Shades::OUT1_OUTPUT)); | |||
| addOutput(createOutput(Vec(58, 283), module, Shades::OUT2_OUTPUT)); | |||
| addOutput(createOutput(Vec(58, 319), module, Shades::OUT3_OUTPUT)); | |||
| Shades *shades = dynamic_cast<Shades*>(module); | |||
| addChild(createValueLight<SmallValueLight>(Vec(42, 256), &shades->lights[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(42, 292), &shades->lights[1])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(42, 328), &shades->lights[2])); | |||
| } | |||
| @@ -0,0 +1,83 @@ | |||
| #include <string.h> | |||
| #include "AudibleInstruments.hpp" | |||
| struct Streams : Module { | |||
| enum ParamIds { | |||
| SHAPE1_PARAM, | |||
| MOD1_PARAM, | |||
| LEVEL1_PARAM, | |||
| RESPONSE1_PARAM, | |||
| SHAPE2_PARAM, | |||
| MOD2_PARAM, | |||
| LEVEL2_PARAM, | |||
| RESPONSE2_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| EXCITE1_INPUT, | |||
| IN1_INPUT, | |||
| LEVEL1_INPUT, | |||
| EXCITE2_INPUT, | |||
| IN2_INPUT, | |||
| LEVEL2_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT1_OUTPUT, | |||
| OUT2_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| Streams(); | |||
| void step(); | |||
| }; | |||
| Streams::Streams() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| void Streams::step() { | |||
| } | |||
| StreamsWidget::StreamsWidget() : ModuleWidget(new Streams()) { | |||
| box.size = Vec(15*12, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Streams.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(150, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(150, 365))); | |||
| // addParam(createParam<HugeGlowKnob>(Vec(30, 53), module, Streams::ALGORITHM_PARAM, 0.0, 8.0, 0.0)); | |||
| // addParam(createParam<SmallWhiteKnob>(Vec(95, 173), module, Streams::TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| // addParam(createParam<MediumToggleSwitch>(Vec(17, 182), module, Streams::STATE_PARAM, 0.0, 3.0, 0.0)); | |||
| // addParam(createParam<TinyBlackKnob>(Vec(15, 214), module, Streams::LEVEL1_PARAM, 0.0, 1.0, 1.0)); | |||
| // addParam(createParam<TinyBlackKnob>(Vec(53, 214), module, Streams::LEVEL2_PARAM, 0.0, 1.0, 1.0)); | |||
| // addInput(createInput(Vec(11, 275), module, Streams::LEVEL1_INPUT)); | |||
| // addInput(createInput(Vec(47, 275), module, Streams::LEVEL2_INPUT)); | |||
| // addInput(createInput(Vec(83, 275), module, Streams::ALGORITHM_INPUT)); | |||
| // addInput(createInput(Vec(119, 275), module, Streams::TIMBRE_INPUT)); | |||
| // addInput(createInput(Vec(11, 318), module, Streams::CARRIER_INPUT)); | |||
| // addInput(createInput(Vec(47, 318), module, Streams::MODULATOR_INPUT)); | |||
| // addOutput(createOutput(Vec(83, 318), module, Streams::MODULATOR_OUTPUT)); | |||
| // addOutput(createOutput(Vec(119, 318), module, Streams::AUX_OUTPUT)); | |||
| // Streams *streams = dynamic_cast<Streams*>(module); | |||
| // addChild(createValueLight<SmallModeLight>(Vec(21, 168), &streams->lights[0])); | |||
| } | |||
| @@ -0,0 +1,187 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| #include "tides/generator.h" | |||
| struct Tides : Module { | |||
| enum ParamIds { | |||
| MODE_PARAM, | |||
| RANGE_PARAM, | |||
| FREQUENCY_PARAM, | |||
| FM_PARAM, | |||
| SHAPE_PARAM, | |||
| SLOPE_PARAM, | |||
| SMOOTHNESS_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| SHAPE_INPUT, | |||
| SLOPE_INPUT, | |||
| SMOOTHNESS_INPUT, | |||
| TRIG_INPUT, | |||
| FREEZE_INPUT, | |||
| PITCH_INPUT, | |||
| FM_INPUT, | |||
| LEVEL_INPUT, | |||
| CLOCK_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| HIGH_OUTPUT, | |||
| LOW_OUTPUT, | |||
| UNI_OUTPUT, | |||
| BI_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| tides::Generator generator; | |||
| float lights[3] = {}; | |||
| int frame = 0; | |||
| uint8_t lastGate; | |||
| Tides(); | |||
| void step(); | |||
| }; | |||
| Tides::Tides() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| memset(&generator, 0, sizeof(generator)); | |||
| generator.Init(); | |||
| generator.set_range(tides::GENERATOR_RANGE_LOW); | |||
| generator.set_mode(tides::GENERATOR_MODE_AD); | |||
| generator.set_sync(false); | |||
| } | |||
| void Tides::step() { | |||
| if (++frame >= 16) { | |||
| frame = 0; | |||
| // Mode and range | |||
| tides::GeneratorMode mode = (tides::GeneratorMode) roundf(1.0 - params[MODE_PARAM]); | |||
| if (mode != generator.mode()) { | |||
| generator.set_mode(mode); | |||
| } | |||
| lights[0] = -params[MODE_PARAM]; | |||
| tides::GeneratorRange range = (tides::GeneratorRange) roundf(1.0 - params[RANGE_PARAM]); | |||
| if (range != generator.range()) { | |||
| generator.set_range(range); | |||
| } | |||
| lights[2] = -params[RANGE_PARAM]; | |||
| // Pitch | |||
| float pitch = params[FREQUENCY_PARAM]; | |||
| pitch += 12.0*getf(inputs[PITCH_INPUT]); | |||
| pitch += params[FM_PARAM] * getf(inputs[FM_INPUT], 0.1) / 5.0; | |||
| pitch += 60.0; | |||
| generator.set_pitch(clampf(pitch*0x80, -0x8000, 0x7fff)); | |||
| // Slope, smoothness, pitch | |||
| int16_t shape = clampf(params[SHAPE_PARAM] + getf(inputs[SHAPE_INPUT]) / 5.0, -1.0, 1.0) * 0x7fff; | |||
| int16_t slope = clampf(params[SLOPE_PARAM] + getf(inputs[SLOPE_INPUT]) / 5.0, -1.0, 1.0) * 0x7fff; | |||
| int16_t smoothness = clampf(params[SMOOTHNESS_PARAM] + getf(inputs[SMOOTHNESS_INPUT]) / 5.0, -1.0, 1.0) * 0x7fff; | |||
| generator.set_shape(shape); | |||
| generator.set_slope(slope); | |||
| generator.set_smoothness(smoothness); | |||
| // Sync | |||
| // Slight deviation from spec here. | |||
| // Instead of toggling sync by holding the range button, just enable it if the clock port is plugged in. | |||
| generator.set_sync(inputs[CLOCK_INPUT]); | |||
| // Generator | |||
| generator.Process(); | |||
| } | |||
| // Level | |||
| uint16_t level = clampf(getf(inputs[LEVEL_INPUT], 8.0) / 8.0, 0.0, 1.0) * 0xffff; | |||
| if (level < 32) | |||
| level = 0; | |||
| uint8_t gate = 0; | |||
| if (getf(inputs[FREEZE_INPUT]) >= 0.7) | |||
| gate |= tides::CONTROL_FREEZE; | |||
| if (getf(inputs[TRIG_INPUT]) >= 0.7) | |||
| gate |= tides::CONTROL_GATE; | |||
| if (getf(inputs[CLOCK_INPUT]) >= 0.7) | |||
| gate |= tides::CONTROL_CLOCK; | |||
| if (!(lastGate & tides::CONTROL_CLOCK) && (gate & tides::CONTROL_CLOCK)) | |||
| gate |= tides::CONTROL_GATE_RISING; | |||
| if (!(lastGate & tides::CONTROL_GATE) && (gate & tides::CONTROL_GATE)) | |||
| gate |= tides::CONTROL_GATE_RISING; | |||
| if ((lastGate & tides::CONTROL_GATE) && !(gate & tides::CONTROL_GATE)) | |||
| gate |= tides::CONTROL_GATE_FALLING; | |||
| lastGate = gate; | |||
| const tides::GeneratorSample& sample = generator.Process(gate); | |||
| uint32_t uni = sample.unipolar; | |||
| int32_t bi = sample.bipolar; | |||
| uni = uni * level >> 16; | |||
| bi = -bi * level >> 16; | |||
| float unif = mapf(uni, 0, 0xffff, 0.0, 8.0); | |||
| float bif = mapf(bi, -0x8000, 0x7fff, -5.0, 5.0); | |||
| setf(outputs[HIGH_OUTPUT], sample.flags & tides::FLAG_END_OF_ATTACK ? 0.0 : 5.0); | |||
| setf(outputs[LOW_OUTPUT], sample.flags & tides::FLAG_END_OF_RELEASE ? 0.0 : 5.0); | |||
| setf(outputs[UNI_OUTPUT], unif); | |||
| setf(outputs[BI_OUTPUT], bif); | |||
| lights[1] = sample.flags & tides::FLAG_END_OF_ATTACK ? -unif : unif; | |||
| } | |||
| TidesWidget::TidesWidget() : ModuleWidget(new Tides()) { | |||
| box.size = Vec(15*14, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Tides.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(180, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(180, 365))); | |||
| addParam(createParam<LargeToggleSwitch>(Vec(19, 52), module, Tides::MODE_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<LargeToggleSwitch>(Vec(19, 93), module, Tides::RANGE_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<LargeGreenKnob>(Vec(79, 60), module, Tides::FREQUENCY_PARAM, -48.0, 48.0, 0.0)); | |||
| addParam(createParam<SmallGreenKnob>(Vec(156, 66), module, Tides::FM_PARAM, -12.0, 12.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(13, 155), module, Tides::SHAPE_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(85, 155), module, Tides::SLOPE_PARAM, -1.0, 1.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(156, 155), module, Tides::SMOOTHNESS_PARAM, -1.0, 1.0, 0.0)); | |||
| addInput(createInput(Vec(23, 221), module, Tides::SHAPE_INPUT)); | |||
| addInput(createInput(Vec(95, 221), module, Tides::SLOPE_INPUT)); | |||
| addInput(createInput(Vec(166, 221), module, Tides::SMOOTHNESS_INPUT)); | |||
| addInput(createInput(Vec(23, 275), module, Tides::TRIG_INPUT)); | |||
| addInput(createInput(Vec(59, 275), module, Tides::FREEZE_INPUT)); | |||
| addInput(createInput(Vec(95, 275), module, Tides::PITCH_INPUT)); | |||
| addInput(createInput(Vec(130, 275), module, Tides::FM_INPUT)); | |||
| addInput(createInput(Vec(166, 275), module, Tides::LEVEL_INPUT)); | |||
| addInput(createInput(Vec(23, 318), module, Tides::CLOCK_INPUT)); | |||
| addOutput(createOutput(Vec(59, 318), module, Tides::HIGH_OUTPUT)); | |||
| addOutput(createOutput(Vec(95, 318), module, Tides::LOW_OUTPUT)); | |||
| addOutput(createOutput(Vec(130, 318), module, Tides::UNI_OUTPUT)); | |||
| addOutput(createOutput(Vec(166, 318), module, Tides::BI_OUTPUT)); | |||
| Tides *tides = dynamic_cast<Tides*>(module); | |||
| addChild(createValueLight<SmallValueLight>(Vec(58, 63), &tides->lights[0])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(58, 84), &tides->lights[1])); | |||
| addChild(createValueLight<SmallValueLight>(Vec(58, 105), &tides->lights[2])); | |||
| } | |||
| @@ -0,0 +1,141 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| #include <string.h> | |||
| struct Veils : Module { | |||
| enum ParamIds { | |||
| GAIN1_PARAM, | |||
| GAIN2_PARAM, | |||
| GAIN3_PARAM, | |||
| GAIN4_PARAM, | |||
| RESPONSE1_PARAM, | |||
| RESPONSE2_PARAM, | |||
| RESPONSE3_PARAM, | |||
| RESPONSE4_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| IN1_INPUT, | |||
| IN2_INPUT, | |||
| IN3_INPUT, | |||
| IN4_INPUT, | |||
| CV1_INPUT, | |||
| CV2_INPUT, | |||
| CV3_INPUT, | |||
| CV4_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| OUT1_OUTPUT, | |||
| OUT2_OUTPUT, | |||
| OUT3_OUTPUT, | |||
| OUT4_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| float lights[4] = {}; | |||
| Veils(); | |||
| void step(); | |||
| }; | |||
| Veils::Veils() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| } | |||
| static float getChannelOutput(float *in, float gain, float *cv, float response) { | |||
| float out = getf(in) * gain; | |||
| if (out == 0.0) | |||
| return 0.0; | |||
| if (cv) { | |||
| float linear = fmaxf(getf(cv) / 5.0, 0.0); | |||
| if (linear == 0.0) | |||
| return 0.0; | |||
| const float ex = 200.0; | |||
| float exponential = (powf(ex, linear) - 1.0) / (ex - 1.0); | |||
| out *= crossf(exponential, linear, response); | |||
| } | |||
| return out; | |||
| } | |||
| void Veils::step() { | |||
| float out = 0.0; | |||
| out += getChannelOutput(inputs[IN1_INPUT], params[GAIN1_PARAM], inputs[CV1_INPUT], params[RESPONSE1_PARAM]); | |||
| lights[0] = out; | |||
| if (outputs[OUT1_OUTPUT]) { | |||
| *outputs[OUT1_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN2_INPUT], params[GAIN2_PARAM], inputs[CV2_INPUT], params[RESPONSE2_PARAM]); | |||
| lights[1] = out; | |||
| if (outputs[OUT2_OUTPUT]) { | |||
| *outputs[OUT2_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN3_INPUT], params[GAIN3_PARAM], inputs[CV3_INPUT], params[RESPONSE3_PARAM]); | |||
| lights[2] = out; | |||
| if (outputs[OUT3_OUTPUT]) { | |||
| *outputs[OUT3_OUTPUT] = out; | |||
| out = 0.0; | |||
| } | |||
| out += getChannelOutput(inputs[IN4_INPUT], params[GAIN4_PARAM], inputs[CV4_INPUT], params[RESPONSE4_PARAM]); | |||
| lights[3] = out; | |||
| if (outputs[OUT4_OUTPUT]) { | |||
| *outputs[OUT4_OUTPUT] = out; | |||
| } | |||
| } | |||
| VeilsWidget::VeilsWidget() : ModuleWidget(new Veils()) { | |||
| box.size = Vec(15*12, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Veils.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(150, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(150, 365))); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 52), module, Veils::GAIN1_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 131), module, Veils::GAIN2_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 210), module, Veils::GAIN3_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(8, 288), module, Veils::GAIN4_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 56), module, Veils::RESPONSE1_PARAM, 0.0, 1.0, 1.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 135), module, Veils::RESPONSE2_PARAM, 0.0, 1.0, 1.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 214), module, Veils::RESPONSE3_PARAM, 0.0, 1.0, 1.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(72, 292), module, Veils::RESPONSE4_PARAM, 0.0, 1.0, 1.0)); | |||
| addInput(createInput(Vec(112, 43), module, Veils::IN1_INPUT)); | |||
| addInput(createInput(Vec(112, 122), module, Veils::IN2_INPUT)); | |||
| addInput(createInput(Vec(112, 200), module, Veils::IN3_INPUT)); | |||
| addInput(createInput(Vec(112, 279), module, Veils::IN4_INPUT)); | |||
| addInput(createInput(Vec(112, 82), module, Veils::CV1_INPUT)); | |||
| addInput(createInput(Vec(112, 161), module, Veils::CV2_INPUT)); | |||
| addInput(createInput(Vec(112, 240), module, Veils::CV3_INPUT)); | |||
| addInput(createInput(Vec(112, 318), module, Veils::CV4_INPUT)); | |||
| addOutput(createOutput(Vec(146, 43), module, Veils::OUT1_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 122), module, Veils::OUT2_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 200), module, Veils::OUT3_OUTPUT)); | |||
| addOutput(createOutput(Vec(146, 279), module, Veils::OUT4_OUTPUT)); | |||
| Veils *veils = dynamic_cast<Veils*>(module); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 86), &veils->lights[0])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 165), &veils->lights[1])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 244), &veils->lights[2])); | |||
| addChild(createValueLight<MediumValueLight>(Vec(149, 323), &veils->lights[3])); | |||
| } | |||
| @@ -0,0 +1,112 @@ | |||
| #include <string.h> | |||
| #include "AudibleInstruments.hpp" | |||
| #include "warps/dsp/modulator.h" | |||
| struct Warps : Module { | |||
| enum ParamIds { | |||
| ALGORITHM_PARAM, | |||
| TIMBRE_PARAM, | |||
| STATE_PARAM, | |||
| LEVEL1_PARAM, | |||
| LEVEL2_PARAM, | |||
| NUM_PARAMS | |||
| }; | |||
| enum InputIds { | |||
| LEVEL1_INPUT, | |||
| LEVEL2_INPUT, | |||
| ALGORITHM_INPUT, | |||
| TIMBRE_INPUT, | |||
| CARRIER_INPUT, | |||
| MODULATOR_INPUT, | |||
| NUM_INPUTS | |||
| }; | |||
| enum OutputIds { | |||
| MODULATOR_OUTPUT, | |||
| AUX_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| int frame = 0; | |||
| warps::Modulator modulator; | |||
| warps::ShortFrame inputFrames[60] = {}; | |||
| warps::ShortFrame outputFrames[60] = {}; | |||
| float lights[1] = {}; | |||
| Warps(); | |||
| void step(); | |||
| }; | |||
| Warps::Warps() { | |||
| params.resize(NUM_PARAMS); | |||
| inputs.resize(NUM_INPUTS); | |||
| outputs.resize(NUM_OUTPUTS); | |||
| memset(&modulator, 0, sizeof(modulator)); | |||
| modulator.Init(96000.0f); | |||
| } | |||
| void Warps::step() { | |||
| if (++frame >= 60) { | |||
| frame = 0; | |||
| warps::Parameters *p = modulator.mutable_parameters(); | |||
| p->channel_drive[0] = clampf(params[LEVEL1_PARAM] + getf(inputs[LEVEL1_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->channel_drive[1] = clampf(params[LEVEL2_PARAM] + getf(inputs[LEVEL2_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->modulation_algorithm = clampf(params[ALGORITHM_PARAM] / 8.0 + getf(inputs[ALGORITHM_PARAM]) / 5.0, 0.0, 1.0); | |||
| p->modulation_parameter = clampf(params[TIMBRE_PARAM] + getf(inputs[TIMBRE_INPUT]) / 5.0, 0.0, 1.0); | |||
| p->frequency_shift_pot = params[ALGORITHM_PARAM] / 8.0; | |||
| p->frequency_shift_cv = clampf(getf(inputs[ALGORITHM_INPUT]) / 5.0, -1.0, 1.0); | |||
| p->phase_shift = p->modulation_algorithm; | |||
| p->note = 60.0 * params[LEVEL1_PARAM] + 12.0 * getf(inputs[LEVEL1_INPUT], 2.0) + 12.0; | |||
| float state = roundf(params[STATE_PARAM]); | |||
| p->carrier_shape = (int32_t)state; | |||
| lights[0] = state - 1.0; | |||
| modulator.Process(inputFrames, outputFrames, 60); | |||
| } | |||
| inputFrames[frame].l = clampf(getf(inputs[CARRIER_INPUT]) / 16.0 * 0x8000, -0x8000, 0x7fff); | |||
| inputFrames[frame].r = clampf(getf(inputs[MODULATOR_INPUT]) / 16.0 * 0x8000, -0x8000, 0x7fff); | |||
| setf(outputs[MODULATOR_OUTPUT], (float)outputFrames[frame].l / 0x8000 * 5.0); | |||
| setf(outputs[AUX_OUTPUT], (float)outputFrames[frame].r / 0x8000 * 5.0); | |||
| } | |||
| WarpsWidget::WarpsWidget() : ModuleWidget(new Warps()) { | |||
| box.size = Vec(15*10, 380); | |||
| { | |||
| AudiblePanel *panel = new AudiblePanel(); | |||
| panel->imageFilename = "plugins/AudibleInstruments/res/Warps.png"; | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addChild(createScrew(Vec(15, 0))); | |||
| addChild(createScrew(Vec(120, 0))); | |||
| addChild(createScrew(Vec(15, 365))); | |||
| addChild(createScrew(Vec(120, 365))); | |||
| addParam(createParam<HugeGlowKnob>(Vec(30, 53), module, Warps::ALGORITHM_PARAM, 0.0, 8.0, 0.0)); | |||
| addParam(createParam<SmallWhiteKnob>(Vec(95, 173), module, Warps::TIMBRE_PARAM, 0.0, 1.0, 0.5)); | |||
| addParam(createParam<MediumToggleSwitch>(Vec(17, 182), module, Warps::STATE_PARAM, 0.0, 3.0, 0.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(15, 214), module, Warps::LEVEL1_PARAM, 0.0, 1.0, 1.0)); | |||
| addParam(createParam<TinyBlackKnob>(Vec(53, 214), module, Warps::LEVEL2_PARAM, 0.0, 1.0, 1.0)); | |||
| addInput(createInput(Vec(11, 275), module, Warps::LEVEL1_INPUT)); | |||
| addInput(createInput(Vec(47, 275), module, Warps::LEVEL2_INPUT)); | |||
| addInput(createInput(Vec(83, 275), module, Warps::ALGORITHM_INPUT)); | |||
| addInput(createInput(Vec(119, 275), module, Warps::TIMBRE_INPUT)); | |||
| addInput(createInput(Vec(11, 318), module, Warps::CARRIER_INPUT)); | |||
| addInput(createInput(Vec(47, 318), module, Warps::MODULATOR_INPUT)); | |||
| addOutput(createOutput(Vec(83, 318), module, Warps::MODULATOR_OUTPUT)); | |||
| addOutput(createOutput(Vec(119, 318), module, Warps::AUX_OUTPUT)); | |||
| Warps *warps = dynamic_cast<Warps*>(module); | |||
| addChild(createValueLight<SmallModeLight>(Vec(21, 168), &warps->lights[0])); | |||
| } | |||