@@ -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)); | |||