Browse Source

Implement normal Frames mode

tags/v0.4.0
Andrew Belt 7 years ago
parent
commit
6953cbf1cd
1 changed files with 111 additions and 43 deletions
  1. +111
    -43
      src/Frames.cpp

+ 111
- 43
src/Frames.cpp View File

@@ -42,6 +42,7 @@ struct Frames : Module {
frames::Keyframer keyframer;
frames::PolyLfo poly_lfo;
bool poly_lfo_mode = true;
uint16_t lastControls[4] = {};

SchmittTrigger addTrigger;
SchmittTrigger delTrigger;
@@ -49,6 +50,18 @@ struct Frames : Module {

Frames();
void step();

json_t *toJson() {
json_t *rootJ = json_object();
json_object_set_new(rootJ, "polyLfo", json_boolean(poly_lfo_mode));
return rootJ;
}

void fromJson(json_t *rootJ) {
json_t *polyLfoJ = json_object_get(rootJ, "polyLfo");
if (polyLfoJ)
poly_lfo_mode = json_boolean_value(polyLfoJ);
}
};


@@ -57,46 +70,64 @@ Frames::Frames() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
keyframer.Init();
memset(&poly_lfo, 0, sizeof(poly_lfo));
poly_lfo.Init();

for (int i = 0; i < 4; i++) {
keyframer.mutable_settings(i)->easing_curve = frames::EASING_CURVE_LINEAR;
}
}


void Frames::step() {
// Handle buttons
if (clearKeyframes) {
keyframer.Clear();
clearKeyframes = false;
// Set gain and timestamp knobs
uint16_t controls[4];
for (int i = 0; i < 4; i++) {
controls[i] = params[GAIN1_PARAM + i].value * 65535.0;
}

// Set gain knobs
if (poly_lfo_mode) {
poly_lfo.set_shape(params[GAIN1_PARAM].value * 65535.0);
poly_lfo.set_shape_spread(params[GAIN2_PARAM].value * 65535.0);
poly_lfo.set_spread(params[GAIN3_PARAM].value * 65535.0);
poly_lfo.set_coupling(params[GAIN4_PARAM].value * 65535.0);
}
else {
for (int i = 0; i < 4; i++) {
keyframer.set_immediate(i, params[GAIN1_PARAM + i].value * 65535.0);
}
int32_t timestamp = clampf(params[FRAME_PARAM].value + params[MODULATION_PARAM].value * inputs[FRAME_INPUT].value / 10.0, 0.0, 1.0) * 65535.0;
int16_t nearestIndex = -1;
if (!poly_lfo_mode) {
nearestIndex = keyframer.FindNearestKeyframe(timestamp, 2048);
}

int32_t frame = clampf(params[FRAME_PARAM].value + params[MODULATION_PARAM].value * inputs[FRAME_INPUT].value / 10.0, 0.0, 1.0) * 65535.0;

// Render, handle buttons
if (poly_lfo_mode) {
poly_lfo.Render(frame);
if (controls[0] != lastControls[0])
poly_lfo.set_shape(controls[0]);
if (controls[1] != lastControls[1])
poly_lfo.set_shape_spread(controls[1]);
if (controls[2] != lastControls[2])
poly_lfo.set_spread(controls[2]);
if (controls[3] != lastControls[3])
poly_lfo.set_coupling(controls[3]);
poly_lfo.Render(timestamp);
}
else {
int16_t nearestFrame = keyframer.FindNearestKeyframe(frame, 2048);
for (int i = 0; i < 4; i++) {
if (controls[i] != lastControls[i]) {
// Update recently moved control
if (keyframer.num_keyframes() == 0) {
keyframer.set_immediate(i, controls[i]);
}
if (nearestIndex >= 0) {
frames::Keyframe *nearestKeyframe = keyframer.mutable_keyframe(nearestIndex);
nearestKeyframe->values[i] = controls[i];
}
}
}

if (addTrigger.process(params[ADD_PARAM].value)) {
uint16_t f[4] = {65000, 30000, 20000, 10000};
keyframer.AddKeyframe(frame, f);
if (nearestIndex < 0) {
keyframer.AddKeyframe(timestamp, controls);
}
}
if (delTrigger.process(params[DEL_PARAM].value)) {
keyframer.RemoveKeyframe(frame);
if (nearestIndex >= 0) {
int32_t nearestTimestamp = keyframer.keyframe(nearestIndex).timestamp;
keyframer.RemoveKeyframe(nearestTimestamp);
}
}
keyframer.Evaluate(frame);
keyframer.Evaluate(timestamp);
}

// Get gains
@@ -111,48 +142,61 @@ void Frames::step() {
gains[i] = lin;
}
}
// printf("%f %f %f %f\n", gains[0], gains[1], gains[2], gains[3]);

// Update last controls
for (int i = 0; i < 4; i++) {
lastControls[i] = controls[i];
}

// Get inputs
float all = ((int)params[OFFSET_PARAM].value == 1) ? 10.0 : 0.0;
if (inputs[ALL_INPUT].active)
if (inputs[ALL_INPUT].active) {
all = inputs[ALL_INPUT].value;
}

float ins[4];
for (int i = 0; i < 4; i++)
for (int i = 0; i < 4; i++) {
ins[i] = inputs[IN1_INPUT + i].normalize(all) * gains[i];
}

// Set outputs
float mix = 0.0;

for (int i = 0; i < 4; i++) {
if (outputs[OUT1_OUTPUT + i].active)
if (outputs[OUT1_OUTPUT + i].active) {
outputs[OUT1_OUTPUT + i].value = ins[i];
else
}
else {
mix += ins[i];
}
}

outputs[MIX_OUTPUT].value = clampf(mix / 2.0, -10.0, 10.0);

// Set lights
for (int i = 0; i < 4; i++)
for (int i = 0; i < 4; i++) {
outputs[GAIN1_LIGHT + i].value = gains[i];
}

if (poly_lfo_mode) {
outputs[EDIT_LIGHT].value = (poly_lfo.level(0) > 128 ? 1.0 : 0.0);
}
else {
outputs[EDIT_LIGHT].value = 1.0;
// TODO
outputs[EDIT_LIGHT].value = (nearestIndex >= 0 ? 1.0 : 0.0);
}

// Set frame light colors
const uint8_t *colors;
if (poly_lfo_mode)
if (poly_lfo_mode) {
colors = poly_lfo.color();
else
}
else {
colors = keyframer.color();
for (int c = 0; c < 3; c++)
}
for (int c = 0; c < 3; c++) {
outputs[FRAME_LIGHT + c].value = colors[c] / 255.0;
}
}


@@ -244,24 +288,48 @@ FramesWidget::FramesWidget() {
}


struct FramesCurveItem : MenuItem {
Frames *frames;
uint8_t channel;
frames::EasingCurve curve;
void onAction() {
frames->keyframer.mutable_settings(channel)->easing_curve = curve;
}
void step() {
rightText = (frames->keyframer.mutable_settings(channel)->easing_curve == curve) ? "✔" : "";
}
};

struct FramesResponseItem : MenuItem {
Frames *frames;
uint8_t channel;
uint8_t response;
void onAction() {
frames->keyframer.mutable_settings(channel)->response = response;
}
void step() {
rightText = (frames->keyframer.mutable_settings(channel)->response = response) ? "✔" : "";
}
};

struct FramesChannelSettingsItem : MenuItem {
Frames *frames;
int channel;
uint8_t channel;
Menu *createChildMenu() {
Menu *menu = new Menu();

// TODO
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Interpolation Curve"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Step"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Linear"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Accelerating"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Decelerating"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Smooth Departure/Arrival"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Bouncing"));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Step", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_STEP));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Linear", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_LINEAR));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Accelerating", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_IN_QUARTIC));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Decelerating", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_OUT_QUARTIC));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Smooth Departure/Arrival", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_SINE));
menu->pushChild(construct<FramesCurveItem>(&MenuEntry::text, "Bouncing", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_BOUNCE));
menu->pushChild(construct<MenuLabel>());
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Response Curve"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Linear"));
menu->pushChild(construct<MenuItem>(&MenuEntry::text, "Exponential"));
menu->pushChild(construct<FramesResponseItem>(&MenuEntry::text, "Linear", &FramesResponseItem::frames, frames, &FramesResponseItem::channel, channel, &FramesResponseItem::response, 0));
menu->pushChild(construct<FramesResponseItem>(&MenuEntry::text, "Exponential", &FramesResponseItem::frames, frames, &FramesResponseItem::channel, channel, &FramesResponseItem::response, 1));

return menu;
}
@@ -270,7 +338,7 @@ struct FramesChannelSettingsItem : MenuItem {
struct FramesClearItem : MenuItem {
Frames *frames;
void onAction() {
frames->clearKeyframes = true;
frames->keyframer.Clear();
}
};



Loading…
Cancel
Save