Browse Source

Update MIDI-CV panel. Prepare MIDI-CV for polyphony. Add "v" to version strings.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
b4be621ddc
13 changed files with 1336 additions and 496 deletions
  1. +1
    -1
      Makefile
  2. +2
    -2
      include/app/common.hpp
  3. +1
    -0
      include/dsp/common.hpp
  4. +6
    -4
      include/dsp/filter.hpp
  5. +1093
    -345
      res/Core/MIDI-CV.svg
  6. +6
    -3
      src/Core/MIDI_CC.cpp
  7. +213
    -128
      src/Core/MIDI_CV.cpp
  8. +2
    -2
      src/app/ModuleWidget.cpp
  9. +4
    -3
      src/app/Scene.cpp
  10. +1
    -1
      src/main.cpp
  11. +3
    -3
      src/patch.cpp
  12. +1
    -1
      src/plugin.cpp
  13. +3
    -3
      src/window.cpp

+ 1
- 1
Makefile View File

@@ -1,7 +1,7 @@
RACK_DIR ?= . RACK_DIR ?= .
VERSION = 1.dev.$(shell git rev-parse --short HEAD) VERSION = 1.dev.$(shell git rev-parse --short HEAD)


FLAGS += -DAPP_VERSION=$(VERSION)
FLAGS += -DVERSION=$(VERSION)
FLAGS += -Iinclude FLAGS += -Iinclude
FLAGS += -Idep/include -Idep/lib/libzip/include FLAGS += -Idep/include -Idep/lib/libzip/include




+ 2
- 2
include/app/common.hpp View File

@@ -8,8 +8,8 @@ namespace rack {
namespace app { namespace app {




static const char NAME[] = "VCV Rack";
static const char VERSION[] = TOSTRING(APP_VERSION);
static const char APP_NAME[] = "VCV Rack";
static const char APP_VERSION[] = TOSTRING(VERSION);
static const char API_URL[] = "https://api.vcvrack.com"; static const char API_URL[] = "https://api.vcvrack.com";


static const float SVG_DPI = 75.0; static const float SVG_DPI = 75.0;


+ 1
- 0
include/dsp/common.hpp View File

@@ -33,6 +33,7 @@ inline float hann(float p) {
return 0.5f * (1.f - std::cos(2*M_PI * p)); return 0.5f * (1.f - std::cos(2*M_PI * p));
} }


/** Applies the Hann window to a signal `x` */
inline void hannWindow(float *x, int len) { inline void hannWindow(float *x, int len) {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
x[i] *= hann((float) i / (len - 1)); x[i] *= hann((float) i / (len - 1));


+ 6
- 4
include/dsp/filter.hpp View File

@@ -84,14 +84,14 @@ struct ExponentialSlewLimiter {




/** Applies exponential smoothing to a signal with the ODE /** Applies exponential smoothing to a signal with the ODE
dy/dt = x * lambda
\f$ \frac{dy}{dt} = x \lambda \f$.
*/ */
struct ExponentialFilter { struct ExponentialFilter {
float out = 0.f; float out = 0.f;
float lambda = 1.f;
float lambda = 0.f;


float process(float in) {
float y = out + (in - out) * lambda;
float process(float deltaTime, float in) {
float y = out + (in - out) * lambda * deltaTime;
// If no change was detected, assume float granularity is too small and snap output to input // If no change was detected, assume float granularity is too small and snap output to input
if (out == y) if (out == y)
out = in; out = in;
@@ -99,6 +99,8 @@ struct ExponentialFilter {
out = y; out = y;
return out; return out;
} }

DEPRECATED float process(float in) {return process(1.f, in);}
}; };






+ 1093
- 345
res/Core/MIDI-CV.svg
File diff suppressed because it is too large
View File


+ 6
- 3
src/Core/MIDI_CC.cpp View File

@@ -25,6 +25,9 @@ struct MIDI_CC : Module {


MIDI_CC() { MIDI_CC() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
for (int i = 0; i < 16; i++) {
valueFilters[i].lambda = 1 / 0.01f;
}
onReset(); onReset();
} }


@@ -45,7 +48,8 @@ struct MIDI_CC : Module {
processMessage(msg); processMessage(msg);
} }


float lambda = APP->engine->getSampleTime() * 100.f;
float deltaTime = APP->engine->getSampleTime();

for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (!outputs[CC_OUTPUT + i].isConnected()) if (!outputs[CC_OUTPUT + i].isConnected())
continue; continue;
@@ -53,7 +57,6 @@ struct MIDI_CC : Module {
int cc = learnedCcs[i]; int cc = learnedCcs[i];


float value = rescale(values[cc], 0, 127, 0.f, 10.f); float value = rescale(values[cc], 0, 127, 0.f, 10.f);
valueFilters[i].lambda = lambda;


// Detect behavior from MIDI buttons. // Detect behavior from MIDI buttons.
if ((lastValues[i] == 0 && values[cc] == 127) || (lastValues[i] == 127 && values[cc] == 0)) { if ((lastValues[i] == 0 && values[cc] == 127) || (lastValues[i] == 127 && values[cc] == 0)) {
@@ -62,7 +65,7 @@ struct MIDI_CC : Module {
} }
else { else {
// Smooth value with filter // Smooth value with filter
valueFilters[i].process(value);
valueFilters[i].process(deltaTime, value);
} }
lastValues[i] = values[cc]; lastValues[i] = values[cc];
outputs[CC_OUTPUT + i].setVoltage(valueFilters[i].out); outputs[CC_OUTPUT + i].setVoltage(valueFilters[i].out);


+ 213
- 128
src/Core/MIDI_CV.cpp View File

@@ -18,8 +18,8 @@ struct MIDI_CV : Module {
PITCH_OUTPUT, PITCH_OUTPUT,
MOD_OUTPUT, MOD_OUTPUT,
RETRIGGER_OUTPUT, RETRIGGER_OUTPUT,
CLOCK_1_OUTPUT,
CLOCK_2_OUTPUT,
CLOCK_OUTPUT,
CLOCK_DIV_OUTPUT,
START_OUTPUT, START_OUTPUT,
STOP_OUTPUT, STOP_OUTPUT,
CONTINUE_OUTPUT, CONTINUE_OUTPUT,
@@ -31,43 +31,57 @@ struct MIDI_CV : Module {


midi::InputQueue midiInput; midi::InputQueue midiInput;


uint8_t mod = 0;
dsp::ExponentialFilter modFilter;
// std::vector<uint8_t> heldNotes;

int channels;
enum PolyMode {
ROTATE_MODE,
REUSE_MODE,
RESET_MODE,
REASSIGN_MODE,
NUM_POLY_MODES
};
PolyMode polyMode;

uint32_t clock = 0;
int clockDivision;

bool pedal = false;
uint8_t notes[16] = {60};
bool gates[128] = {};
uint8_t velocities[128] = {};
uint8_t aftertouches[128] = {};

uint16_t pitch = 8192; uint16_t pitch = 8192;
uint8_t mod = 0;

dsp::ExponentialFilter pitchFilter; dsp::ExponentialFilter pitchFilter;
dsp::PulseGenerator retriggerPulse;
dsp::PulseGenerator clockPulses[2];
dsp::ExponentialFilter modFilter;
dsp::PulseGenerator clockPulse;
dsp::PulseGenerator clockDividerPulse;
dsp::PulseGenerator retriggerPulses[16];
dsp::PulseGenerator startPulse; dsp::PulseGenerator startPulse;
dsp::PulseGenerator stopPulse; dsp::PulseGenerator stopPulse;
dsp::PulseGenerator continuePulse; dsp::PulseGenerator continuePulse;
int clock = 0;
int divisions[2];

struct NoteData {
uint8_t velocity = 0;
uint8_t aftertouch = 0;
};


NoteData noteData[128];
std::vector<uint8_t> heldNotes;
uint8_t lastNote;
bool pedal;
bool gate;


MIDI_CV() { MIDI_CV() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
heldNotes.resize(128, 0);
// heldNotes.resize(128, 0);
pitchFilter.lambda = 1 / 0.01f;
modFilter.lambda = 1 / 0.01f;
onReset(); onReset();
} }


void onReset() override { void onReset() override {
heldNotes.clear();
lastNote = 60;
pedal = false;
gate = false;
clock = 0;
divisions[0] = 24;
divisions[1] = 6;
// heldNotes.clear();
// lastNote = 60;
// pedal = false;
// gate = false;
// clock = 0;
channels = 1;
polyMode = RESET_MODE;
clockDivision = 24;
midiInput.reset(); midiInput.reset();
} }


@@ -78,20 +92,26 @@ struct MIDI_CV : Module {
} }
float deltaTime = APP->engine->getSampleTime(); float deltaTime = APP->engine->getSampleTime();


outputs[CV_OUTPUT].setVoltage((lastNote - 60) / 12.f);
outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f);
outputs[VELOCITY_OUTPUT].setVoltage(rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f));

outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f));
pitchFilter.lambda = 100.f * deltaTime;
outputs[PITCH_OUTPUT].setVoltage(pitchFilter.process(rescale(pitch, 0, 16384, -5.f, 5.f)));
modFilter.lambda = 100.f * deltaTime;
outputs[MOD_OUTPUT].setVoltage(modFilter.process(rescale(mod, 0, 127, 0.f, 10.f)));
outputs[CV_OUTPUT].setChannels(channels);
outputs[GATE_OUTPUT].setChannels(channels);
outputs[VELOCITY_OUTPUT].setChannels(channels);
outputs[AFTERTOUCH_OUTPUT].setChannels(channels);
outputs[RETRIGGER_OUTPUT].setChannels(channels);
for (int c = 0; c < channels; c++) {
uint8_t note = notes[c];
outputs[CV_OUTPUT].setVoltage((note - 60.f) / 12.f, c);
outputs[GATE_OUTPUT].setVoltage(gates[note] ? 10.f : 0.f, c);
outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[note], 0, 127, 0.f, 10.f), c);
outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[note], 0, 127, 0.f, 10.f), c);
outputs[RETRIGGER_OUTPUT].setVoltage(retriggerPulses[c].process(deltaTime) ? 10.f : 0.f, c);
}


outputs[RETRIGGER_OUTPUT].setVoltage(retriggerPulse.process(deltaTime) ? 10.f : 0.f);
outputs[CLOCK_1_OUTPUT].setVoltage(clockPulses[0].process(deltaTime) ? 10.f : 0.f);
outputs[CLOCK_2_OUTPUT].setVoltage(clockPulses[1].process(deltaTime) ? 10.f : 0.f);
uint16_t pitchAdjusted = (pitch == 16383) ? 16384 : pitch;
outputs[PITCH_OUTPUT].setVoltage(pitchFilter.process(deltaTime, rescale(pitchAdjusted, 0, 1<<14, -5.f, 5.f)));
outputs[MOD_OUTPUT].setVoltage(modFilter.process(deltaTime, rescale(mod, 0, 127, 0.f, 10.f)));


outputs[CLOCK_OUTPUT].setVoltage(clockPulse.process(deltaTime) ? 10.f : 0.f);
outputs[CLOCK_DIV_OUTPUT].setVoltage(clockDividerPulse.process(deltaTime) ? 10.f : 0.f);
outputs[START_OUTPUT].setVoltage(startPulse.process(deltaTime) ? 10.f : 0.f); outputs[START_OUTPUT].setVoltage(startPulse.process(deltaTime) ? 10.f : 0.f);
outputs[STOP_OUTPUT].setVoltage(stopPulse.process(deltaTime) ? 10.f : 0.f); outputs[STOP_OUTPUT].setVoltage(stopPulse.process(deltaTime) ? 10.f : 0.f);
outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(deltaTime) ? 10.f : 0.f); outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(deltaTime) ? 10.f : 0.f);
@@ -108,7 +128,7 @@ struct MIDI_CV : Module {
// note on // note on
case 0x9: { case 0x9: {
if (msg.getValue() > 0) { if (msg.getValue() > 0) {
noteData[msg.getNote()].velocity = msg.getValue();
velocities[msg.getNote()] = msg.getValue();
pressNote(msg.getNote()); pressNote(msg.getNote());
} }
else { else {
@@ -118,8 +138,7 @@ struct MIDI_CV : Module {
} break; } break;
// channel aftertouch // channel aftertouch
case 0xa: { case 0xa: {
uint8_t note = msg.getNote();
noteData[note].aftertouch = msg.getValue();
aftertouches[msg.getNote()] = msg.getValue();
} break; } break;
// cc // cc
case 0xb: { case 0xb: {
@@ -127,7 +146,7 @@ struct MIDI_CV : Module {
} break; } break;
// pitch wheel // pitch wheel
case 0xe: { case 0xe: {
pitch = msg.getValue() * 128 + msg.getNote();
pitch = ((uint16_t) msg.getValue() << 7) | msg.getNote();
} break; } break;
case 0xf: { case 0xf: {
processSystem(msg); processSystem(msg);
@@ -157,16 +176,11 @@ struct MIDI_CV : Module {
switch (msg.getChannel()) { switch (msg.getChannel()) {
// Timing // Timing
case 0x8: { case 0x8: {
if (clock % divisions[0] == 0) {
clockPulses[0].trigger(1e-3);
}
if (clock % divisions[1] == 0) {
clockPulses[1].trigger(1e-3);
}
if (++clock >= (24*16*16)) {
// Avoid overflowing the integer
clock = 0;
clockPulse.trigger(1e-3);
if (clock % clockDivision == 0) {
clockDividerPulse.trigger(1e-3);
} }
clock++;
} break; } break;
// Start // Start
case 0xa: { case 0xa: {
@@ -180,7 +194,6 @@ struct MIDI_CV : Module {
// Stop // Stop
case 0xc: { case 0xc: {
stopPulse.trigger(1e-3); stopPulse.trigger(1e-3);
// Reset timing
clock = 0; clock = 0;
} break; } break;
default: break; default: break;
@@ -188,33 +201,37 @@ struct MIDI_CV : Module {
} }


void pressNote(uint8_t note) { void pressNote(uint8_t note) {
// Remove existing similar note
auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
if (it != heldNotes.end())
heldNotes.erase(it);
// Push note
heldNotes.push_back(note);
lastNote = note;
gate = true;
retriggerPulse.trigger(1e-3);
int c = 0;
notes[c] = note;
gates[note] = true;
// // Remove existing similar note
// auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
// if (it != heldNotes.end())
// heldNotes.erase(it);
// // Push note
// heldNotes.push_back(note);
// lastNote = note;
// gate = true;
retriggerPulses[c].trigger(1e-3);
} }


void releaseNote(uint8_t note) { void releaseNote(uint8_t note) {
// Remove the note
auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
if (it != heldNotes.end())
heldNotes.erase(it);
// Hold note if pedal is pressed
if (pedal)
return;
// Set last note
if (!heldNotes.empty()) {
lastNote = heldNotes[heldNotes.size() - 1];
gate = true;
}
else {
gate = false;
}
gates[note] = false;
// // Remove the note
// auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
// if (it != heldNotes.end())
// heldNotes.erase(it);
// // Hold note if pedal is pressed
// if (pedal)
// return;
// // Set last note
// if (!heldNotes.empty()) {
// lastNote = heldNotes[heldNotes.size() - 1];
// gate = true;
// }
// else {
// gate = false;
// }
} }


void pressPedal() { void pressPedal() {
@@ -223,32 +240,30 @@ struct MIDI_CV : Module {


void releasePedal() { void releasePedal() {
pedal = false; pedal = false;
releaseNote(255);
// releaseNote(255);
} }


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

json_t *divisionsJ = json_array();
for (int i = 0; i < 2; i++) {
json_t *divisionJ = json_integer(divisions[i]);
json_array_append_new(divisionsJ, divisionJ);
}
json_object_set_new(rootJ, "divisions", divisionsJ);

json_object_set_new(rootJ, "channels", json_integer(channels));
json_object_set_new(rootJ, "polyMode", json_integer(polyMode));
json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision));
json_object_set_new(rootJ, "midi", midiInput.toJson()); json_object_set_new(rootJ, "midi", midiInput.toJson());
return rootJ; return rootJ;
} }


void dataFromJson(json_t *rootJ) override { void dataFromJson(json_t *rootJ) override {
json_t *divisionsJ = json_object_get(rootJ, "divisions");
if (divisionsJ) {
for (int i = 0; i < 2; i++) {
json_t *divisionJ = json_array_get(divisionsJ, i);
if (divisionJ)
divisions[i] = json_integer_value(divisionJ);
}
}
json_t *channelsJ = json_object_get(rootJ, "channels");
if (channelsJ)
channels = json_integer_value(channelsJ);

json_t *polyModeJ = json_object_get(rootJ, "polyMode");
if (polyModeJ)
polyMode = (PolyMode) json_integer_value(polyModeJ);

json_t *clockDivisionJ = json_object_get(rootJ, "clockDivision");
if (clockDivisionJ)
clockDivision = json_integer_value(clockDivisionJ);


json_t *midiJ = json_object_get(rootJ, "midi"); json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ) if (midiJ)
@@ -257,6 +272,96 @@ struct MIDI_CV : Module {
}; };




struct ClockDivisionValueItem : MenuItem {
MIDI_CV *module;
int clockDivision;
void onAction(const event::Action &e) override {
module->clockDivision = clockDivision;
}
};


struct ClockDivisionItem : MenuItem {
MIDI_CV *module;
Menu *createChildMenu() override {
Menu *menu = new Menu;
std::vector<int> divisions = {24*4, 24*2, 24, 24/2, 24/4, 24/8, 2, 1};
std::vector<std::string> divisionNames = {"Whole", "Half", "Quarter", "8th", "16th", "32nd", "12 PPQN", "24 PPQN"};
for (size_t i = 0; i < divisions.size(); i++) {
ClockDivisionValueItem *item = new ClockDivisionValueItem;
item->text = divisionNames[i];
item->rightText = CHECKMARK(module->clockDivision == divisions[i]);
item->module = module;
item->clockDivision = divisions[i];
menu->addChild(item);
}
return menu;
}
};


struct ChannelValueItem : MenuItem {
MIDI_CV *module;
int channels;
void onAction(const event::Action &e) override {
module->channels = channels;
}
};


struct ChannelItem : MenuItem {
MIDI_CV *module;
Menu *createChildMenu() override {
Menu *menu = new Menu;
for (int channels = 1; channels <= 16; channels++) {
ChannelValueItem *item = new ChannelValueItem;
if (channels == 1)
item->text = "Monophonic";
else
item->text = string::f("%d", channels);
item->rightText = CHECKMARK(module->channels == channels);
item->module = module;
item->channels = channels;
menu->addChild(item);
}
return menu;
}
};


struct PolyModeValueItem : MenuItem {
MIDI_CV *module;
MIDI_CV::PolyMode polyMode;
void onAction(const event::Action &e) override {
module->polyMode = polyMode;
}
};


struct PolyModeItem : MenuItem {
MIDI_CV *module;
Menu *createChildMenu() override {
Menu *menu = new Menu;
std::vector<std::string> polyModeNames = {
"Rotate",
"Reuse",
"Reset",
"Reassign",
};
for (int i = 0; i < MIDI_CV::NUM_POLY_MODES; i++) {
MIDI_CV::PolyMode polyMode = (MIDI_CV::PolyMode) i;
PolyModeValueItem *item = new PolyModeValueItem;
item->text = polyModeNames[i];
item->rightText = CHECKMARK(module->polyMode == polyMode);
item->module = module;
item->polyMode = polyMode;
menu->addChild(item);
}
return menu;
}
};


struct MIDI_CVWidget : ModuleWidget { struct MIDI_CVWidget : ModuleWidget {
MIDI_CVWidget(MIDI_CV *module) { MIDI_CVWidget(MIDI_CV *module) {
setModule(module); setModule(module);
@@ -273,9 +378,9 @@ struct MIDI_CVWidget : ModuleWidget {
addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 76.1449)), module, MIDI_CV::AFTERTOUCH_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 76.1449)), module, MIDI_CV::AFTERTOUCH_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 76.1449)), module, MIDI_CV::PITCH_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 76.1449)), module, MIDI_CV::PITCH_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 76.1449)), module, MIDI_CV::MOD_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 76.1449)), module, MIDI_CV::MOD_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 92.1439)), module, MIDI_CV::RETRIGGER_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 92.1439)), module, MIDI_CV::CLOCK_1_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 92.1439)), module, MIDI_CV::CLOCK_2_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 92.1439)), module, MIDI_CV::CLOCK_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 92.1439)), module, MIDI_CV::CLOCK_DIV_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 92.1439)), module, MIDI_CV::RETRIGGER_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 108.144)), module, MIDI_CV::START_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 108.144)), module, MIDI_CV::START_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 108.144)), module, MIDI_CV::STOP_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 108.144)), module, MIDI_CV::STOP_OUTPUT));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 108.144)), module, MIDI_CV::CONTINUE_OUTPUT)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 108.144)), module, MIDI_CV::CONTINUE_OUTPUT));
@@ -290,40 +395,20 @@ struct MIDI_CVWidget : ModuleWidget {
void appendContextMenu(Menu *menu) override { void appendContextMenu(Menu *menu) override {
MIDI_CV *module = dynamic_cast<MIDI_CV*>(this->module); MIDI_CV *module = dynamic_cast<MIDI_CV*>(this->module);


struct ClockDivisionItem : MenuItem {
MIDI_CV *module;
int index;
int division;
void onAction(const event::Action &e) override {
module->divisions[index] = division;
}
};
menu->addChild(new MenuEntry);


struct ClockItem : MenuItem {
MIDI_CV *module;
int index;
Menu *createChildMenu() override {
Menu *menu = new Menu;
std::vector<int> divisions = {24*4, 24*2, 24, 24/2, 24/4, 24/8, 2, 1};
std::vector<std::string> divisionNames = {"Whole", "Half", "Quarter", "8th", "16th", "32nd", "12 PPQN", "24 PPQN"};
for (size_t i = 0; i < divisions.size(); i++) {
ClockDivisionItem *item = createMenuItem<ClockDivisionItem>(divisionNames[i], CHECKMARK(module->divisions[index] == divisions[i]));
item->module = module;
item->index = index;
item->division = divisions[i];
menu->addChild(item);
}
return menu;
}
};
ClockDivisionItem *clockDivisionItem = new ClockDivisionItem;
clockDivisionItem->text = "CLK/N divider";
clockDivisionItem->module = module;
menu->addChild(clockDivisionItem);


menu->addChild(construct<MenuLabel>());
for (int i = 0; i < 2; i++) {
ClockItem *item = createMenuItem<ClockItem>(string::f("CLK %d rate", i + 1));
item->module = module;
item->index = i;
menu->addChild(item);
}
ChannelItem *channelItem = createMenuItem<ChannelItem>("Polyphony channels");
channelItem->module = module;
menu->addChild(channelItem);

PolyModeItem *polyModeItem = createMenuItem<PolyModeItem>("Polyphony mode");
polyModeItem->module = module;
menu->addChild(polyModeItem);
} }
}; };




+ 2
- 2
src/app/ModuleWidget.cpp View File

@@ -399,7 +399,7 @@ void ModuleWidget::fromJson(json_t *rootJ) {
if (versionJ) { if (versionJ) {
std::string version = json_string_value(versionJ); std::string version = json_string_value(versionJ);
if (version != model->plugin->version) { if (version != model->plugin->version) {
INFO("Patch created with %s version %s, using version %s.", pluginSlug.c_str(), version.c_str(), model->plugin->version.c_str());
INFO("Patch created with %s v%s, currently using v%s.", pluginSlug.c_str(), version.c_str(), model->plugin->version.c_str());
} }
} }


@@ -677,7 +677,7 @@ void ModuleWidget::createContextMenu() {
assert(model); assert(model);


ui::MenuLabel *menuLabel = new ui::MenuLabel; ui::MenuLabel *menuLabel = new ui::MenuLabel;
menuLabel->text = model->plugin->name + " " + model->name + " " + model->plugin->version;
menuLabel->text = model->plugin->name + " " + model->name + " v" + model->plugin->version;
menu->addChild(menuLabel); menu->addChild(menuLabel);


ModuleResetItem *resetItem = new ModuleResetItem; ModuleResetItem *resetItem = new ModuleResetItem;


+ 4
- 3
src/app/Scene.cpp View File

@@ -58,12 +58,13 @@ void Scene::step() {
// Autosave every 15 seconds // Autosave every 15 seconds
int frame = APP->window->frame; int frame = APP->window->frame;
if (frame > 0 && frame % (60 * 15) == 0) { if (frame > 0 && frame % (60 * 15) == 0) {
// DEBUG("frame %d", frame);
APP->patch->save(asset::user("autosave.vcv")); APP->patch->save(asset::user("autosave.vcv"));
settings.save(asset::user("settings.json")); settings.save(asset::user("settings.json"));
} }


// Set zoom every few frames // Set zoom every few frames
if (APP->window->frame % 10 == 0)
if (frame % 10 == 0)
zoomWidget->setZoom(std::round(settings.zoom * 100) / 100); zoomWidget->setZoom(std::round(settings.zoom * 100) / 100);


// Request latest version from server // Request latest version from server
@@ -75,7 +76,7 @@ void Scene::step() {


// Version popup message // Version popup message
if (!latestVersion.empty()) { if (!latestVersion.empty()) {
std::string versionMessage = string::f("Rack %s is available.\n\nYou have Rack %s.\n\nClose Rack and download new version on the website?", latestVersion.c_str(), app::VERSION);
std::string versionMessage = string::f("Rack v%s is available.\n\nYou have Rack v%s.\n\nClose Rack and download new version on the website?", latestVersion.c_str(), app::APP_VERSION);
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) { if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) {
std::thread t(system::openBrowser, "https://vcvrack.com/"); std::thread t(system::openBrowser, "https://vcvrack.com/");
t.detach(); t.detach();
@@ -172,7 +173,7 @@ void Scene::runCheckVersion() {
json_t *versionJ = json_object_get(versionResJ, "version"); json_t *versionJ = json_object_get(versionResJ, "version");
if (versionJ) { if (versionJ) {
std::string version = json_string_value(versionJ); std::string version = json_string_value(versionJ);
if (version != app::VERSION) {
if (version != app::APP_VERSION) {
latestVersion = version; latestVersion = version;
} }
} }


+ 1
- 1
src/main.cpp View File

@@ -65,7 +65,7 @@ int main(int argc, char *argv[]) {
logger::init(devMode); logger::init(devMode);


// Log environment // Log environment
INFO("%s %s", app::NAME, app::VERSION);
INFO("%s v%s", app::APP_NAME, app::APP_VERSION);
if (devMode) if (devMode)
INFO("Development mode"); INFO("Development mode");
INFO("System directory: %s", asset::systemDir.c_str()); INFO("System directory: %s", asset::systemDir.c_str());


+ 3
- 3
src/patch.cpp View File

@@ -223,7 +223,7 @@ json_t *PatchManager::toJson() {
json_t *rootJ = json_object(); json_t *rootJ = json_object();


// version // version
json_t *versionJ = json_string(app::VERSION);
json_t *versionJ = json_string(app::APP_VERSION);
json_object_set_new(rootJ, "version", versionJ); json_object_set_new(rootJ, "version", versionJ);


// Merge with RackWidget JSON // Merge with RackWidget JSON
@@ -243,8 +243,8 @@ void PatchManager::fromJson(json_t *rootJ) {
json_t *versionJ = json_object_get(rootJ, "version"); json_t *versionJ = json_object_get(rootJ, "version");
if (versionJ) if (versionJ)
version = json_string_value(versionJ); version = json_string_value(versionJ);
if (version != app::VERSION) {
INFO("Patch made with Rack version %s, current Rack version is %s", version.c_str(), app::VERSION);
if (version != app::APP_VERSION) {
INFO("Patch was made with Rack v%s, current Rack version is v%s", version.c_str(), app::APP_VERSION);
} }


// Detect old patches with ModuleWidget::params/inputs/outputs indices. // Detect old patches with ModuleWidget::params/inputs/outputs indices.


+ 1
- 1
src/plugin.cpp View File

@@ -132,7 +132,7 @@ static bool loadPlugin(std::string path) {


// Add plugin to list // Add plugin to list
plugins.push_back(plugin); plugins.push_back(plugin);
INFO("Loaded plugin %s %s from %s", plugin->slug.c_str(), plugin->version.c_str(), libraryFilename.c_str());
INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), libraryFilename.c_str());


return true; return true;
} }


+ 3
- 3
src/window.cpp View File

@@ -332,9 +332,9 @@ void Window::run() {


// Set window title // Set window title
std::string windowTitle; std::string windowTitle;
windowTitle = app::NAME;
windowTitle += " ";
windowTitle += app::VERSION;
windowTitle = app::APP_NAME;
windowTitle += " v";
windowTitle += app::APP_VERSION;
if (!APP->patch->path.empty()) { if (!APP->patch->path.empty()) {
windowTitle += " - "; windowTitle += " - ";
windowTitle += string::filename(APP->patch->path); windowTitle += string::filename(APP->patch->path);


Loading…
Cancel
Save