| @@ -8,8 +8,8 @@ namespace rack { | |||||
| struct Input : Port { | struct Input : Port { | ||||
| /** Returns the value if a wire is plugged in, otherwise returns the given default value */ | /** Returns the value if a wire is plugged in, otherwise returns the given default value */ | ||||
| float normalize(float normalValue, int index = 0) { | |||||
| return active ? getValue(index) : normalValue; | |||||
| float normalize(float normalVoltage, int index = 0) { | |||||
| return active ? getVoltage(index) : normalVoltage; | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -12,6 +12,9 @@ static const int PORT_MAX_CHANNELS = 16; | |||||
| struct Port { | struct Port { | ||||
| /** Voltage of the port */ | /** Voltage of the port */ | ||||
| union { | union { | ||||
| /** Accessing this directly is deprecated. | |||||
| Use getVoltage() and setVoltage() instead | |||||
| */ | |||||
| float value; | float value; | ||||
| float values[PORT_MAX_CHANNELS] = {}; | float values[PORT_MAX_CHANNELS] = {}; | ||||
| }; | }; | ||||
| @@ -21,12 +24,11 @@ struct Port { | |||||
| bool active = false; | bool active = false; | ||||
| Light plugLights[2]; | Light plugLights[2]; | ||||
| float getValue(int index = 0) { | |||||
| float getVoltage(int index = 0) { | |||||
| return values[index]; | return values[index]; | ||||
| } | } | ||||
| void setValue(float value, int index = 0) { | |||||
| this->values[index] = value; | |||||
| void setVoltage(float voltage, int index = 0) { | |||||
| values[index] = voltage; | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -71,7 +71,7 @@ struct AudioInterfaceIO : audio::IO { | |||||
| else { | else { | ||||
| // Timed out, fill output with zeros | // Timed out, fill output with zeros | ||||
| memset(output, 0, frames * numOutputs * sizeof(float)); | memset(output, 0, frames * numOutputs * sizeof(float)); | ||||
| DEBUG("Audio Interface IO underflow"); | |||||
| // DEBUG("Audio Interface IO underflow"); | |||||
| } | } | ||||
| } | } | ||||
| @@ -172,7 +172,7 @@ void AudioInterface::step() { | |||||
| else { | else { | ||||
| // Give up on pulling input | // Give up on pulling input | ||||
| audioIO.active = false; | audioIO.active = false; | ||||
| DEBUG("Audio Interface underflow"); | |||||
| // DEBUG("Audio Interface underflow"); | |||||
| } | } | ||||
| } | } | ||||
| @@ -185,10 +185,10 @@ void AudioInterface::step() { | |||||
| memset(&inputFrame, 0, sizeof(inputFrame)); | memset(&inputFrame, 0, sizeof(inputFrame)); | ||||
| } | } | ||||
| for (int i = 0; i < audioIO.numInputs; i++) { | for (int i = 0; i < audioIO.numInputs; i++) { | ||||
| outputs[AUDIO_OUTPUT + i].value = 10.f * inputFrame.samples[i]; | |||||
| outputs[AUDIO_OUTPUT + i].setVoltage(10.f * inputFrame.samples[i]); | |||||
| } | } | ||||
| for (int i = audioIO.numInputs; i < AUDIO_INPUTS; i++) { | for (int i = audioIO.numInputs; i < AUDIO_INPUTS; i++) { | ||||
| outputs[AUDIO_OUTPUT + i].value = 0.f; | |||||
| outputs[AUDIO_OUTPUT + i].setVoltage(0.f); | |||||
| } | } | ||||
| // Outputs: rack engine -> audio engine | // Outputs: rack engine -> audio engine | ||||
| @@ -197,7 +197,7 @@ void AudioInterface::step() { | |||||
| if (!outputBuffer.full()) { | if (!outputBuffer.full()) { | ||||
| Frame<AUDIO_OUTPUTS> outputFrame; | Frame<AUDIO_OUTPUTS> outputFrame; | ||||
| for (int i = 0; i < AUDIO_OUTPUTS; i++) { | for (int i = 0; i < AUDIO_OUTPUTS; i++) { | ||||
| outputFrame.samples[i] = inputs[AUDIO_INPUT + i].value / 10.f; | |||||
| outputFrame.samples[i] = inputs[AUDIO_INPUT + i].getVoltage() / 10.f; | |||||
| } | } | ||||
| outputBuffer.push(outputFrame); | outputBuffer.push(outputFrame); | ||||
| } | } | ||||
| @@ -222,7 +222,7 @@ void AudioInterface::step() { | |||||
| // Give up on pushing output | // Give up on pushing output | ||||
| audioIO.active = false; | audioIO.active = false; | ||||
| outputBuffer.clear(); | outputBuffer.clear(); | ||||
| DEBUG("Audio Interface underflow"); | |||||
| // DEBUG("Audio Interface underflow"); | |||||
| } | } | ||||
| } | } | ||||
| @@ -232,9 +232,9 @@ void AudioInterface::step() { | |||||
| // Turn on light if at least one port is enabled in the nearby pair | // Turn on light if at least one port is enabled in the nearby pair | ||||
| for (int i = 0; i < AUDIO_INPUTS / 2; i++) | for (int i = 0; i < AUDIO_INPUTS / 2; i++) | ||||
| lights[INPUT_LIGHT + i].value = (audioIO.active && audioIO.numOutputs >= 2*i+1); | |||||
| lights[INPUT_LIGHT + i].setBrightness(audioIO.active && audioIO.numOutputs >= 2*i+1); | |||||
| for (int i = 0; i < AUDIO_OUTPUTS / 2; i++) | for (int i = 0; i < AUDIO_OUTPUTS / 2; i++) | ||||
| lights[OUTPUT_LIGHT + i].value = (audioIO.active && audioIO.numInputs >= 2*i+1); | |||||
| lights[OUTPUT_LIGHT + i].setBrightness(audioIO.active && audioIO.numInputs >= 2*i+1); | |||||
| } | } | ||||
| @@ -51,7 +51,7 @@ struct MIDICCToCVInterface : Module { | |||||
| int learnedCc = learnedCcs[i]; | int learnedCc = learnedCcs[i]; | ||||
| float value = rescale(clamp(ccs[learnedCc], -127, 127), 0, 127, 0.f, 10.f); | float value = rescale(clamp(ccs[learnedCc], -127, 127), 0, 127, 0.f, 10.f); | ||||
| ccFilters[i].lambda = lambda; | ccFilters[i].lambda = lambda; | ||||
| outputs[CC_OUTPUT + i].value = ccFilters[i].process(value); | |||||
| outputs[CC_OUTPUT + i].setVoltage(ccFilters[i].process(value)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -148,23 +148,23 @@ struct MIDIToCVInterface : Module { | |||||
| } | } | ||||
| float deltaTime = context()->engine->getSampleTime(); | float deltaTime = context()->engine->getSampleTime(); | ||||
| outputs[CV_OUTPUT].value = (lastNote - 60) / 12.f; | |||||
| outputs[GATE_OUTPUT].value = gate ? 10.f : 0.f; | |||||
| outputs[VELOCITY_OUTPUT].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f); | |||||
| 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].value = rescale(noteData[lastNote].aftertouch, 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; | pitchFilter.lambda = 100.f * deltaTime; | ||||
| outputs[PITCH_OUTPUT].value = pitchFilter.process(rescale(pitch, 0, 16384, -5.f, 5.f)); | |||||
| outputs[PITCH_OUTPUT].setVoltage(pitchFilter.process(rescale(pitch, 0, 16384, -5.f, 5.f))); | |||||
| modFilter.lambda = 100.f * deltaTime; | modFilter.lambda = 100.f * deltaTime; | ||||
| outputs[MOD_OUTPUT].value = modFilter.process(rescale(mod, 0, 127, 0.f, 10.f)); | |||||
| outputs[MOD_OUTPUT].setVoltage(modFilter.process(rescale(mod, 0, 127, 0.f, 10.f))); | |||||
| outputs[RETRIGGER_OUTPUT].value = retriggerPulse.process(deltaTime) ? 10.f : 0.f; | |||||
| outputs[CLOCK_1_OUTPUT].value = clockPulses[0].process(deltaTime) ? 10.f : 0.f; | |||||
| outputs[CLOCK_2_OUTPUT].value = clockPulses[1].process(deltaTime) ? 10.f : 0.f; | |||||
| 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); | |||||
| outputs[START_OUTPUT].value = startPulse.process(deltaTime) ? 10.f : 0.f; | |||||
| outputs[STOP_OUTPUT].value = stopPulse.process(deltaTime) ? 10.f : 0.f; | |||||
| outputs[CONTINUE_OUTPUT].value = continuePulse.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[CONTINUE_OUTPUT].setVoltage(continuePulse.process(deltaTime) ? 10.f : 0.f); | |||||
| } | } | ||||
| void processMessage(midi::Message msg) { | void processMessage(midi::Message msg) { | ||||
| @@ -75,7 +75,7 @@ struct MIDITriggerToCVInterface : Module { | |||||
| for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
| if (gateTimes[i] > 0.f) { | if (gateTimes[i] > 0.f) { | ||||
| outputs[TRIG_OUTPUT + i].value = velocity ? rescale(velocities[i], 0, 127, 0.f, 10.f) : 10.f; | |||||
| outputs[TRIG_OUTPUT + i].setVoltage(velocity ? rescale(velocities[i], 0, 127, 0.f, 10.f) : 10.f); | |||||
| // If the gate is off, wait 1 ms before turning the pulse off. | // If the gate is off, wait 1 ms before turning the pulse off. | ||||
| // This avoids drum controllers sending a pulse with 0 ms duration. | // This avoids drum controllers sending a pulse with 0 ms duration. | ||||
| if (!gates[i]) { | if (!gates[i]) { | ||||
| @@ -83,7 +83,7 @@ struct MIDITriggerToCVInterface : Module { | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| outputs[TRIG_OUTPUT + i].value = 0.f; | |||||
| outputs[TRIG_OUTPUT + i].setVoltage(0.f); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -251,10 +251,10 @@ struct QuadMIDIToCVInterface : Module { | |||||
| for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
| uint8_t lastNote = notes[i]; | uint8_t lastNote = notes[i]; | ||||
| uint8_t lastGate = (gates[i] || pedalgates[i]); | uint8_t lastGate = (gates[i] || pedalgates[i]); | ||||
| outputs[CV_OUTPUT + i].value = (lastNote - 60) / 12.f; | |||||
| outputs[GATE_OUTPUT + i].value = lastGate ? 10.f : 0.f; | |||||
| outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f); | |||||
| outputs[AFTERTOUCH_OUTPUT + i].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f); | |||||
| outputs[CV_OUTPUT + i].setVoltage((lastNote - 60) / 12.f); | |||||
| outputs[GATE_OUTPUT + i].setVoltage(lastGate ? 10.f : 0.f); | |||||
| outputs[VELOCITY_OUTPUT + i].setVoltage(rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f)); | |||||
| outputs[AFTERTOUCH_OUTPUT + i].setVoltage(rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -132,7 +132,7 @@ static void Engine_step(Engine *engine) { | |||||
| // Bypass module | // Bypass module | ||||
| for (Output &output : module->outputs) { | for (Output &output : module->outputs) { | ||||
| output.numChannels = 1; | output.numChannels = 1; | ||||
| output.setValue(0.f); | |||||
| output.setVoltage(0.f); | |||||
| } | } | ||||
| module->cpuTime = 0.f; | module->cpuTime = 0.f; | ||||
| } | } | ||||
| @@ -62,13 +62,6 @@ int main(int argc, char *argv[]) { | |||||
| random::init(); | random::init(); | ||||
| asset::init(devMode); | asset::init(devMode); | ||||
| logger::init(devMode); | logger::init(devMode); | ||||
| midi::init(); | |||||
| rtmidiInit(); | |||||
| bridgeInit(); | |||||
| keyboard::init(); | |||||
| gamepad::init(); | |||||
| ui::init(); | |||||
| plugin::init(devMode); | |||||
| // Log environment | // Log environment | ||||
| INFO("%s %s", APP_NAME.c_str(), APP_VERSION.c_str()); | INFO("%s %s", APP_NAME.c_str(), APP_VERSION.c_str()); | ||||
| @@ -77,6 +70,14 @@ int main(int argc, char *argv[]) { | |||||
| INFO("System directory: %s", asset::systemDir.c_str()); | INFO("System directory: %s", asset::systemDir.c_str()); | ||||
| INFO("User directory: %s", asset::userDir.c_str()); | INFO("User directory: %s", asset::userDir.c_str()); | ||||
| midi::init(); | |||||
| rtmidiInit(); | |||||
| bridgeInit(); | |||||
| keyboard::init(); | |||||
| gamepad::init(); | |||||
| ui::init(); | |||||
| plugin::init(devMode); | |||||
| // Initialize app | // Initialize app | ||||
| context()->engine = new Engine; | context()->engine = new Engine; | ||||
| context()->event = new event::State; | context()->event = new event::State; | ||||
| @@ -9,7 +9,9 @@ void Model::fromJson(json_t *rootJ) { | |||||
| if (nameJ) | if (nameJ) | ||||
| name = json_string_value(nameJ); | name = json_string_value(nameJ); | ||||
| DEBUG("name: %s", name.c_str()); | |||||
| json_t *descriptionJ = json_object_get(rootJ, "description"); | |||||
| if (descriptionJ) | |||||
| description = json_string_value(descriptionJ); | |||||
| json_t *tagsJ = json_object_get(rootJ, "tags"); | json_t *tagsJ = json_object_get(rootJ, "tags"); | ||||
| if (tagsJ) { | if (tagsJ) { | ||||
| @@ -17,7 +19,7 @@ void Model::fromJson(json_t *rootJ) { | |||||
| json_t *tagJ; | json_t *tagJ; | ||||
| json_array_foreach(tagsJ, i, tagJ) { | json_array_foreach(tagsJ, i, tagJ) { | ||||
| std::string tag = json_string_value(tagJ); | std::string tag = json_string_value(tagJ); | ||||
| DEBUG("tag: %s", tag.c_str()); | |||||
| tags.push_back(tag); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||