diff --git a/include/audio.hpp b/include/audio.hpp index fff6ce3c..b967410f 100644 --- a/include/audio.hpp +++ b/include/audio.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #include @@ -13,20 +15,20 @@ struct AudioIO { int maxOutputs = 8; int maxInputs = 8; - RtAudio *stream = NULL; // Stream properties + int driver = 0; int device = -1; int sampleRate = 44100; int blockSize = 256; int numOutputs = 0; int numInputs = 0; + RtAudio *rtAudio = NULL; AudioIO(); virtual ~AudioIO(); std::vector listDrivers(); std::string getDriverName(int driver); - int getDriver(); void setDriver(int driver); int getDeviceCount(); @@ -40,6 +42,8 @@ struct AudioIO { virtual void processStream(const float *input, float *output, int length) {} virtual void onCloseStream() {} virtual void onOpenStream() {} + json_t *toJson(); + void fromJson(json_t *rootJ); }; diff --git a/include/midi.hpp b/include/midi.hpp index a55d4ac5..342a5b55 100644 --- a/include/midi.hpp +++ b/include/midi.hpp @@ -1,5 +1,11 @@ #pragma once +#include "util.hpp" +#include +#include +#include + + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #include "rtmidi/RtMidi.h" @@ -9,8 +15,13 @@ namespace rack { +struct MidiMessage { + double time; + std::vector data; +}; + + struct MidiIO { - RtMidi *midi; int port = -1; /* For MIDI output, the channel to output messages. For MIDI input, the channel to filter. @@ -18,17 +29,27 @@ struct MidiIO { Zero indexed. */ int channel = -1; + RtMidi *rtMidi = NULL; virtual ~MidiIO() {} - virtual int getPortCount(); - virtual std::string getPortName(int port); - virtual void openPort(int port); + int getPortCount(); + std::string getPortName(int port); + void openPort(int port); + json_t *toJson(); + void fromJson(json_t *rootJ); }; struct MidiInput : MidiIO { MidiInput(); ~MidiInput(); + virtual void onMessage(const MidiMessage &message) {} +}; + + +struct MidiInputQueue : MidiInput { + std::queue messageQueue; + void onMessage(const MidiMessage &message) override; }; diff --git a/src/app/AudioWidget.cpp b/src/app/AudioWidget.cpp index 67ca64d9..bd73f662 100644 --- a/src/app/AudioWidget.cpp +++ b/src/app/AudioWidget.cpp @@ -59,7 +59,7 @@ void AudioWidget::onMouseDown(EventMouseDown &e) { item->audioIO = audioIO; item->driver = driver; item->text = audioIO->getDriverName(driver); - item->rightText = CHECKMARK(item->driver == audioIO->getDriver()); + item->rightText = CHECKMARK(item->driver == audioIO->driver); menu->addChild(item); } menu->addChild(construct()); diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index cd1b7f0b..ef37b5b5 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -110,7 +110,7 @@ void RackWidget::savePatch(std::string path) { FILE *file = fopen(path.c_str(), "w"); if (file) { - json_dumpf(rootJ, file, JSON_INDENT(2)); + json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); fclose(file); } diff --git a/src/audio.cpp b/src/audio.cpp index cc80df47..812951eb 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -3,6 +3,9 @@ #include "audio.hpp" +#define DRIVER_BRIDGE -1 + + namespace rack { @@ -20,6 +23,8 @@ std::vector AudioIO::listDrivers() { std::vector drivers; for (RtAudio::Api api : apis) drivers.push_back((int) api); + // Add Bridge fake driver + // drivers.push_back(DRIVER_BRIDGE); return drivers; } @@ -35,55 +40,71 @@ std::string AudioIO::getDriverName(int driver) { case RtAudio::WINDOWS_ASIO: return "ASIO"; case RtAudio::WINDOWS_DS: return "DirectSound"; case RtAudio::RTAUDIO_DUMMY: return "Dummy"; + case DRIVER_BRIDGE: return "VCV Bridge"; default: return "Unknown"; } } -int AudioIO::getDriver() { - if (!stream) - return RtAudio::UNSPECIFIED; - return stream->getCurrentApi(); -} - void AudioIO::setDriver(int driver) { + // Close driver closeStream(); - if (stream) - delete stream; - stream = new RtAudio((RtAudio::Api) driver); + if (rtAudio) { + delete rtAudio; + rtAudio = NULL; + } + this->driver = 0; + + // Open driver + if (driver >= 0) { + rtAudio = new RtAudio((RtAudio::Api) driver); + this->driver = (int) rtAudio->getCurrentApi(); + } + else if (driver == DRIVER_BRIDGE) { + // TODO Connect to Bridge + this->driver = DRIVER_BRIDGE; + } } int AudioIO::getDeviceCount() { - if (!stream) - return 0; - return stream->getDeviceCount(); + if (rtAudio) { + return rtAudio->getDeviceCount(); + } + if (driver == DRIVER_BRIDGE) { + return 16; + } + return 0; } std::string AudioIO::getDeviceName(int device) { - if (!stream || device < 0) - return ""; - - try { - RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); - return deviceInfo.name; + if (rtAudio) { + try { + RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); + return deviceInfo.name; + } + catch (RtAudioError &e) { + warn("Failed to query RtAudio device: %s", e.what()); + } } - catch (RtAudioError &e) { - warn("Failed to query audio device: %s", e.what()); - return ""; + if (driver == DRIVER_BRIDGE) { + return stringf("%d", device + 1); } + return ""; } std::string AudioIO::getDeviceDetail(int device) { - if (!stream || device < 0) - return ""; - - try { - RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); - return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels); + if (rtAudio) { + try { + RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); + return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels); + } + catch (RtAudioError &e) { + warn("Failed to query RtAudio device: %s", e.what()); + } } - catch (RtAudioError &e) { - warn("Failed to query audio device: %s", e.what()); - return ""; + if (driver == DRIVER_BRIDGE) { + return stringf("Channel %d", device + 1); } + return ""; } static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { @@ -97,17 +118,18 @@ void AudioIO::openStream() { // Close device but remember the current device number int device = this->device; closeStream(); - if (!stream) + + if (device < 0) return; - // Open new device - if (device >= 0) { + if (rtAudio) { + // Open new device RtAudio::DeviceInfo deviceInfo; try { - deviceInfo = stream->getDeviceInfo(device); + deviceInfo = rtAudio->getDeviceInfo(device); } catch (RtAudioError &e) { - warn("Failed to query audio device: %s", e.what()); + warn("Failed to query RtAudio device: %s", e.what()); return; } @@ -115,7 +137,7 @@ void AudioIO::openStream() { numInputs = mini(deviceInfo.inputChannels, maxInputs); if (numOutputs == 0 && numInputs == 0) { - warn("Audio device %d has 0 inputs and 0 outputs"); + warn("RtAudio device %d has 0 inputs and 0 outputs"); return; } @@ -138,56 +160,56 @@ void AudioIO::openStream() { } try { - debug("Opening audio stream %d", device); - stream->openStream( + debug("Opening audio RtAudio device %d", device); + rtAudio->openStream( numOutputs == 0 ? NULL : &outParameters, numInputs == 0 ? NULL : &inParameters, RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL); } catch (RtAudioError &e) { - warn("Failed to open audio stream: %s", e.what()); + warn("Failed to open RtAudio stream: %s", e.what()); return; } try { - debug("Starting audio stream %d", device); - stream->startStream(); + debug("Starting RtAudio stream %d", device); + rtAudio->startStream(); } catch (RtAudioError &e) { - warn("Failed to start audio stream: %s", e.what()); + warn("Failed to start RtAudio stream: %s", e.what()); return; } // Update sample rate because this may have changed - this->sampleRate = stream->getStreamSampleRate(); + this->sampleRate = rtAudio->getStreamSampleRate(); this->device = device; onOpenStream(); } } void AudioIO::closeStream() { - if (stream) { - if (stream->isStreamRunning()) { - debug("Stopping audio stream %d", device); + if (rtAudio) { + if (rtAudio->isStreamRunning()) { + debug("Stopping RtAudio stream %d", device); try { - stream->stopStream(); + rtAudio->stopStream(); } catch (RtAudioError &e) { - warn("Failed to stop stream %s", e.what()); + warn("Failed to stop RtAudio stream %s", e.what()); } } - if (stream->isStreamOpen()) { - debug("Closing audio stream %d", device); + if (rtAudio->isStreamOpen()) { + debug("Closing RtAudio stream %d", device); try { - stream->closeStream(); + rtAudio->closeStream(); } catch (RtAudioError &e) { - warn("Failed to close stream %s", e.what()); + warn("Failed to close RtAudio stream %s", e.what()); } } } - // Reset stream settings + // Reset rtAudio settings device = -1; numOutputs = 0; numInputs = 0; @@ -195,18 +217,59 @@ void AudioIO::closeStream() { } std::vector AudioIO::listSampleRates() { - if (!stream || device < 0) - return {}; - - try { - RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); - std::vector sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end()); - return sampleRates; + if (rtAudio) { + try { + RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); + std::vector sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end()); + return sampleRates; + } + catch (RtAudioError &e) { + warn("Failed to query RtAudio device: %s", e.what()); + } } - catch (RtAudioError &e) { - warn("Failed to query audio device: %s", e.what()); - return {}; + if (driver == DRIVER_BRIDGE) { + return {44100, 48000, 88200, 96000, 176400, 192000}; } + + return {}; +} + +json_t *AudioIO::toJson() { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "driver", json_integer(driver)); + std::string deviceName = getDeviceName(device); + json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str())); + json_object_set_new(rootJ, "sampleRate", json_integer(sampleRate)); + json_object_set_new(rootJ, "blockSize", json_integer(blockSize)); + return rootJ; +} + +void AudioIO::fromJson(json_t *rootJ) { + json_t *driverJ = json_object_get(rootJ, "driver"); + if (driverJ) + setDriver(json_number_value(driverJ)); + + json_t *deviceNameJ = json_object_get(rootJ, "deviceName"); + if (deviceNameJ) { + std::string deviceName = json_string_value(deviceNameJ); + // Search for device ID with equal name + for (int device = 0; device < getDeviceCount(); device++) { + if (getDeviceName(device) == deviceName) { + this->device = device; + break; + } + } + } + + json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); + if (sampleRateJ) + sampleRate = json_integer_value(sampleRateJ); + + json_t *blockSizeJ = json_object_get(rootJ, "blockSize"); + if (blockSizeJ) + blockSize = json_integer_value(blockSizeJ); + + openStream(); } diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 68b0ed33..e4edc563 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -114,40 +114,13 @@ struct AudioInterface : Module { json_t *toJson() override { json_t *rootJ = json_object(); - json_object_set_new(rootJ, "driver", json_integer(audioIO.getDriver())); - std::string deviceName = audioIO.getDeviceName(audioIO.device); - json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str())); - json_object_set_new(rootJ, "sampleRate", json_integer(audioIO.sampleRate)); - json_object_set_new(rootJ, "blockSize", json_integer(audioIO.blockSize)); + json_object_set_new(rootJ, "audio", audioIO.toJson()); return rootJ; } void fromJson(json_t *rootJ) override { - json_t *driverJ = json_object_get(rootJ, "driver"); - if (driverJ) - audioIO.setDriver(json_number_value(driverJ)); - - json_t *deviceNameJ = json_object_get(rootJ, "deviceName"); - if (deviceNameJ) { - std::string deviceName = json_string_value(deviceNameJ); - // Search for device ID with equal name - for (int device = 0; device < audioIO.getDeviceCount(); device++) { - if (audioIO.getDeviceName(device) == deviceName) { - audioIO.device = device; - break; - } - } - } - - json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); - if (sampleRateJ) - audioIO.sampleRate = json_integer_value(sampleRateJ); - - json_t *blockSizeJ = json_object_get(rootJ, "blockSize"); - if (blockSizeJ) - audioIO.blockSize = json_integer_value(blockSizeJ); - - audioIO.openStream(); + json_t *audioJ = json_object_get(rootJ, "audio"); + audioIO.fromJson(audioJ); } void onReset() override { @@ -236,7 +209,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() { { Label *label = new Label(); label->box.pos = Vec(margin.x, yPos); - label->text = "Outputs"; + label->text = "Outputs (DACs)"; addChild(label); yPos += labelHeight + margin.y; } @@ -270,7 +243,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() { { Label *label = new Label(); label->box.pos = Vec(margin.x, yPos); - label->text = "Inputs"; + label->text = "Inputs (ADCs)"; addChild(label); yPos += labelHeight + margin.y; } diff --git a/src/core/Bridge.cpp b/src/core/Bridge.cpp deleted file mode 100644 index bb7ade53..00000000 --- a/src/core/Bridge.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "core.hpp" - -using namespace rack; - - -struct Bridge : Module { - enum ParamIds { - NUM_PARAMS - }; - enum InputIds { - NUM_INPUTS - }; - enum OutputIds { - NUM_OUTPUTS - }; - - Bridge() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { - } - ~Bridge() { - } - void step() override; -}; - - -void Bridge::step() { -} - - -BridgeWidget::BridgeWidget() { - Bridge *module = new Bridge(); - setModule(module); - box.size = Vec(15*8, 380); - - { - Panel *panel = new LightPanel(); - panel->box.size = box.size; - addChild(panel); - } - - addChild(createScrew(Vec(15, 0))); - addChild(createScrew(Vec(box.size.x-30, 0))); - addChild(createScrew(Vec(15, 365))); - addChild(createScrew(Vec(box.size.x-30, 365))); -} diff --git a/src/core/MidiToCV.cpp b/src/core/MidiToCV.cpp index 89fd38a9..ba3620c1 100644 --- a/src/core/MidiToCV.cpp +++ b/src/core/MidiToCV.cpp @@ -1,4 +1,3 @@ -#if 0 #include #include #include "core.hpp" @@ -12,7 +11,7 @@ */ struct MidiValue { int val = 0; // Controller value - TransitionSmoother tSmooth; + // TransitionSmoother tSmooth; bool changed = false; // Value has been changed by midi message (only if it is in sync!) }; @@ -38,6 +37,7 @@ struct MIDIToCVInterface : Module { NUM_LIGHTS }; + MidiInputQueue midiInput; std::list notes; bool pedal = false; int note = 60; // C4, most modules should use 261.626 Hz @@ -51,7 +51,7 @@ struct MIDIToCVInterface : Module { MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { pitchWheel.val = 64; - pitchWheel.tSmooth.set(0, 0); + // pitchWheel.tSmooth.set(0, 0); } ~MIDIToCVInterface() { @@ -67,22 +67,22 @@ struct MIDIToCVInterface : Module { json_t *toJson() override { json_t *rootJ = json_object(); - addBaseJson(rootJ); + // addBaseJson(rootJ); return rootJ; } void fromJson(json_t *rootJ) override { - baseFromJson(rootJ); + // baseFromJson(rootJ); } void onReset() override { - resetMidi(); + // resetMidi(); } - void resetMidi() override; - + // void resetMidi() override; }; +/* void MIDIToCVInterface::resetMidi() { mod.val = 0; mod.tSmooth.set(0, 0); @@ -94,8 +94,10 @@ void MIDIToCVInterface::resetMidi() { gate = false; notes.clear(); } +*/ void MIDIToCVInterface::step() { + /* if (isPortOpen()) { std::vector message; @@ -132,11 +134,8 @@ void MIDIToCVInterface::step() { } outputs[PITCHWHEEL_OUTPUT].value = pitchWheel.tSmooth.next(); - - /* NOTE: I'll leave out value smoothing for after touch for now. I currently don't - * have an after touch capable device around and I assume it would require different - * smoothing*/ outputs[CHANNEL_AFTERTOUCH_OUTPUT].value = afterTouch.val / 127.0 * 10.0; + */ } void MIDIToCVInterface::pressNote(int note) { @@ -171,6 +170,7 @@ void MIDIToCVInterface::releaseNote(int note) { } void MIDIToCVInterface::processMidi(std::vector msg) { + /* int channel = msg[0] & 0xf; int status = (msg[0] >> 4) & 0xf; int data1 = msg[1]; @@ -220,6 +220,7 @@ void MIDIToCVInterface::processMidi(std::vector msg) { afterTouch.changed = true; break; } + */ } @@ -254,35 +255,6 @@ MidiToCVWidget::MidiToCVWidget() { addParam(createParam(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); addChild(createLight>(Vec(7 * 15 + 5, labelHeight + 5), module, MIDIToCVInterface::RESET_LIGHT)); - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "MIDI Interface"; - addChild(label); - yPos += labelHeight + margin; - - MidiChoice *midiChoice = new MidiChoice(); - midiChoice->midiModule = dynamic_cast(module); - midiChoice->box.pos = Vec(margin, yPos); - midiChoice->box.size.x = box.size.x - 10; - addChild(midiChoice); - yPos += midiChoice->box.size.y + margin; - } - - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "Channel"; - addChild(label); - yPos += labelHeight + margin; - - ChannelChoice *channelChoice = new ChannelChoice(); - channelChoice->midiModule = dynamic_cast(module); - channelChoice->box.pos = Vec(margin, yPos); - channelChoice->box.size.x = box.size.x - 10; - addChild(channelChoice); - yPos += channelChoice->box.size.y + margin + 15; - } std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", "Aftertouch"}; @@ -296,5 +268,8 @@ MidiToCVWidget::MidiToCVWidget() { yPos += yGap + margin; } + + MidiWidget *midiWidget = construct(); + midiWidget->midiIO = &module->midiInput; + addChild(midiWidget); } -#endif \ No newline at end of file diff --git a/src/core/core.cpp b/src/core/core.cpp index a444e273..ad4de7b7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -9,13 +9,12 @@ void init(rack::Plugin *p) { p->addModel(createModel("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); - // p->addModel(createModel("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); + p->addModel(createModel("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); // p->addModel(createModel("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); // p->addModel(createModel("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); // p->addModel(createModel("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); // p->addModel(createModel("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); - // p->addModel(createModel("Core", "Bridge", "Bridge")); p->addModel(createModel("Core", "Blank", "Blank", BLANK_TAG)); p->addModel(createModel("Core", "Notes", "Notes", BLANK_TAG)); } diff --git a/src/main.cpp b/src/main.cpp index 6252506c..8f707823 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "settings.hpp" #include "asset.hpp" #include +#include "../ext/osdialog/osdialog.h" using namespace rack; @@ -40,8 +41,12 @@ int main(int argc, char* argv[]) { skipAutosaveOnLaunch = true; settingsSave(assetLocal("settings.json")); skipAutosaveOnLaunch = false; - if (!oldSkipAutosaveOnLaunch) + if (oldSkipAutosaveOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, likely caused by a faulty module in your patch. Would you like to clear your patch and start over?")) { + // Do nothing. Empty patch is already loaded. + } + else { gRackWidget->loadPatch(assetLocal("autosave.vcv")); + } engineStart(); guiRun(); diff --git a/src/midi.cpp b/src/midi.cpp index e30b3163..bbb2a9a1 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -4,38 +4,101 @@ namespace rack { +//////////////////// +// MidiIO +//////////////////// + int MidiIO::getPortCount() { - return midi->getPortCount(); + return rtMidi->getPortCount(); } std::string MidiIO::getPortName(int port) { - return midi->getPortName(port); + if (port < 0) + return ""; + return rtMidi->getPortName(port); } void MidiIO::openPort(int port) { - midi->closePort(); + rtMidi->closePort(); if (port >= 0) { - midi->openPort(port); + rtMidi->openPort(port); } this->port = port; } +json_t *MidiIO::toJson() { + json_t *rootJ = json_object(); + std::string portName = getPortName(port); + json_object_set_new(rootJ, "port", json_string(portName.c_str())); + json_object_set_new(rootJ, "channel", json_integer(channel)); + return rootJ; +} + +void MidiIO::fromJson(json_t *rootJ) { + json_t *portNameJ = json_object_get(rootJ, "port"); + if (portNameJ) { + std::string portName = json_string_value(portNameJ); + // Search for port with equal name + for (int port = 0; port < getPortCount(); port++) { + if (getPortName(port) == portName) { + openPort(port); + break; + } + } + } + + json_t *channelJ = json_object_get(rootJ, "channel"); + if (channelJ) + channel = json_integer_value(channelJ); +} + +//////////////////// +// MidiInput +//////////////////// + +static void midiInputCallback(double timeStamp, std::vector *message, void *userData) { + if (!message) return; + if (!userData) return; + + MidiInput *midiInput = (MidiInput*) userData; + if (!midiInput) return; + MidiMessage midiMessage; + midiMessage.time = timeStamp; + midiMessage.data = *message; + midiInput->onMessage(midiMessage); +} + MidiInput::MidiInput() { - midi = new RtMidiIn(); + RtMidiIn *rtMidiIn = new RtMidiIn(); + rtMidi = rtMidiIn; + rtMidiIn->setCallback(midiInputCallback, this); } MidiInput::~MidiInput() { - delete dynamic_cast(midi); + delete dynamic_cast(rtMidi); +} + +void MidiInputQueue::onMessage(const MidiMessage &message) { + for (uint8_t d : message.data) { + debug("MIDI message: %02x", d); + } + + const int messageQueueSize = 8192; + if (messageQueue.size() < messageQueueSize) + messageQueue.push(message); } +//////////////////// +// MidiOutput +//////////////////// MidiOutput::MidiOutput() { - midi = new RtMidiOut(); + rtMidi = new RtMidiOut(); } MidiOutput::~MidiOutput() { - delete dynamic_cast(midi); + delete dynamic_cast(rtMidi); } diff --git a/src/settings.cpp b/src/settings.cpp index a6425fb1..e593c92b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -137,7 +137,7 @@ void settingsSave(std::string filename) { if (!file) return; - json_dumpf(rootJ, file, JSON_INDENT(2)); + json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); json_decref(rootJ); fclose(file); }