| @@ -7,7 +7,7 @@ namespace rack { | |||
| namespace audio { | |||
| struct IO; | |||
| struct Port; | |||
| } | |||
| @@ -22,7 +22,7 @@ struct AudioWidget : LedDisplay { | |||
| LedDisplayChoice *sampleRateChoice; | |||
| LedDisplaySeparator *sampleRateSeparator; | |||
| LedDisplayChoice *bufferSizeChoice; | |||
| void setAudioIO(audio::IO *audioIO); | |||
| void setAudioPort(audio::Port *port); | |||
| }; | |||
| @@ -7,7 +7,7 @@ namespace rack { | |||
| namespace midi { | |||
| struct IO; | |||
| struct Port; | |||
| } | |||
| @@ -20,7 +20,7 @@ struct MidiWidget : LedDisplay { | |||
| LedDisplayChoice *deviceChoice; | |||
| LedDisplaySeparator *deviceSeparator; | |||
| LedDisplayChoice *channelChoice; | |||
| void setMidiIO(midi::IO *midiIO); | |||
| void setMidiPort(midi::Port *port); | |||
| }; | |||
| @@ -14,7 +14,7 @@ namespace rack { | |||
| namespace audio { | |||
| struct IO { | |||
| struct Port { | |||
| // Stream properties | |||
| int driver = 0; | |||
| int device = -1; | |||
| @@ -28,8 +28,8 @@ struct IO { | |||
| /** Cached */ | |||
| RtAudio::DeviceInfo deviceInfo; | |||
| IO(); | |||
| virtual ~IO(); | |||
| Port(); | |||
| virtual ~Port(); | |||
| std::vector<int> getDrivers(); | |||
| std::string getDriverName(int driver); | |||
| @@ -8,8 +8,8 @@ namespace rack { | |||
| void bridgeInit(); | |||
| void bridgeDestroy(); | |||
| void bridgeAudioSubscribe(int channel, audio::IO *audio); | |||
| void bridgeAudioUnsubscribe(int channel, audio::IO *audio); | |||
| void bridgeAudioSubscribe(int channel, audio::Port *port); | |||
| void bridgeAudioUnsubscribe(int channel, audio::Port *port); | |||
| } // namespace rack | |||
| @@ -5,7 +5,7 @@ | |||
| namespace rack { | |||
| /** Driver ID in AudioIO and MidiIO */ | |||
| /** Driver ID for AudioDriver and MidiDriver */ | |||
| const int BRIDGE_DRIVER = -12512; | |||
| const char* const BRIDGE_HOST = "127.0.0.1"; | |||
| const int BRIDGE_PORT = 12512; | |||
| @@ -88,10 +88,10 @@ struct OutputDevice : Device { | |||
| }; | |||
| //////////////////// | |||
| // IO | |||
| // Port | |||
| //////////////////// | |||
| struct IO { | |||
| struct Port { | |||
| int driverId = -1; | |||
| int deviceId = -1; | |||
| /* For MIDI output, the channel to output messages. | |||
| @@ -104,7 +104,7 @@ struct IO { | |||
| Driver *driver = NULL; | |||
| /** Remember to call setDriverId(-1) in subclass destructors. */ | |||
| virtual ~IO() {} | |||
| virtual ~Port() {} | |||
| std::vector<int> getDriverIds(); | |||
| std::string getDriverName(int driverId); | |||
| @@ -123,7 +123,7 @@ struct IO { | |||
| }; | |||
| struct Input : IO { | |||
| struct Input : Port { | |||
| /** Not owned */ | |||
| InputDevice *inputDevice = NULL; | |||
| @@ -149,7 +149,7 @@ struct InputQueue : Input { | |||
| }; | |||
| struct Output : IO { | |||
| struct Output : Port { | |||
| /** Not owned */ | |||
| OutputDevice *outputDevice = NULL; | |||
| @@ -15,7 +15,7 @@ static const int AUDIO_INPUTS = 8; | |||
| using namespace rack; | |||
| struct AudioInterfaceIO : audio::IO { | |||
| struct AudioInterfacePort : audio::Port { | |||
| std::mutex engineMutex; | |||
| std::condition_variable engineCv; | |||
| std::mutex audioMutex; | |||
| @@ -26,8 +26,8 @@ struct AudioInterfaceIO : audio::IO { | |||
| dsp::DoubleRingBuffer<dsp::Frame<AUDIO_OUTPUTS>, (1<<15)> outputBuffer; | |||
| bool active = false; | |||
| ~AudioInterfaceIO() { | |||
| // Close stream here before destructing AudioInterfaceIO, so the mutexes are still valid when waiting to close. | |||
| ~AudioInterfacePort() { | |||
| // Close stream here before destructing AudioInterfacePort, so the mutexes are still valid when waiting to close. | |||
| setDevice(-1, 0); | |||
| } | |||
| @@ -69,7 +69,7 @@ struct AudioInterfaceIO : audio::IO { | |||
| else { | |||
| // Timed out, fill output with zeros | |||
| std::memset(output, 0, frames * numOutputs * sizeof(float)); | |||
| // DEBUG("Audio Interface IO underflow"); | |||
| // DEBUG("Audio Interface Port underflow"); | |||
| } | |||
| } | |||
| @@ -105,7 +105,7 @@ struct AudioInterface : Module { | |||
| NUM_LIGHTS | |||
| }; | |||
| AudioInterfaceIO audioIO; | |||
| AudioInterfacePort port; | |||
| int lastSampleRate = 0; | |||
| int lastNumOutputs = -1; | |||
| int lastNumInputs = -1; | |||
| @@ -125,32 +125,32 @@ struct AudioInterface : Module { | |||
| void step() override { | |||
| // Update SRC states | |||
| int sampleRate = (int) APP->engine->getSampleRate(); | |||
| inputSrc.setRates(audioIO.sampleRate, sampleRate); | |||
| outputSrc.setRates(sampleRate, audioIO.sampleRate); | |||
| inputSrc.setRates(port.sampleRate, sampleRate); | |||
| outputSrc.setRates(sampleRate, port.sampleRate); | |||
| inputSrc.setChannels(audioIO.numInputs); | |||
| outputSrc.setChannels(audioIO.numOutputs); | |||
| inputSrc.setChannels(port.numInputs); | |||
| outputSrc.setChannels(port.numOutputs); | |||
| // Inputs: audio engine -> rack engine | |||
| if (audioIO.active && audioIO.numInputs > 0) { | |||
| if (port.active && port.numInputs > 0) { | |||
| // Wait until inputs are present | |||
| // Give up after a timeout in case the audio device is being unresponsive. | |||
| std::unique_lock<std::mutex> lock(audioIO.engineMutex); | |||
| std::unique_lock<std::mutex> lock(port.engineMutex); | |||
| auto cond = [&] { | |||
| return (!audioIO.inputBuffer.empty()); | |||
| return (!port.inputBuffer.empty()); | |||
| }; | |||
| auto timeout = std::chrono::milliseconds(200); | |||
| if (audioIO.engineCv.wait_for(lock, timeout, cond)) { | |||
| if (port.engineCv.wait_for(lock, timeout, cond)) { | |||
| // Convert inputs | |||
| int inLen = audioIO.inputBuffer.size(); | |||
| int inLen = port.inputBuffer.size(); | |||
| int outLen = inputBuffer.capacity(); | |||
| inputSrc.process(audioIO.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen); | |||
| audioIO.inputBuffer.startIncr(inLen); | |||
| inputSrc.process(port.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen); | |||
| port.inputBuffer.startIncr(inLen); | |||
| inputBuffer.endIncr(outLen); | |||
| } | |||
| else { | |||
| // Give up on pulling input | |||
| audioIO.active = false; | |||
| port.active = false; | |||
| // DEBUG("Audio Interface underflow"); | |||
| } | |||
| } | |||
| @@ -163,15 +163,15 @@ struct AudioInterface : Module { | |||
| else { | |||
| std::memset(&inputFrame, 0, sizeof(inputFrame)); | |||
| } | |||
| for (int i = 0; i < audioIO.numInputs; i++) { | |||
| for (int i = 0; i < port.numInputs; i++) { | |||
| outputs[AUDIO_OUTPUT + i].setVoltage(10.f * inputFrame.samples[i]); | |||
| } | |||
| for (int i = audioIO.numInputs; i < AUDIO_INPUTS; i++) { | |||
| for (int i = port.numInputs; i < AUDIO_INPUTS; i++) { | |||
| outputs[AUDIO_OUTPUT + i].setVoltage(0.f); | |||
| } | |||
| // Outputs: rack engine -> audio engine | |||
| if (audioIO.active && audioIO.numOutputs > 0) { | |||
| if (port.active && port.numOutputs > 0) { | |||
| // Get and push output SRC frame | |||
| if (!outputBuffer.full()) { | |||
| dsp::Frame<AUDIO_OUTPUTS> outputFrame; | |||
| @@ -184,51 +184,51 @@ struct AudioInterface : Module { | |||
| if (outputBuffer.full()) { | |||
| // Wait until enough outputs are consumed | |||
| // Give up after a timeout in case the audio device is being unresponsive. | |||
| std::unique_lock<std::mutex> lock(audioIO.engineMutex); | |||
| std::unique_lock<std::mutex> lock(port.engineMutex); | |||
| auto cond = [&] { | |||
| return (audioIO.outputBuffer.size() < (size_t) audioIO.blockSize); | |||
| return (port.outputBuffer.size() < (size_t) port.blockSize); | |||
| }; | |||
| auto timeout = std::chrono::milliseconds(200); | |||
| if (audioIO.engineCv.wait_for(lock, timeout, cond)) { | |||
| if (port.engineCv.wait_for(lock, timeout, cond)) { | |||
| // Push converted output | |||
| int inLen = outputBuffer.size(); | |||
| int outLen = audioIO.outputBuffer.capacity(); | |||
| outputSrc.process(outputBuffer.startData(), &inLen, audioIO.outputBuffer.endData(), &outLen); | |||
| int outLen = port.outputBuffer.capacity(); | |||
| outputSrc.process(outputBuffer.startData(), &inLen, port.outputBuffer.endData(), &outLen); | |||
| outputBuffer.startIncr(inLen); | |||
| audioIO.outputBuffer.endIncr(outLen); | |||
| port.outputBuffer.endIncr(outLen); | |||
| } | |||
| else { | |||
| // Give up on pushing output | |||
| audioIO.active = false; | |||
| port.active = false; | |||
| outputBuffer.clear(); | |||
| // DEBUG("Audio Interface underflow"); | |||
| } | |||
| } | |||
| // Notify audio thread that an output is potentially ready | |||
| audioIO.audioCv.notify_one(); | |||
| port.audioCv.notify_one(); | |||
| } | |||
| // Turn on light if at least one port is enabled in the nearby pair | |||
| for (int i = 0; i < AUDIO_INPUTS / 2; i++) | |||
| lights[INPUT_LIGHT + i].setBrightness(audioIO.active && audioIO.numOutputs >= 2*i+1); | |||
| lights[INPUT_LIGHT + i].setBrightness(port.active && port.numOutputs >= 2*i+1); | |||
| for (int i = 0; i < AUDIO_OUTPUTS / 2; i++) | |||
| lights[OUTPUT_LIGHT + i].setBrightness(audioIO.active && audioIO.numInputs >= 2*i+1); | |||
| lights[OUTPUT_LIGHT + i].setBrightness(port.active && port.numInputs >= 2*i+1); | |||
| } | |||
| json_t *dataToJson() override { | |||
| json_t *rootJ = json_object(); | |||
| json_object_set_new(rootJ, "audio", audioIO.toJson()); | |||
| json_object_set_new(rootJ, "audio", port.toJson()); | |||
| return rootJ; | |||
| } | |||
| void dataFromJson(json_t *rootJ) override { | |||
| json_t *audioJ = json_object_get(rootJ, "audio"); | |||
| audioIO.fromJson(audioJ); | |||
| port.fromJson(audioJ); | |||
| } | |||
| void onReset() override { | |||
| audioIO.setDevice(-1, 0); | |||
| port.setDevice(-1, 0); | |||
| } | |||
| }; | |||
| @@ -272,7 +272,7 @@ struct AudioInterfaceWidget : ModuleWidget { | |||
| AudioWidget *audioWidget = createWidget<AudioWidget>(mm2px(Vec(3.2122073, 14.837339))); | |||
| audioWidget->box.size = mm2px(Vec(44, 28)); | |||
| audioWidget->setAudioIO(module ? &module->audioIO : NULL); | |||
| audioWidget->setAudioPort(module ? &module->port : NULL); | |||
| addChild(audioWidget); | |||
| } | |||
| }; | |||
| @@ -139,7 +139,7 @@ struct CV_CCWidget : ModuleWidget { | |||
| typedef Grid16MidiWidget<CcChoice<CV_CC>> TMidiWidget; | |||
| TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | |||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||
| midiWidget->setMidiIO(module ? &module->midiOutput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiOutput : NULL); | |||
| midiWidget->setModule(module); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -189,7 +189,7 @@ struct CV_GateWidget : ModuleWidget { | |||
| typedef Grid16MidiWidget<NoteChoice<CV_Gate>> TMidiWidget; | |||
| TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | |||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||
| midiWidget->setMidiIO(module ? &module->midiOutput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiOutput : NULL); | |||
| midiWidget->setModule(module); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -346,7 +346,7 @@ struct CV_MIDIWidget : ModuleWidget { | |||
| MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.41891, 14.8373))); | |||
| midiWidget->box.size = mm2px(Vec(33.840, 28)); | |||
| midiWidget->setMidiIO(module ? &module->midiOutput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiOutput : NULL); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -171,7 +171,7 @@ struct MIDI_CCWidget : ModuleWidget { | |||
| typedef Grid16MidiWidget<CcChoice<MIDI_CC>> TMidiWidget; | |||
| TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | |||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||
| midiWidget->setMidiIO(module ? &module->midiInput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiInput : NULL); | |||
| midiWidget->setModule(module); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -540,7 +540,7 @@ struct MIDI_CVWidget : ModuleWidget { | |||
| MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.41891, 14.8373))); | |||
| midiWidget->box.size = mm2px(Vec(33.840, 28)); | |||
| midiWidget->setMidiIO(module ? &module->midiInput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiInput : NULL); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -196,7 +196,7 @@ struct MIDI_GateWidget : ModuleWidget { | |||
| typedef Grid16MidiWidget<NoteChoice<MIDI_Gate>> TMidiWidget; | |||
| TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | |||
| midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||
| midiWidget->setMidiIO(module ? &module->midiInput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiInput : NULL); | |||
| midiWidget->setModule(module); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -433,7 +433,7 @@ struct MIDI_MapWidget : ModuleWidget { | |||
| MIDI_MapDisplay *midiWidget = createWidget<MIDI_MapDisplay>(mm2px(Vec(3.41891, 14.8373))); | |||
| midiWidget->box.size = mm2px(Vec(43.999, 102.664)); | |||
| midiWidget->setMidiIO(module ? &module->midiInput : NULL); | |||
| midiWidget->setMidiPort(module ? &module->midiInput : NULL); | |||
| midiWidget->setModule(module); | |||
| addChild(midiWidget); | |||
| } | |||
| @@ -8,33 +8,33 @@ namespace app { | |||
| struct AudioDriverItem : ui::MenuItem { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| int driver; | |||
| void onAction(const event::Action &e) override { | |||
| audioIO->setDriver(driver); | |||
| port->setDriver(driver); | |||
| } | |||
| }; | |||
| struct AudioDriverChoice : LedDisplayChoice { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!audioIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("Audio driver")); | |||
| for (int driver : audioIO->getDrivers()) { | |||
| for (int driver : port->getDrivers()) { | |||
| AudioDriverItem *item = new AudioDriverItem; | |||
| item->audioIO = audioIO; | |||
| item->port = port; | |||
| item->driver = driver; | |||
| item->text = audioIO->getDriverName(driver); | |||
| item->rightText = CHECKMARK(item->driver == audioIO->driver); | |||
| item->text = port->getDriverName(driver); | |||
| item->rightText = CHECKMARK(item->driver == port->driver); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (audioIO) | |||
| text = audioIO->getDriverName(audioIO->driver); | |||
| if (port) | |||
| text = port->getDriverName(port->driver); | |||
| else | |||
| text = ""; | |||
| } | |||
| @@ -42,53 +42,53 @@ struct AudioDriverChoice : LedDisplayChoice { | |||
| struct AudioDeviceItem : ui::MenuItem { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| int device; | |||
| int offset; | |||
| void onAction(const event::Action &e) override { | |||
| audioIO->setDevice(device, offset); | |||
| port->setDevice(device, offset); | |||
| } | |||
| }; | |||
| struct AudioDeviceChoice : LedDisplayChoice { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| /** Prevents devices with a ridiculous number of channels from being displayed */ | |||
| int maxTotalChannels = 128; | |||
| void onAction(const event::Action &e) override { | |||
| if (!audioIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("Audio device")); | |||
| int deviceCount = audioIO->getDeviceCount(); | |||
| int deviceCount = port->getDeviceCount(); | |||
| { | |||
| AudioDeviceItem *item = new AudioDeviceItem; | |||
| item->audioIO = audioIO; | |||
| item->port = port; | |||
| item->device = -1; | |||
| item->text = "(No device)"; | |||
| item->rightText = CHECKMARK(item->device == audioIO->device); | |||
| item->rightText = CHECKMARK(item->device == port->device); | |||
| menu->addChild(item); | |||
| } | |||
| for (int device = 0; device < deviceCount; device++) { | |||
| int channels = std::min(maxTotalChannels, audioIO->getDeviceChannels(device)); | |||
| for (int offset = 0; offset < channels; offset += audioIO->maxChannels) { | |||
| int channels = std::min(maxTotalChannels, port->getDeviceChannels(device)); | |||
| for (int offset = 0; offset < channels; offset += port->maxChannels) { | |||
| AudioDeviceItem *item = new AudioDeviceItem; | |||
| item->audioIO = audioIO; | |||
| item->port = port; | |||
| item->device = device; | |||
| item->offset = offset; | |||
| item->text = audioIO->getDeviceDetail(device, offset); | |||
| item->rightText = CHECKMARK(item->device == audioIO->device && item->offset == audioIO->offset); | |||
| item->text = port->getDeviceDetail(device, offset); | |||
| item->rightText = CHECKMARK(item->device == port->device && item->offset == port->offset); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| } | |||
| void step() override { | |||
| if (!audioIO) { | |||
| if (!port) { | |||
| text = ""; | |||
| return; | |||
| } | |||
| text = audioIO->getDeviceDetail(audioIO->device, audioIO->offset); | |||
| text = port->getDeviceDetail(port->device, port->offset); | |||
| if (text.empty()) { | |||
| text = "(No device)"; | |||
| color.a = 0.5f; | |||
| @@ -101,37 +101,37 @@ struct AudioDeviceChoice : LedDisplayChoice { | |||
| struct AudioSampleRateItem : ui::MenuItem { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| int sampleRate; | |||
| void onAction(const event::Action &e) override { | |||
| audioIO->setSampleRate(sampleRate); | |||
| port->setSampleRate(sampleRate); | |||
| } | |||
| }; | |||
| struct AudioSampleRateChoice : LedDisplayChoice { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!audioIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("Sample rate")); | |||
| std::vector<int> sampleRates = audioIO->getSampleRates(); | |||
| std::vector<int> sampleRates = port->getSampleRates(); | |||
| if (sampleRates.empty()) { | |||
| menu->addChild(createMenuLabel("(Locked by device)")); | |||
| } | |||
| for (int sampleRate : sampleRates) { | |||
| AudioSampleRateItem *item = new AudioSampleRateItem; | |||
| item->audioIO = audioIO; | |||
| item->port = port; | |||
| item->sampleRate = sampleRate; | |||
| item->text = string::f("%d Hz", sampleRate); | |||
| item->rightText = CHECKMARK(item->sampleRate == audioIO->sampleRate); | |||
| item->rightText = CHECKMARK(item->sampleRate == port->sampleRate); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (audioIO) | |||
| text = string::f("%g kHz", audioIO->sampleRate / 1000.f); | |||
| if (port) | |||
| text = string::f("%g kHz", port->sampleRate / 1000.f); | |||
| else | |||
| text = ""; | |||
| } | |||
| @@ -139,52 +139,52 @@ struct AudioSampleRateChoice : LedDisplayChoice { | |||
| struct AudioBlockSizeItem : ui::MenuItem { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| int blockSize; | |||
| void onAction(const event::Action &e) override { | |||
| audioIO->setBlockSize(blockSize); | |||
| port->setBlockSize(blockSize); | |||
| } | |||
| }; | |||
| struct AudioBlockSizeChoice : LedDisplayChoice { | |||
| audio::IO *audioIO; | |||
| audio::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!audioIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("Block size")); | |||
| std::vector<int> blockSizes = audioIO->getBlockSizes(); | |||
| std::vector<int> blockSizes = port->getBlockSizes(); | |||
| if (blockSizes.empty()) { | |||
| menu->addChild(createMenuLabel("(Locked by device)")); | |||
| } | |||
| for (int blockSize : blockSizes) { | |||
| AudioBlockSizeItem *item = new AudioBlockSizeItem; | |||
| item->audioIO = audioIO; | |||
| item->port = port; | |||
| item->blockSize = blockSize; | |||
| float latency = (float) blockSize / audioIO->sampleRate * 1000.0; | |||
| float latency = (float) blockSize / port->sampleRate * 1000.0; | |||
| item->text = string::f("%d (%.1f ms)", blockSize, latency); | |||
| item->rightText = CHECKMARK(item->blockSize == audioIO->blockSize); | |||
| item->rightText = CHECKMARK(item->blockSize == port->blockSize); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (audioIO) | |||
| text = string::f("%d", audioIO->blockSize); | |||
| if (port) | |||
| text = string::f("%d", port->blockSize); | |||
| else | |||
| text = ""; | |||
| } | |||
| }; | |||
| void AudioWidget::setAudioIO(audio::IO *audioIO) { | |||
| void AudioWidget::setAudioPort(audio::Port *port) { | |||
| clearChildren(); | |||
| math::Vec pos; | |||
| AudioDriverChoice *driverChoice = createWidget<AudioDriverChoice>(pos); | |||
| driverChoice->box.size.x = box.size.x; | |||
| driverChoice->audioIO = audioIO; | |||
| driverChoice->port = port; | |||
| addChild(driverChoice); | |||
| pos = driverChoice->box.getBottomLeft(); | |||
| this->driverChoice = driverChoice; | |||
| @@ -195,7 +195,7 @@ void AudioWidget::setAudioIO(audio::IO *audioIO) { | |||
| AudioDeviceChoice *deviceChoice = createWidget<AudioDeviceChoice>(pos); | |||
| deviceChoice->box.size.x = box.size.x; | |||
| deviceChoice->audioIO = audioIO; | |||
| deviceChoice->port = port; | |||
| addChild(deviceChoice); | |||
| pos = deviceChoice->box.getBottomLeft(); | |||
| this->deviceChoice = deviceChoice; | |||
| @@ -206,7 +206,7 @@ void AudioWidget::setAudioIO(audio::IO *audioIO) { | |||
| AudioSampleRateChoice *sampleRateChoice = createWidget<AudioSampleRateChoice>(pos); | |||
| sampleRateChoice->box.size.x = box.size.x / 2; | |||
| sampleRateChoice->audioIO = audioIO; | |||
| sampleRateChoice->port = port; | |||
| addChild(sampleRateChoice); | |||
| this->sampleRateChoice = sampleRateChoice; | |||
| @@ -218,7 +218,7 @@ void AudioWidget::setAudioIO(audio::IO *audioIO) { | |||
| AudioBlockSizeChoice *bufferSizeChoice = createWidget<AudioBlockSizeChoice>(pos); | |||
| bufferSizeChoice->box.pos.x = box.size.x / 2; | |||
| bufferSizeChoice->box.size.x = box.size.x / 2; | |||
| bufferSizeChoice->audioIO = audioIO; | |||
| bufferSizeChoice->port = port; | |||
| addChild(bufferSizeChoice); | |||
| this->bufferSizeChoice = bufferSizeChoice; | |||
| } | |||
| @@ -8,36 +8,36 @@ namespace app { | |||
| struct MidiDriverItem : ui::MenuItem { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| int driverId; | |||
| void onAction(const event::Action &e) override { | |||
| midiIO->setDriverId(driverId); | |||
| port->setDriverId(driverId); | |||
| } | |||
| }; | |||
| struct MidiDriverChoice : LedDisplayChoice { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!midiIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("MIDI driver")); | |||
| for (int driverId : midiIO->getDriverIds()) { | |||
| for (int driverId : port->getDriverIds()) { | |||
| MidiDriverItem *item = new MidiDriverItem; | |||
| item->midiIO = midiIO; | |||
| item->port = port; | |||
| item->driverId = driverId; | |||
| item->text = midiIO->getDriverName(driverId); | |||
| item->rightText = CHECKMARK(item->driverId == midiIO->driverId); | |||
| item->text = port->getDriverName(driverId); | |||
| item->rightText = CHECKMARK(item->driverId == port->driverId); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (!midiIO) { | |||
| if (!port) { | |||
| text = ""; | |||
| return; | |||
| } | |||
| text = midiIO->getDriverName(midiIO->driverId); | |||
| text = port->getDriverName(port->driverId); | |||
| if (text.empty()) { | |||
| text = "(No driver)"; | |||
| color.a = 0.5f; | |||
| @@ -49,44 +49,44 @@ struct MidiDriverChoice : LedDisplayChoice { | |||
| }; | |||
| struct MidiDeviceItem : ui::MenuItem { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| int deviceId; | |||
| void onAction(const event::Action &e) override { | |||
| midiIO->setDeviceId(deviceId); | |||
| port->setDeviceId(deviceId); | |||
| } | |||
| }; | |||
| struct MidiDeviceChoice : LedDisplayChoice { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!midiIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("MIDI device")); | |||
| { | |||
| MidiDeviceItem *item = new MidiDeviceItem; | |||
| item->midiIO = midiIO; | |||
| item->port = port; | |||
| item->deviceId = -1; | |||
| item->text = "(No device)"; | |||
| item->rightText = CHECKMARK(item->deviceId == midiIO->deviceId); | |||
| item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||
| menu->addChild(item); | |||
| } | |||
| for (int deviceId : midiIO->getDeviceIds()) { | |||
| for (int deviceId : port->getDeviceIds()) { | |||
| MidiDeviceItem *item = new MidiDeviceItem; | |||
| item->midiIO = midiIO; | |||
| item->port = port; | |||
| item->deviceId = deviceId; | |||
| item->text = midiIO->getDeviceName(deviceId); | |||
| item->rightText = CHECKMARK(item->deviceId == midiIO->deviceId); | |||
| item->text = port->getDeviceName(deviceId); | |||
| item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (!midiIO) { | |||
| if (!port) { | |||
| text = ""; | |||
| return; | |||
| } | |||
| text = midiIO->getDeviceName(midiIO->deviceId); | |||
| text = port->getDeviceName(port->deviceId); | |||
| if (text.empty()) { | |||
| text = "(No device)"; | |||
| color.a = 0.5f; | |||
| @@ -98,47 +98,47 @@ struct MidiDeviceChoice : LedDisplayChoice { | |||
| }; | |||
| struct MidiChannelItem : ui::MenuItem { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| int channel; | |||
| void onAction(const event::Action &e) override { | |||
| midiIO->channel = channel; | |||
| port->channel = channel; | |||
| } | |||
| }; | |||
| struct MidiChannelChoice : LedDisplayChoice { | |||
| midi::IO *midiIO; | |||
| midi::Port *port; | |||
| void onAction(const event::Action &e) override { | |||
| if (!midiIO) | |||
| if (!port) | |||
| return; | |||
| ui::Menu *menu = createMenu(); | |||
| menu->addChild(createMenuLabel("MIDI channel")); | |||
| for (int channel : midiIO->getChannels()) { | |||
| for (int channel : port->getChannels()) { | |||
| MidiChannelItem *item = new MidiChannelItem; | |||
| item->midiIO = midiIO; | |||
| item->port = port; | |||
| item->channel = channel; | |||
| item->text = midiIO->getChannelName(channel); | |||
| item->rightText = CHECKMARK(item->channel == midiIO->channel); | |||
| item->text = port->getChannelName(channel); | |||
| item->rightText = CHECKMARK(item->channel == port->channel); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (midiIO) | |||
| text = midiIO->getChannelName(midiIO->channel); | |||
| if (port) | |||
| text = port->getChannelName(port->channel); | |||
| else | |||
| text = ""; | |||
| } | |||
| }; | |||
| void MidiWidget::setMidiIO(midi::IO *midiIO) { | |||
| void MidiWidget::setMidiPort(midi::Port *port) { | |||
| clearChildren(); | |||
| math::Vec pos; | |||
| MidiDriverChoice *driverChoice = createWidget<MidiDriverChoice>(pos); | |||
| driverChoice->box.size.x = box.size.x; | |||
| driverChoice->midiIO = midiIO; | |||
| driverChoice->port = port; | |||
| addChild(driverChoice); | |||
| pos = driverChoice->box.getBottomLeft(); | |||
| this->driverChoice = driverChoice; | |||
| @@ -149,7 +149,7 @@ void MidiWidget::setMidiIO(midi::IO *midiIO) { | |||
| MidiDeviceChoice *deviceChoice = createWidget<MidiDeviceChoice>(pos); | |||
| deviceChoice->box.size.x = box.size.x; | |||
| deviceChoice->midiIO = midiIO; | |||
| deviceChoice->port = port; | |||
| addChild(deviceChoice); | |||
| pos = deviceChoice->box.getBottomLeft(); | |||
| this->deviceChoice = deviceChoice; | |||
| @@ -160,7 +160,7 @@ void MidiWidget::setMidiIO(midi::IO *midiIO) { | |||
| MidiChannelChoice *channelChoice = createWidget<MidiChannelChoice>(pos); | |||
| channelChoice->box.size.x = box.size.x; | |||
| channelChoice->midiIO = midiIO; | |||
| channelChoice->port = port; | |||
| addChild(channelChoice); | |||
| this->channelChoice = channelChoice; | |||
| } | |||
| @@ -9,15 +9,15 @@ namespace rack { | |||
| namespace audio { | |||
| IO::IO() { | |||
| Port::Port() { | |||
| setDriver(RtAudio::UNSPECIFIED); | |||
| } | |||
| IO::~IO() { | |||
| Port::~Port() { | |||
| closeStream(); | |||
| } | |||
| std::vector<int> IO::getDrivers() { | |||
| std::vector<int> Port::getDrivers() { | |||
| std::vector<RtAudio::Api> apis; | |||
| RtAudio::getCompiledApi(apis); | |||
| std::vector<int> drivers; | |||
| @@ -29,7 +29,7 @@ std::vector<int> IO::getDrivers() { | |||
| return drivers; | |||
| } | |||
| std::string IO::getDriverName(int driver) { | |||
| std::string Port::getDriverName(int driver) { | |||
| switch (driver) { | |||
| case RtAudio::UNSPECIFIED: return "Unspecified"; | |||
| case RtAudio::LINUX_ALSA: return "ALSA"; | |||
| @@ -46,7 +46,7 @@ std::string IO::getDriverName(int driver) { | |||
| } | |||
| } | |||
| void IO::setDriver(int driver) { | |||
| void Port::setDriver(int driver) { | |||
| // Close device | |||
| setDevice(-1, 0); | |||
| @@ -67,7 +67,7 @@ void IO::setDriver(int driver) { | |||
| } | |||
| } | |||
| int IO::getDeviceCount() { | |||
| int Port::getDeviceCount() { | |||
| if (rtAudio) { | |||
| return rtAudio->getDeviceCount(); | |||
| } | |||
| @@ -77,7 +77,7 @@ int IO::getDeviceCount() { | |||
| return 0; | |||
| } | |||
| bool IO::getDeviceInfo(int device, RtAudio::DeviceInfo *deviceInfo) { | |||
| bool Port::getDeviceInfo(int device, RtAudio::DeviceInfo *deviceInfo) { | |||
| if (!deviceInfo) | |||
| return false; | |||
| @@ -100,7 +100,7 @@ bool IO::getDeviceInfo(int device, RtAudio::DeviceInfo *deviceInfo) { | |||
| return false; | |||
| } | |||
| int IO::getDeviceChannels(int device) { | |||
| int Port::getDeviceChannels(int device) { | |||
| if (device < 0) | |||
| return 0; | |||
| @@ -115,7 +115,7 @@ int IO::getDeviceChannels(int device) { | |||
| return 0; | |||
| } | |||
| std::string IO::getDeviceName(int device) { | |||
| std::string Port::getDeviceName(int device) { | |||
| if (device < 0) | |||
| return ""; | |||
| @@ -130,7 +130,7 @@ std::string IO::getDeviceName(int device) { | |||
| return ""; | |||
| } | |||
| std::string IO::getDeviceDetail(int device, int offset) { | |||
| std::string Port::getDeviceDetail(int device, int offset) { | |||
| if (device < 0) | |||
| return ""; | |||
| @@ -154,14 +154,14 @@ std::string IO::getDeviceDetail(int device, int offset) { | |||
| return ""; | |||
| } | |||
| void IO::setDevice(int device, int offset) { | |||
| void Port::setDevice(int device, int offset) { | |||
| closeStream(); | |||
| this->device = device; | |||
| this->offset = offset; | |||
| openStream(); | |||
| } | |||
| std::vector<int> IO::getSampleRates() { | |||
| std::vector<int> Port::getSampleRates() { | |||
| if (rtAudio) { | |||
| try { | |||
| RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); | |||
| @@ -175,7 +175,7 @@ std::vector<int> IO::getSampleRates() { | |||
| return {}; | |||
| } | |||
| void IO::setSampleRate(int sampleRate) { | |||
| void Port::setSampleRate(int sampleRate) { | |||
| if (sampleRate == this->sampleRate) | |||
| return; | |||
| closeStream(); | |||
| @@ -183,14 +183,14 @@ void IO::setSampleRate(int sampleRate) { | |||
| openStream(); | |||
| } | |||
| std::vector<int> IO::getBlockSizes() { | |||
| std::vector<int> Port::getBlockSizes() { | |||
| if (rtAudio) { | |||
| return {64, 128, 256, 512, 1024, 2048, 4096}; | |||
| } | |||
| return {}; | |||
| } | |||
| void IO::setBlockSize(int blockSize) { | |||
| void Port::setBlockSize(int blockSize) { | |||
| if (blockSize == this->blockSize) | |||
| return; | |||
| closeStream(); | |||
| @@ -198,7 +198,7 @@ void IO::setBlockSize(int blockSize) { | |||
| openStream(); | |||
| } | |||
| void IO::setChannels(int numOutputs, int numInputs) { | |||
| void Port::setChannels(int numOutputs, int numInputs) { | |||
| this->numOutputs = numOutputs; | |||
| this->numInputs = numInputs; | |||
| onChannelsChange(); | |||
| @@ -206,18 +206,18 @@ void IO::setChannels(int numOutputs, int numInputs) { | |||
| static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { | |||
| IO *audioIO = (IO*) userData; | |||
| assert(audioIO); | |||
| Port *port = (Port*) userData; | |||
| assert(port); | |||
| // Exploit the stream time to run code on startup of the audio thread | |||
| if (streamTime == 0.0) { | |||
| system::setThreadName("Audio"); | |||
| system::setThreadRealTime(); | |||
| } | |||
| audioIO->processStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); | |||
| port->processStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); | |||
| return 0; | |||
| } | |||
| void IO::openStream() { | |||
| void Port::openStream() { | |||
| if (device < 0) | |||
| return; | |||
| @@ -294,7 +294,7 @@ void IO::openStream() { | |||
| } | |||
| } | |||
| void IO::closeStream() { | |||
| void Port::closeStream() { | |||
| setChannels(0, 0); | |||
| if (rtAudio) { | |||
| @@ -325,7 +325,7 @@ void IO::closeStream() { | |||
| onCloseStream(); | |||
| } | |||
| json_t *IO::toJson() { | |||
| json_t *Port::toJson() { | |||
| json_t *rootJ = json_object(); | |||
| json_object_set_new(rootJ, "driver", json_integer(driver)); | |||
| std::string deviceName = getDeviceName(device); | |||
| @@ -338,7 +338,7 @@ json_t *IO::toJson() { | |||
| return rootJ; | |||
| } | |||
| void IO::fromJson(json_t *rootJ) { | |||
| void Port::fromJson(json_t *rootJ) { | |||
| closeStream(); | |||
| json_t *driverJ = json_object_get(rootJ, "driver"); | |||
| @@ -25,7 +25,7 @@ struct BridgeMidiDriver; | |||
| struct BridgeClientConnection; | |||
| static BridgeClientConnection *connections[BRIDGE_NUM_PORTS] = {}; | |||
| static audio::IO *audioListeners[BRIDGE_NUM_PORTS] = {}; | |||
| static audio::Port *audioListeners[BRIDGE_NUM_PORTS] = {}; | |||
| static std::thread serverThread; | |||
| static bool serverRunning = false; | |||
| static BridgeMidiDriver *driver = NULL; | |||
| @@ -429,7 +429,7 @@ void bridgeDestroy() { | |||
| serverThread.join(); | |||
| } | |||
| void bridgeAudioSubscribe(int port, audio::IO *audio) { | |||
| void bridgeAudioSubscribe(int port, audio::Port *audio) { | |||
| if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | |||
| return; | |||
| // Check if an Audio is already subscribed on the port | |||
| @@ -440,7 +440,7 @@ void bridgeAudioSubscribe(int port, audio::IO *audio) { | |||
| connections[port]->refreshAudio(); | |||
| } | |||
| void bridgeAudioUnsubscribe(int port, audio::IO *audio) { | |||
| void bridgeAudioUnsubscribe(int port, audio::Port *audio) { | |||
| if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | |||
| return; | |||
| if (audioListeners[port] != audio) | |||
| @@ -48,14 +48,14 @@ void OutputDevice::unsubscribe(Output *output) { | |||
| } | |||
| //////////////////// | |||
| // IO | |||
| // Port | |||
| //////////////////// | |||
| std::vector<int> IO::getDriverIds() { | |||
| std::vector<int> Port::getDriverIds() { | |||
| return driverIds; | |||
| } | |||
| std::string IO::getDriverName(int driverId) { | |||
| std::string Port::getDriverName(int driverId) { | |||
| auto it = drivers.find(driverId); | |||
| if (it == drivers.end()) | |||
| return ""; | |||
| @@ -63,7 +63,7 @@ std::string IO::getDriverName(int driverId) { | |||
| return it->second->getName(); | |||
| } | |||
| void IO::setDriverId(int driverId) { | |||
| void Port::setDriverId(int driverId) { | |||
| // Unset device and driver | |||
| setDeviceId(-1); | |||
| if (driver) { | |||
| @@ -79,18 +79,18 @@ void IO::setDriverId(int driverId) { | |||
| } | |||
| } | |||
| std::string IO::getChannelName(int channel) { | |||
| std::string Port::getChannelName(int channel) { | |||
| if (channel == -1) | |||
| return "All channels"; | |||
| else | |||
| return string::f("Channel %d", channel + 1); | |||
| } | |||
| void IO::setChannel(int channel) { | |||
| void Port::setChannel(int channel) { | |||
| this->channel = channel; | |||
| } | |||
| json_t *IO::toJson() { | |||
| json_t *Port::toJson() { | |||
| json_t *rootJ = json_object(); | |||
| json_object_set_new(rootJ, "driver", json_integer(driverId)); | |||
| std::string deviceName = getDeviceName(deviceId); | |||
| @@ -100,7 +100,7 @@ json_t *IO::toJson() { | |||
| return rootJ; | |||
| } | |||
| void IO::fromJson(json_t *rootJ) { | |||
| void Port::fromJson(json_t *rootJ) { | |||
| json_t *driverJ = json_object_get(rootJ, "driver"); | |||
| if (driverJ) | |||
| setDriverId(json_integer_value(driverJ)); | |||