@@ -1,9 +1,7 @@ | |||
ARCH ?= linux | |||
CXXFLAGS = -MMD -fPIC -g -Wall -std=c++11 -O3 -ffast-math -DTEST \ | |||
CXXFLAGS = -MMD -fPIC -g -Wall -std=c++11 -O3 -msse -mfpmath=sse -ffast-math -DTEST \ | |||
-I./src -I../../include -I./eurorack \ | |||
-fasm \ | |||
-finline \ | |||
-fshort-enums | |||
LDFLAGS = | |||
@@ -57,3 +57,51 @@ Percentages are progress amounts, X means won't port | |||
#### [100%] Branches (Bernoulli Gate) | |||
#### [100%] Blinds (Quad VC-polarizer) | |||
#### [100%] Veils (Quad VCA) | |||
### Sound sources | |||
- [[Macro Oscillator]] (based on [Braids](http://mutable-instruments.net/modules/braids)) | |||
- [[Modal Synthesizer]] (based on [Elements](http://mutable-instruments.net/modules/elements)) | |||
### Modulation sources | |||
- [[Tidal Modulator]] (based on [Tides](http://mutable-instruments.net/modules/tides)) | |||
### Sound modifiers | |||
- [[Texture Synthesizer]] (based on [Clouds](http://mutable-instruments.net/modules/clouds)) | |||
- [[Meta Modulator]] (based on [Warps](http://mutable-instruments.net/modules/warps)) | |||
- [[Resonator]] (based on [Rings](http://mutable-instruments.net/modules/rings)) | |||
### Plumbing | |||
- [[Multiples]] (based on [Links](http://mutable-instruments.net/modules/links)) | |||
- [[Utilities]] (based on [Kinks](http://mutable-instruments.net/modules/kinks)) | |||
- [[Mixer]] (based on [Shades](http://mutable-instruments.net/modules/shades)) | |||
- [[Bernoulli Gate]] (based on [Branches](http://mutable-instruments.net/modules/branches)) | |||
- [[Quad VC-polarizer]] (based on [Blinds](http://mutable-instruments.net/modules/blinds)) | |||
- [[Quad VCA]] (based on [Veils](http://mutable-instruments.net/modules/veils)) | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 | |||
 |
@@ -1,5 +1,6 @@ | |||
#include "AudibleInstruments.hpp" | |||
#include <string.h> | |||
#include "AudibleInstruments.hpp" | |||
#include "dsp.hpp" | |||
#include "braids/macro_oscillator.h" | |||
@@ -28,8 +29,8 @@ struct Braids : Module { | |||
}; | |||
braids::MacroOscillator *osc; | |||
int bufferFrame = 0; | |||
int16_t buffer[24] = {}; | |||
SampleRateConverter<1> src; | |||
DoubleRingBuffer<float, 256> outputBuffer; | |||
bool lastTrig = false; | |||
Braids(); | |||
@@ -54,9 +55,6 @@ Braids::~Braids() { | |||
} | |||
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) { | |||
@@ -64,8 +62,8 @@ void Braids::step() { | |||
} | |||
lastTrig = trig; | |||
if (++bufferFrame >= 24) { | |||
bufferFrame = 0; | |||
// Render frames | |||
if (outputBuffer.empty()) { | |||
// Set shape | |||
int shape = roundf(params[SHAPE_PARAM]); | |||
osc->set_shape((braids::MacroOscillatorShape) shape); | |||
@@ -82,8 +80,28 @@ void Braids::step() { | |||
int16_t p = clampf((pitch * 12.0 + 60) * 128, 0, INT16_MAX); | |||
osc->set_pitch(p); | |||
// TODO: add a sync input buffer (must be sample rate converted) | |||
uint8_t sync_buffer[24] = {}; | |||
osc->Render(sync_buffer, buffer, 24); | |||
int16_t render_buffer[24]; | |||
osc->Render(sync_buffer, render_buffer, 24); | |||
// Sample rate convert | |||
float in[24]; | |||
for (int i = 0; i < 24; i++) { | |||
in[i] = render_buffer[i] / 32768.0; | |||
} | |||
src.setRatio(gRack->sampleRate / 96000.0); | |||
int inLen = 24; | |||
int outLen = outputBuffer.capacity(); | |||
src.process(in, &inLen, outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
} | |||
// Output | |||
if (!outputBuffer.empty()) { | |||
setf(outputs[OUT_OUTPUT], 5.0 * outputBuffer.shift()); | |||
} | |||
} | |||
@@ -45,8 +45,8 @@ static void computeChannel(const float *in, const float *p, float threshold, flo | |||
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)); | |||
float r = randomf(); | |||
bool toss = (r < threshold + getf(p)); | |||
if (mode < 0.5) { | |||
// direct mode | |||
*outcome = toss; | |||
@@ -1,5 +1,6 @@ | |||
#include "AudibleInstruments.hpp" | |||
#include <string.h> | |||
#include "AudibleInstruments.hpp" | |||
#include "dsp.hpp" | |||
#include "clouds/dsp/granular_processor.h" | |||
@@ -33,14 +34,15 @@ struct Clouds : Module { | |||
NUM_OUTPUTS | |||
}; | |||
SampleRateConverter<2> inputSrc; | |||
SampleRateConverter<2> outputSrc; | |||
DoubleRingBuffer<Frame<2>, 256> inputBuffer; | |||
DoubleRingBuffer<Frame<2>, 256> outputBuffer; | |||
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(); | |||
@@ -56,10 +58,8 @@ Clouds::Clouds() { | |||
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); | |||
block_mem = new uint8_t[memLen](); | |||
block_ccm = new uint8_t[ccmLen](); | |||
processor = new clouds::GranularProcessor(); | |||
memset(processor, 0, sizeof(*processor)); | |||
@@ -73,21 +73,42 @@ Clouds::~Clouds() { | |||
} | |||
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]); | |||
// Get input | |||
if (!inputBuffer.full()) { | |||
Frame<2> inputFrame; | |||
inputFrame.samples[0] = getf(inputs[IN_L_INPUT]) * params[IN_GAIN_PARAM] / 5.0; | |||
inputFrame.samples[1] = getf(inputs[IN_R_INPUT]) * params[IN_GAIN_PARAM] / 5.0; | |||
inputBuffer.push(inputFrame); | |||
} | |||
// Trigger | |||
if (getf(inputs[TRIG_INPUT]) >= 1.0) { | |||
triggered = true; | |||
} | |||
if (++bufferFrame >= 32) { | |||
bufferFrame = 0; | |||
// Render frames | |||
if (outputBuffer.empty()) { | |||
clouds::ShortFrame input[32] = {}; | |||
// Convert input buffer | |||
{ | |||
inputSrc.setRatio(32000.0 / gRack->sampleRate); | |||
Frame<2> inputFrames[32]; | |||
int inLen = inputBuffer.size(); | |||
int outLen = 32; | |||
inputSrc.process((const float*) inputBuffer.startData(), &inLen, (float*) inputFrames, &outLen); | |||
inputBuffer.startIncr(inLen); | |||
// We might not fill all of the input buffer if there is a deficiency, but this cannot be avoided due to imprecisions between the input and output SRC. | |||
for (int i = 0; i < outLen; i++) { | |||
input[i].l = clampf(inputFrames[i].samples[0] * 32767.0, -32768, 32767); | |||
input[i].r = clampf(inputFrames[i].samples[1] * 32767.0, -32768, 32767); | |||
} | |||
} | |||
// Set up processor | |||
processor->set_num_channels(2); | |||
processor->set_low_fidelity(false); | |||
// TODO Support the other modes | |||
processor->set_playback_mode(clouds::PLAYBACK_MODE_GRANULAR); | |||
processor->Prepare(); | |||
@@ -105,22 +126,33 @@ void Clouds::step() { | |||
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; | |||
// Convert output buffer | |||
{ | |||
Frame<2> outputFrames[32]; | |||
for (int i = 0; i < 32; i++) { | |||
outputFrames[i].samples[0] = output[i].l / 32768.0; | |||
outputFrames[i].samples[1] = output[i].r / 32768.0; | |||
} | |||
outputSrc.setRatio(gRack->sampleRate / 32000.0); | |||
int inLen = 32; | |||
int outLen = outputBuffer.capacity(); | |||
outputSrc.process((const float*) outputFrames, &inLen, (float*) outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
} | |||
triggered = false; | |||
} | |||
// Set output | |||
if (!outputBuffer.empty()) { | |||
Frame<2> outputFrame = outputBuffer.shift(); | |||
setf(outputs[OUT_L_OUTPUT], 5.0 * outputFrame.samples[0]); | |||
setf(outputs[OUT_R_OUTPUT], 5.0 * outputFrame.samples[1]); | |||
} | |||
} | |||
@@ -1,5 +1,6 @@ | |||
#include "AudibleInstruments.hpp" | |||
#include <string.h> | |||
#include "AudibleInstruments.hpp" | |||
#include "dsp.hpp" | |||
#include "elements/dsp/part.h" | |||
@@ -65,13 +66,13 @@ struct Elements : Module { | |||
NUM_OUTPUTS | |||
}; | |||
SampleRateConverter<2> inputSrc; | |||
SampleRateConverter<2> outputSrc; | |||
DoubleRingBuffer<Frame<2>, 256> inputBuffer; | |||
DoubleRingBuffer<Frame<2>, 256> outputBuffer; | |||
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(); | |||
@@ -99,14 +100,36 @@ Elements::~Elements() { | |||
} | |||
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; | |||
// Get input | |||
if (!inputBuffer.full()) { | |||
Frame<2> inputFrame; | |||
inputFrame.samples[0] = getf(inputs[BLOW_INPUT]) / 5.0; | |||
inputFrame.samples[1] = getf(inputs[STRIKE_INPUT]) / 5.0; | |||
inputBuffer.push(inputFrame); | |||
} | |||
// Render frames | |||
if (outputBuffer.empty()) { | |||
float blow[16] = {}; | |||
float strike[16] = {}; | |||
float main[16]; | |||
float aux[16]; | |||
// Convert input buffer | |||
{ | |||
inputSrc.setRatio(32000.0 / gRack->sampleRate); | |||
Frame<2> inputFrames[16]; | |||
int inLen = inputBuffer.size(); | |||
int outLen = 16; | |||
inputSrc.process((float*) inputBuffer.startData(), &inLen, (float*) inputFrames, &outLen); | |||
inputBuffer.startIncr(inLen); | |||
for (int i = 0; i < outLen; i++) { | |||
blow[i] = inputFrames[i].samples[0]; | |||
strike[i] = inputFrames[i].samples[1]; | |||
} | |||
} | |||
// Set patch from parameters | |||
elements::Patch* p = part->mutable_patch(); | |||
p->exciter_envelope_shape = params[CONTOUR_PARAM]; | |||
@@ -114,7 +137,7 @@ void Elements::step() { | |||
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) | |||
#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); | |||
@@ -137,10 +160,32 @@ void Elements::step() { | |||
// Generate audio | |||
part->Process(performance, blow, strike, main, aux, 16); | |||
// Convert output buffer | |||
{ | |||
Frame<2> outputFrames[16]; | |||
for (int i = 0; i < 16; i++) { | |||
outputFrames[i].samples[0] = main[i]; | |||
outputFrames[i].samples[1] = aux[i]; | |||
} | |||
outputSrc.setRatio(gRack->sampleRate / 32000.0); | |||
int inLen = 16; | |||
int outLen = outputBuffer.capacity(); | |||
outputSrc.process((float*) outputFrames, &inLen, (float*) outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
} | |||
// Set lights | |||
lights[0] = part->exciter_level(); | |||
lights[1] = part->resonator_level(); | |||
} | |||
// Set output | |||
if (!outputBuffer.empty()) { | |||
Frame<2> outputFrame = outputBuffer.shift(); | |||
setf(outputs[AUX_OUTPUT], 5.0 * outputFrame.samples[0]); | |||
setf(outputs[MAIN_OUTPUT], 5.0 * outputFrame.samples[1]); | |||
} | |||
} | |||
@@ -28,7 +28,6 @@ struct Kinks : Module { | |||
NUM_OUTPUTS | |||
}; | |||
std::normal_distribution<float> dist; | |||
float lastTrig = 0.0; | |||
float sample = 0.0; | |||
float lights[3] = {}; | |||
@@ -38,7 +37,7 @@ struct Kinks : Module { | |||
}; | |||
Kinks::Kinks() : dist(0.0, 1.0) { | |||
Kinks::Kinks() { | |||
params.resize(NUM_PARAMS); | |||
inputs.resize(NUM_INPUTS); | |||
outputs.resize(NUM_OUTPUTS); | |||
@@ -46,11 +45,11 @@ Kinks::Kinks() : dist(0.0, 1.0) { | |||
void Kinks::step() { | |||
// Gaussian noise generator | |||
float noise = 2.0 * dist(rng); | |||
float noise = 2.0 * randomNormal(); | |||
// S&H | |||
float trig = getf(inputs[TRIG_INPUT]); | |||
float dtrig = (trig - lastTrig) * SAMPLE_RATE; | |||
float dtrig = (trig - lastTrig) * gRack->sampleRate; | |||
if (dtrig > DTRIG) { | |||
sample = getf(inputs[SH_INPUT], noise); | |||
} | |||
@@ -1,5 +1,6 @@ | |||
#include "AudibleInstruments.hpp" | |||
#include <string.h> | |||
#include "AudibleInstruments.hpp" | |||
#include "dsp.hpp" | |||
#include "rings/dsp/part.h" | |||
#include "rings/dsp/strummer.h" | |||
#include "rings/dsp/string_synth_part.h" | |||
@@ -41,11 +42,12 @@ struct Rings : Module { | |||
NUM_OUTPUTS | |||
}; | |||
SampleRateConverter<1> inputSrc; | |||
SampleRateConverter<2> outputSrc; | |||
DoubleRingBuffer<float, 256> inputBuffer; | |||
DoubleRingBuffer<Frame<2>, 256> outputBuffer; | |||
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; | |||
@@ -76,33 +78,36 @@ 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); | |||
// Get input | |||
if (!inputBuffer.full()) { | |||
float inputFrame = getf(inputs[IN_INPUT]) / 5.0; | |||
inputBuffer.push(inputFrame); | |||
} | |||
if (!strum) { | |||
strum = getf(inputs[STRUM_INPUT]) >= 1.0; | |||
} | |||
if (++bufferFrame >= 24) { | |||
bufferFrame = 0; | |||
// Render frames | |||
if (outputBuffer.empty()) { | |||
float in[24] = {}; | |||
// Convert input buffer | |||
{ | |||
inputSrc.setRatio(48000.0 / gRack->sampleRate); | |||
int inLen = inputBuffer.size(); | |||
int outLen = 24; | |||
inputSrc.process(inputBuffer.startData(), &inLen, (float*) in, &outLen); | |||
inputBuffer.startIncr(inLen); | |||
} | |||
// modes | |||
int polyphony = 1; | |||
int polyphony; | |||
switch ((int) roundf(params[POLYPHONY_PARAM])) { | |||
case 1: polyphony = 2; break; | |||
case 2: polyphony = 4; break; | |||
default: polyphony = 1; | |||
} | |||
if (polyphony != part.polyphony()) { | |||
part.set_polyphony(polyphony); | |||
@@ -145,6 +150,8 @@ void Rings::step() { | |||
performance_state.chord = clampf(roundf(structure * (rings::kNumChords - 1)), 0, rings::kNumChords - 1); | |||
// Process audio | |||
float out[24]; | |||
float aux[24]; | |||
if (0) { | |||
// strummer.Process(NULL, 24, &performance_state); | |||
// string_synth.Process(performance_state, patch, in, out, aux, 24); | |||
@@ -153,7 +160,38 @@ void Rings::step() { | |||
strummer.Process(in, 24, &performance_state); | |||
part.Process(performance_state, patch, in, out, aux, 24); | |||
} | |||
// Convert output buffer | |||
{ | |||
Frame<2> outputFrames[24]; | |||
for (int i = 0; i < 24; i++) { | |||
outputFrames[i].samples[0] = out[i]; | |||
outputFrames[i].samples[1] = aux[i]; | |||
} | |||
outputSrc.setRatio(gRack->sampleRate / 48000.0); | |||
int inLen = 24; | |||
int outLen = outputBuffer.capacity(); | |||
outputSrc.process((const float*) outputFrames, &inLen, (float*) outputBuffer.endData(), &outLen); | |||
outputBuffer.endIncr(outLen); | |||
} | |||
} | |||
// Set output | |||
if (!outputBuffer.empty()) { | |||
Frame<2> outputFrame = outputBuffer.shift(); | |||
// "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(outputFrame.samples[0], -1.0, 1.0)*5.0); | |||
setf(outputs[EVEN_OUTPUT], clampf(outputFrame.samples[1], -1.0, 1.0)*5.0); | |||
} | |||
else { | |||
float v = clampf(outputFrame.samples[0] + outputFrame.samples[1], -1.0, 1.0)*5.0; | |||
setf(outputs[ODD_OUTPUT], v); | |||
setf(outputs[EVEN_OUTPUT], v); | |||
} | |||
} | |||
} | |||
@@ -82,6 +82,8 @@ void Tides::step() { | |||
pitch += 12.0*getf(inputs[PITCH_INPUT]); | |||
pitch += params[FM_PARAM] * getf(inputs[FM_INPUT], 0.1) / 5.0; | |||
pitch += 60.0; | |||
// Scale to the global sample rate | |||
pitch += log2f(48000.0 / gRack->sampleRate) * 12.0; | |||
generator.set_pitch(clampf(pitch*0x80, -0x8000, 0x7fff)); | |||
// Slope, smoothness, pitch | |||
@@ -108,10 +108,10 @@ VeilsWidget::VeilsWidget() : ModuleWidget(new Veils()) { | |||
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<SmallWhiteKnob>(Vec(8, 52), module, Veils::GAIN1_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<SmallWhiteKnob>(Vec(8, 131), module, Veils::GAIN2_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<SmallWhiteKnob>(Vec(8, 210), module, Veils::GAIN3_PARAM, 0.0, 1.0, 0.0)); | |||
addParam(createParam<SmallWhiteKnob>(Vec(8, 288), module, Veils::GAIN4_PARAM, 0.0, 1.0, 0.0)); | |||
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)); | |||
@@ -61,6 +61,7 @@ void Warps::step() { | |||
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; | |||
p->note += log2f(96000.0 / gRack->sampleRate) * 12.0; | |||
float state = roundf(params[STATE_PARAM]); | |||
p->carrier_shape = (int32_t)state; | |||
lights[0] = state - 1.0; | |||