Browse Source

Initial commit

tags/v0.4.0
Andrew Belt 8 years ago
commit
af21b244ae
18 changed files with 2336 additions and 0 deletions
  1. +7
    -0
      LICENSE.txt
  2. +80
    -0
      Makefile
  3. +46
    -0
      README.txt
  4. +48
    -0
      src/AudibleInstruments.cpp
  5. +275
    -0
      src/AudibleInstruments.hpp
  6. +137
    -0
      src/Blinds.cpp
  7. +197
    -0
      src/Braids.cpp
  8. +106
    -0
      src/Branches.cpp
  9. +168
    -0
      src/Clouds.cpp
  10. +222
    -0
      src/Elements.cpp
  11. +121
    -0
      src/Kinks.cpp
  12. +89
    -0
      src/Links.cpp
  13. +206
    -0
      src/Rings.cpp
  14. +111
    -0
      src/Shades.cpp
  15. +83
    -0
      src/Streams.cpp
  16. +187
    -0
      src/Tides.cpp
  17. +141
    -0
      src/Veils.cpp
  18. +112
    -0
      src/Warps.cpp

+ 7
- 0
LICENSE.txt View File

@@ -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.

+ 80
- 0
Makefile View File

@@ -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

+ 46
- 0
README.txt View File

@@ -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)

+ 48
- 0
src/AudibleInstruments.cpp View File

@@ -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;
}

+ 275
- 0
src/AudibleInstruments.hpp View File

@@ -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();
};

+ 137
- 0
src/Blinds.cpp View File

@@ -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]));
}

+ 197
- 0
src/Braids.cpp View File

@@ -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));
}

+ 106
- 0
src/Branches.cpp View File

@@ -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]));
}

+ 168
- 0
src/Clouds.cpp View File

@@ -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));
}

+ 222
- 0
src/Elements.cpp View File

@@ -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]));
}

+ 121
- 0
src/Kinks.cpp View File

@@ -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]));
}

+ 89
- 0
src/Links.cpp View File

@@ -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]));
}

+ 206
- 0
src/Rings.cpp View File

@@ -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]));
}

+ 111
- 0
src/Shades.cpp View File

@@ -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]));
}

+ 83
- 0
src/Streams.cpp View File

@@ -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]));
}

+ 187
- 0
src/Tides.cpp View File

@@ -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]));
}

+ 141
- 0
src/Veils.cpp View File

@@ -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]));
}

+ 112
- 0
src/Warps.cpp View File

@@ -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]));
}

Loading…
Cancel
Save