Browse Source

Add Plaits

tags/v1.0.1
Andrew Belt 6 years ago
parent
commit
a721c9083f
9 changed files with 3312 additions and 4 deletions
  1. +4
    -0
      CHANGELOG.md
  2. +16
    -1
      Makefile
  3. +1
    -1
      eurorack
  4. +2968
    -0
      res/Plaits.svg
  5. +1
    -0
      src/AudibleInstruments.cpp
  6. +1
    -0
      src/AudibleInstruments.hpp
  7. +1
    -1
      src/Braids.cpp
  8. +319
    -0
      src/Plaits.cpp
  9. +1
    -1
      src/Tides.cpp

+ 4
- 0
CHANGELOG.md View File

@@ -0,0 +1,4 @@

### 0.6.1 (2018-09-12)

- Added Macro Oscillator 2 from Audible Instruments Preview

+ 16
- 1
Makefile View File

@@ -1,5 +1,5 @@
SLUG = AudibleInstruments SLUG = AudibleInstruments
VERSION = 0.6.0
VERSION = 0.6.1


FLAGS += \ FLAGS += \
-DTEST \ -DTEST \
@@ -7,14 +7,23 @@ FLAGS += \
-Wno-unused-local-typedefs -Wno-unused-local-typedefs


SOURCES += $(wildcard src/*.cpp) SOURCES += $(wildcard src/*.cpp)

SOURCES += eurorack/stmlib/utils/random.cc SOURCES += eurorack/stmlib/utils/random.cc
SOURCES += eurorack/stmlib/dsp/atan.cc SOURCES += eurorack/stmlib/dsp/atan.cc
SOURCES += eurorack/stmlib/dsp/units.cc SOURCES += eurorack/stmlib/dsp/units.cc

SOURCES += eurorack/braids/macro_oscillator.cc SOURCES += eurorack/braids/macro_oscillator.cc
SOURCES += eurorack/braids/analog_oscillator.cc SOURCES += eurorack/braids/analog_oscillator.cc
SOURCES += eurorack/braids/digital_oscillator.cc SOURCES += eurorack/braids/digital_oscillator.cc
SOURCES += eurorack/braids/quantizer.cc SOURCES += eurorack/braids/quantizer.cc
SOURCES += eurorack/braids/resources.cc SOURCES += eurorack/braids/resources.cc

SOURCES += $(wildcard eurorack/plaits/dsp/*.cc)
SOURCES += $(wildcard eurorack/plaits/dsp/engine/*.cc)
SOURCES += $(wildcard eurorack/plaits/dsp/speech/*.cc)
SOURCES += $(wildcard eurorack/plaits/dsp/physical_modelling/*.cc)
SOURCES += eurorack/plaits/resources.cc

SOURCES += eurorack/clouds/dsp/correlator.cc SOURCES += eurorack/clouds/dsp/correlator.cc
SOURCES += eurorack/clouds/dsp/granular_processor.cc SOURCES += eurorack/clouds/dsp/granular_processor.cc
SOURCES += eurorack/clouds/dsp/mu_law.cc SOURCES += eurorack/clouds/dsp/mu_law.cc
@@ -22,6 +31,7 @@ SOURCES += eurorack/clouds/dsp/pvoc/frame_transformation.cc
SOURCES += eurorack/clouds/dsp/pvoc/phase_vocoder.cc SOURCES += eurorack/clouds/dsp/pvoc/phase_vocoder.cc
SOURCES += eurorack/clouds/dsp/pvoc/stft.cc SOURCES += eurorack/clouds/dsp/pvoc/stft.cc
SOURCES += eurorack/clouds/resources.cc SOURCES += eurorack/clouds/resources.cc

SOURCES += eurorack/elements/dsp/exciter.cc SOURCES += eurorack/elements/dsp/exciter.cc
SOURCES += eurorack/elements/dsp/ominous_voice.cc SOURCES += eurorack/elements/dsp/ominous_voice.cc
SOURCES += eurorack/elements/dsp/resonator.cc SOURCES += eurorack/elements/dsp/resonator.cc
@@ -31,22 +41,27 @@ SOURCES += eurorack/elements/dsp/part.cc
SOURCES += eurorack/elements/dsp/string.cc SOURCES += eurorack/elements/dsp/string.cc
SOURCES += eurorack/elements/dsp/voice.cc SOURCES += eurorack/elements/dsp/voice.cc
SOURCES += eurorack/elements/resources.cc SOURCES += eurorack/elements/resources.cc

SOURCES += eurorack/rings/dsp/fm_voice.cc SOURCES += eurorack/rings/dsp/fm_voice.cc
SOURCES += eurorack/rings/dsp/part.cc SOURCES += eurorack/rings/dsp/part.cc
SOURCES += eurorack/rings/dsp/string_synth_part.cc SOURCES += eurorack/rings/dsp/string_synth_part.cc
SOURCES += eurorack/rings/dsp/string.cc SOURCES += eurorack/rings/dsp/string.cc
SOURCES += eurorack/rings/dsp/resonator.cc SOURCES += eurorack/rings/dsp/resonator.cc
SOURCES += eurorack/rings/resources.cc SOURCES += eurorack/rings/resources.cc

SOURCES += eurorack/tides/generator.cc SOURCES += eurorack/tides/generator.cc
SOURCES += eurorack/tides/resources.cc SOURCES += eurorack/tides/resources.cc

SOURCES += eurorack/warps/dsp/modulator.cc SOURCES += eurorack/warps/dsp/modulator.cc
SOURCES += eurorack/warps/dsp/oscillator.cc SOURCES += eurorack/warps/dsp/oscillator.cc
SOURCES += eurorack/warps/dsp/vocoder.cc SOURCES += eurorack/warps/dsp/vocoder.cc
SOURCES += eurorack/warps/dsp/filter_bank.cc SOURCES += eurorack/warps/dsp/filter_bank.cc
SOURCES += eurorack/warps/resources.cc SOURCES += eurorack/warps/resources.cc

SOURCES += eurorack/frames/keyframer.cc SOURCES += eurorack/frames/keyframer.cc
SOURCES += eurorack/frames/resources.cc SOURCES += eurorack/frames/resources.cc
SOURCES += eurorack/frames/poly_lfo.cc SOURCES += eurorack/frames/poly_lfo.cc

SOURCES += eurorack/peaks/processors.cc SOURCES += eurorack/peaks/processors.cc
SOURCES += eurorack/peaks/resources.cc SOURCES += eurorack/peaks/resources.cc
SOURCES += eurorack/peaks/drums/bass_drum.cc SOURCES += eurorack/peaks/drums/bass_drum.cc


+ 1
- 1
eurorack

@@ -1 +1 @@
Subproject commit 916d9620b538e004c8d1480ce378152805979eba
Subproject commit 0bcabd2baa131576c38780972aee0ef1b30163f8

+ 2968
- 0
res/Plaits.svg
File diff suppressed because it is too large
View File


+ 1
- 0
src/AudibleInstruments.cpp View File

@@ -9,6 +9,7 @@ void init(rack::Plugin *p) {
p->version = TOSTRING(VERSION); p->version = TOSTRING(VERSION);


p->addModel(modelBraids); p->addModel(modelBraids);
p->addModel(modelPlaits);
p->addModel(modelElements); p->addModel(modelElements);
p->addModel(modelTides); p->addModel(modelTides);
p->addModel(modelClouds); p->addModel(modelClouds);


+ 1
- 0
src/AudibleInstruments.hpp View File

@@ -7,6 +7,7 @@ using namespace rack;
extern Plugin *plugin; extern Plugin *plugin;


extern Model *modelBraids; extern Model *modelBraids;
extern Model *modelPlaits;
extern Model *modelElements; extern Model *modelElements;
extern Model *modelTides; extern Model *modelTides;
extern Model *modelClouds; extern Model *modelClouds;


+ 1
- 1
src/Braids.cpp View File

@@ -129,7 +129,7 @@ void Braids::step() {
if (!settings.meta_modulation) if (!settings.meta_modulation)
pitchV += fm; pitchV += fm;
if (lowCpu) if (lowCpu)
pitchV += log2f(96000.0 / engineGetSampleRate());
pitchV += log2f(96000.f * engineGetSampleTime());
int32_t pitch = (pitchV * 12.0 + 60) * 128; int32_t pitch = (pitchV * 12.0 + 60) * 128;
pitch += jitter_source.Render(settings.vco_drift); pitch += jitter_source.Render(settings.vco_drift);
pitch = clamp(pitch, 0, 16383); pitch = clamp(pitch, 0, 16383);


+ 319
- 0
src/Plaits.cpp View File

@@ -0,0 +1,319 @@
#include "AudibleInstruments.hpp"
#include "dsp/samplerate.hpp"
#include "dsp/ringbuffer.hpp"
#include "dsp/functions.hpp"
#include "dsp/digital.hpp"
#include "plaits/dsp/voice.h"


struct Plaits : Module {
enum ParamIds {
MODEL1_PARAM,
MODEL2_PARAM,
FREQ_PARAM,
HARMONICS_PARAM,
TIMBRE_PARAM,
MORPH_PARAM,
TIMBRE_CV_PARAM,
FREQ_CV_PARAM,
MORPH_CV_PARAM,
NUM_PARAMS
};
enum InputIds {
ENGINE_INPUT,
TIMBRE_INPUT,
FREQ_INPUT,
MORPH_INPUT,
HARMONICS_INPUT,
TRIGGER_INPUT,
LEVEL_INPUT,
NOTE_INPUT,
NUM_INPUTS
};
enum OutputIds {
OUT_OUTPUT,
AUX_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
ENUMS(MODEL_LIGHT, 8 * 2),
NUM_LIGHTS
};

plaits::Voice voice;
plaits::Patch patch;
plaits::Modulations modulations;
char shared_buffer[16384];
float triPhase = 0.f;

SampleRateConverter<2> outputSrc;
DoubleRingBuffer<Frame<2>, 256> outputBuffer;
bool lowCpu = false;
bool lpg = false;

SchmittTrigger model1Trigger;
SchmittTrigger model2Trigger;

Plaits() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
memset(shared_buffer, 0, sizeof(shared_buffer));
stmlib::BufferAllocator allocator(shared_buffer, sizeof(shared_buffer));
voice.Init(&allocator);

memset(&patch, 0, sizeof(patch));
memset(&modulations, 0, sizeof(modulations));
onReset();
}

void onReset() override {
patch.engine = 0;
patch.lpg_colour = 0.5f;
patch.decay = 0.5f;
}

void onRandomize() override {
patch.engine = randomu32() % 16;
}

json_t *toJson() override {
json_t *rootJ = json_object();

json_object_set_new(rootJ, "lowCpu", json_boolean(lowCpu));
json_object_set_new(rootJ, "model", json_integer(patch.engine));
json_object_set_new(rootJ, "lpgColor", json_real(patch.lpg_colour));
json_object_set_new(rootJ, "decay", json_real(patch.decay));

return rootJ;
}

void fromJson(json_t *rootJ) override {
json_t *lowCpuJ = json_object_get(rootJ, "lowCpu");
if (lowCpuJ)
lowCpu = json_boolean_value(lowCpuJ);

json_t *modelJ = json_object_get(rootJ, "model");
if (modelJ)
patch.engine = json_integer_value(modelJ);

json_t *lpgColorJ = json_object_get(rootJ, "lpgColor");
if (lpgColorJ)
patch.lpg_colour = json_number_value(lpgColorJ);

json_t *decayJ = json_object_get(rootJ, "decay");
if (decayJ)
patch.decay = json_number_value(decayJ);
}

void step() override {
if (outputBuffer.empty()) {
const int blockSize = 12;

// Model buttons
if (model1Trigger.process(params[MODEL1_PARAM].value)) {
if (patch.engine >= 8) {
patch.engine -= 8;
}
else {
patch.engine = (patch.engine + 1) % 8;
}
}
if (model2Trigger.process(params[MODEL2_PARAM].value)) {
if (patch.engine < 8) {
patch.engine += 8;
}
else {
patch.engine = (patch.engine + 1) % 8 + 8;
}
}

// Model lights
int activeEngine = voice.active_engine();
triPhase += 2.f * engineGetSampleTime() * blockSize;
if (triPhase >= 1.f)
triPhase -= 1.f;
float tri = (triPhase < 0.5f) ? triPhase * 2.f : (1.f - triPhase) * 2.f;

for (int i = 0; i < 8; i++) {
lights[MODEL_LIGHT + 2*i + 0].setBrightness((activeEngine == i) ? 1.f : (patch.engine == i) ? tri : 0.f);
lights[MODEL_LIGHT + 2*i + 1].setBrightness((activeEngine == i + 8) ? 1.f : (patch.engine == i + 8) ? tri : 0.f);
}

// Calculate pitch for lowCpu mode if needed
float pitch = params[FREQ_PARAM].value;
if (lowCpu)
pitch += log2f(48000.f * engineGetSampleTime());
// Update patch
patch.note = 60.f + pitch * 12.f;
patch.harmonics = params[HARMONICS_PARAM].value;
if (!lpg) {
patch.timbre = params[TIMBRE_PARAM].value;
patch.morph = params[MORPH_PARAM].value;
}
else {
patch.lpg_colour = params[TIMBRE_PARAM].value;
patch.decay = params[MORPH_PARAM].value;
}
patch.frequency_modulation_amount = params[FREQ_CV_PARAM].value;
patch.timbre_modulation_amount = params[TIMBRE_CV_PARAM].value;
patch.morph_modulation_amount = params[MORPH_CV_PARAM].value;

// Update modulations
modulations.engine = inputs[ENGINE_INPUT].value / 5.f;
modulations.note = inputs[NOTE_INPUT].value * 12.f;
modulations.frequency = inputs[FREQ_INPUT].value * 6.f;
modulations.harmonics = inputs[HARMONICS_INPUT].value / 5.f;
modulations.timbre = inputs[TIMBRE_INPUT].value / 8.f;
modulations.morph = inputs[MORPH_INPUT].value / 8.f;
// Triggers at around 0.7 V
modulations.trigger = inputs[TRIGGER_INPUT].value / 3.f;
modulations.level = inputs[LEVEL_INPUT].value / 8.f;

modulations.frequency_patched = inputs[FREQ_INPUT].active;
modulations.timbre_patched = inputs[TIMBRE_INPUT].active;
modulations.morph_patched = inputs[MORPH_INPUT].active;
modulations.trigger_patched = inputs[TRIGGER_INPUT].active;
modulations.level_patched = inputs[LEVEL_INPUT].active;

// Render frames
plaits::Voice::Frame output[blockSize];
voice.Render(patch, modulations, output, blockSize);

// Convert output to frames
Frame<2> outputFrames[blockSize];
for (int i = 0; i < blockSize; i++) {
outputFrames[i].samples[0] = output[i].out / 32768.f;
outputFrames[i].samples[1] = output[i].aux / 32768.f;
}

// Convert output
if (lowCpu) {
int len = min(outputBuffer.capacity(), blockSize);
memcpy(outputBuffer.endData(), outputFrames, len * sizeof(Frame<2>));
outputBuffer.endIncr(len);
}
else {
outputSrc.setRates(48000, engineGetSampleRate());
int inLen = blockSize;
int outLen = outputBuffer.capacity();
outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
outputBuffer.endIncr(outLen);
}
}

// Set output
if (!outputBuffer.empty()) {
Frame<2> outputFrame = outputBuffer.shift();
outputs[OUT_OUTPUT].value = outputFrame.samples[0] * 5.f;
outputs[AUX_OUTPUT].value = outputFrame.samples[1] * 5.f;
}
}
};


static const std::string modelLabels[16] = {
"Pair of classic waveforms",
"Waveshaping oscillator",
"Two operator FM",
"Granular formant oscillator",
"Harmonic oscillator",
"Wavetable oscillator",
"Chords",
"Vowel and speech synthesis",
"Granular cloud",
"Filtered noise",
"Particle noise",
"Inharmonic string modeling",
"Modal resonator",
"Analog bass drum",
"Analog snare drum",
"Analog hi-hat",
};


struct PlaitsWidget : ModuleWidget {
PlaitsWidget(Plaits *module) : ModuleWidget(module) {
setPanel(SVG::load(assetPlugin(plugin, "res/Plaits.svg")));

addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));

addParam(ParamWidget::create<TL1105>(mm2px(Vec(23.32685, 14.6539)), module, Plaits::MODEL1_PARAM, 0.0, 1.0, 0.0));
addParam(ParamWidget::create<TL1105>(mm2px(Vec(32.22764, 14.6539)), module, Plaits::MODEL2_PARAM, 0.0, 1.0, 0.0));
addParam(ParamWidget::create<Rogan3PSWhite>(mm2px(Vec(3.1577, 20.21088)), module, Plaits::FREQ_PARAM, -4.0, 4.0, 0.0));
addParam(ParamWidget::create<Rogan3PSWhite>(mm2px(Vec(39.3327, 20.21088)), module, Plaits::HARMONICS_PARAM, 0.0, 1.0, 0.5));
addParam(ParamWidget::create<Rogan1PSWhite>(mm2px(Vec(4.04171, 49.6562)), module, Plaits::TIMBRE_PARAM, 0.0, 1.0, 0.5));
addParam(ParamWidget::create<Rogan1PSWhite>(mm2px(Vec(42.71716, 49.6562)), module, Plaits::MORPH_PARAM, 0.0, 1.0, 0.5));
addParam(ParamWidget::create<Trimpot>(mm2px(Vec(7.88712, 77.60705)), module, Plaits::TIMBRE_CV_PARAM, -1.0, 1.0, 0.0));
addParam(ParamWidget::create<Trimpot>(mm2px(Vec(27.2245, 77.60705)), module, Plaits::FREQ_CV_PARAM, -1.0, 1.0, 0.0));
addParam(ParamWidget::create<Trimpot>(mm2px(Vec(46.56189, 77.60705)), module, Plaits::MORPH_CV_PARAM, -1.0, 1.0, 0.0));

addInput(Port::create<PJ301MPort>(mm2px(Vec(3.31381, 92.48067)), Port::INPUT, module, Plaits::ENGINE_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(14.75983, 92.48067)), Port::INPUT, module, Plaits::TIMBRE_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(26.20655, 92.48067)), Port::INPUT, module, Plaits::FREQ_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(37.65257, 92.48067)), Port::INPUT, module, Plaits::MORPH_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(49.0986, 92.48067)), Port::INPUT, module, Plaits::HARMONICS_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(3.31381, 107.08103)), Port::INPUT, module, Plaits::TRIGGER_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(14.75983, 107.08103)), Port::INPUT, module, Plaits::LEVEL_INPUT));
addInput(Port::create<PJ301MPort>(mm2px(Vec(26.20655, 107.08103)), Port::INPUT, module, Plaits::NOTE_INPUT));

addOutput(Port::create<PJ301MPort>(mm2px(Vec(37.65257, 107.08103)), Port::OUTPUT, module, Plaits::OUT_OUTPUT));
addOutput(Port::create<PJ301MPort>(mm2px(Vec(49.0986, 107.08103)), Port::OUTPUT, module, Plaits::AUX_OUTPUT));

addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 23.31649)), module, Plaits::MODEL_LIGHT + 0 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 28.71704)), module, Plaits::MODEL_LIGHT + 1 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 34.1162)), module, Plaits::MODEL_LIGHT + 2 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 39.51675)), module, Plaits::MODEL_LIGHT + 3 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 44.91731)), module, Plaits::MODEL_LIGHT + 4 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 50.31785)), module, Plaits::MODEL_LIGHT + 5 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 55.71771)), module, Plaits::MODEL_LIGHT + 6 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.79498, 61.11827)), module, Plaits::MODEL_LIGHT + 7 * 2));
}

void appendContextMenu(Menu *menu) override {
Plaits *module = dynamic_cast<Plaits*>(this->module);

struct PlaitsLowCpuItem : MenuItem {
Plaits *module;
void onAction(EventAction &e) override {
module->lowCpu ^= true;
}
};

struct PlaitsLPGItem : MenuItem {
Plaits *module;
void onAction(EventAction &e) override {
module->lpg ^= true;
}
};

struct PlaitsModelItem : MenuItem {
Plaits *module;
int model;
void onAction(EventAction &e) override {
module->patch.engine = model;
}
};

menu->addChild(MenuEntry::create());
PlaitsLowCpuItem *lowCpuItem = MenuItem::create<PlaitsLowCpuItem>("Low CPU", CHECKMARK(module->lowCpu));
lowCpuItem->module = module;
menu->addChild(lowCpuItem);
PlaitsLPGItem *lpgItem = MenuItem::create<PlaitsLPGItem>("Edit LPG response/decay", CHECKMARK(module->lpg));
lpgItem->module = module;
menu->addChild(lpgItem);

menu->addChild(new MenuEntry());
menu->addChild(MenuLabel::create("Models"));
for (int i = 0; i < 16; i++) {
PlaitsModelItem *modelItem = MenuItem::create<PlaitsModelItem>(modelLabels[i], CHECKMARK(module->patch.engine == i));
modelItem->module = module;
modelItem->model = i;
menu->addChild(modelItem);
}
}
};


Model *modelPlaits = Model::create<Plaits, PlaitsWidget>("Audible Instruments", "Plaits", "Macro Oscillator 2", OSCILLATOR_TAG, WAVESHAPER_TAG);


+ 1
- 1
src/Tides.cpp View File

@@ -145,7 +145,7 @@ void Tides::step() {
// Sync // Sync
// Slight deviation from spec here. // Slight deviation from spec here.
// Instead of toggling sync by holding the range button, just enable it if the clock port is plugged in. // 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].active);
generator.set_sync(inputs[CLOCK_INPUT].active && !sheep);


// Generator // Generator
generator.Process(sheep); generator.Process(sheep);


Loading…
Cancel
Save