diff --git a/include/audio.hpp b/include/audio.hpp index 38da910c..972d4ec6 100644 --- a/include/audio.hpp +++ b/include/audio.hpp @@ -40,7 +40,9 @@ struct AudioIO { std::string getDeviceDetail(int device, int offset); void setDevice(int device, int offset); + std::vector getSampleRates(); void setSampleRate(int sampleRate); + std::vector getBlockSizes(); void setBlockSize(int blockSize); void setChannels(int numOutputs, int numInputs); @@ -49,8 +51,6 @@ struct AudioIO { void openStream(); void closeStream(); - std::vector getSampleRates(); - virtual void processStream(const float *input, float *output, int frames) {} virtual void onCloseStream() {} virtual void onOpenStream() {} diff --git a/src/app/AudioWidget.cpp b/src/app/AudioWidget.cpp index 6050fa6f..6577a399 100644 --- a/src/app/AudioWidget.cpp +++ b/src/app/AudioWidget.cpp @@ -98,7 +98,11 @@ struct AudioSampleRateChoice : LedDisplayChoice { void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->addChild(construct(&MenuLabel::text, "Sample rate")); - for (int sampleRate : audioWidget->audioIO->getSampleRates()) { + std::vector sampleRates = audioWidget->audioIO->getSampleRates(); + if (sampleRates.empty()) { + menu->addChild(construct(&MenuLabel::text, "(None available)")); + } + for (int sampleRate : sampleRates) { AudioSampleRateItem *item = new AudioSampleRateItem(); item->audioIO = audioWidget->audioIO; item->sampleRate = sampleRate; @@ -126,7 +130,10 @@ struct AudioBlockSizeChoice : LedDisplayChoice { void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->addChild(construct(&MenuLabel::text, "Block size")); - std::vector blockSizes = {64, 128, 256, 512, 1024, 2048, 4096}; + std::vector blockSizes = audioWidget->audioIO->getBlockSizes(); + if (blockSizes.empty()) { + menu->addChild(construct(&MenuLabel::text, "(None available)")); + } for (int blockSize : blockSizes) { AudioBlockSizeItem *item = new AudioBlockSizeItem(); item->audioIO = audioWidget->audioIO; diff --git a/src/audio.cpp b/src/audio.cpp index 254a580b..fbef04ed 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -70,7 +70,7 @@ int AudioIO::getDeviceCount() { if (rtAudio) { return rtAudio->getDeviceCount(); } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { return BRIDGE_NUM_PORTS; } return 0; @@ -108,7 +108,7 @@ int AudioIO::getDeviceChannels(int device) { if (getDeviceInfo(device, &deviceInfo)) return max((int) deviceInfo.inputChannels, (int) deviceInfo.outputChannels); } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { return 2; } return 0; @@ -123,7 +123,7 @@ std::string AudioIO::getDeviceName(int device) { if (getDeviceInfo(device, &deviceInfo)) return deviceInfo.name; } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { return stringf("%d", device + 1); } return ""; @@ -147,7 +147,7 @@ std::string AudioIO::getDeviceDetail(int device, int offset) { return deviceDetail; } } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { return stringf("Port %d", device + 1); } return ""; @@ -160,13 +160,38 @@ void AudioIO::setDevice(int device, int offset) { openStream(); } +std::vector AudioIO::getSampleRates() { + 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()); + } + } + return {}; +} + void AudioIO::setSampleRate(int sampleRate) { + if (sampleRate == this->sampleRate) + return; closeStream(); this->sampleRate = sampleRate; openStream(); } +std::vector AudioIO::getBlockSizes() { + if (rtAudio) { + return {64, 128, 256, 512, 1024, 2048, 4096}; + } + return {}; +} + void AudioIO::setBlockSize(int blockSize) { + if (blockSize == this->blockSize) + return; closeStream(); this->blockSize = blockSize; openStream(); @@ -256,11 +281,8 @@ void AudioIO::openStream() { this->sampleRate = rtAudio->getStreamSampleRate(); onOpenStream(); } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { setChannels(0, 0); - // TEMP - sampleRate = 44100; - blockSize = 256; bridgeAudioSubscribe(device, this); } } @@ -289,31 +311,13 @@ void AudioIO::closeStream() { } deviceInfo = RtAudio::DeviceInfo(); } - if (driver == BRIDGE_DRIVER) { + else if (driver == BRIDGE_DRIVER) { bridgeAudioUnsubscribe(device, this); } onCloseStream(); } -std::vector AudioIO::getSampleRates() { - 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()); - } - } - if (driver == BRIDGE_DRIVER) { - 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)); diff --git a/src/bridge.cpp b/src/bridge.cpp index fb621f0c..a7952ffb 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -21,14 +21,11 @@ namespace rack { -static const int RECV_BUFFER_SIZE = (1<<13); -static const int RECV_QUEUE_SIZE = (1<<17); - struct BridgeClientConnection; static BridgeClientConnection *connections[BRIDGE_NUM_PORTS] = {}; static AudioIO *audioListeners[BRIDGE_NUM_PORTS] = {}; static std::thread serverThread; -static bool running; +static bool serverRunning = false; struct BridgeClientConnection { @@ -138,7 +135,7 @@ struct BridgeClientConnection { case QUIT_COMMAND: { debug("Bridge client quitting"); - ready = true; + ready = false; } break; case PORT_SET_COMMAND: { @@ -150,7 +147,7 @@ struct BridgeClientConnection { case MIDI_MESSAGE_SEND_COMMAND: { uint8_t midiBuffer[3]; recv(&midiBuffer, 3); - // debug("MIDI: %02x %02x %02x", midiBuffer[0], midiBuffer[1], midiBuffer[2]); + debug("MIDI: %02x %02x %02x", midiBuffer[0], midiBuffer[1], midiBuffer[2]); } break; case AUDIO_SAMPLE_RATE_SET_COMMAND: { @@ -174,9 +171,13 @@ struct BridgeClientConnection { } float input[length]; - recv(&input, length * sizeof(float)); + if (!recv(&input, length * sizeof(float))) { + ready = false; + return; + } float output[length]; int frames = length / 2; + memset(&output, 0, sizeof(output)); processStream(input, output, frames); send(&output, length * sizeof(float)); flush(); @@ -184,12 +185,12 @@ struct BridgeClientConnection { case AUDIO_ACTIVATE: { audioActive = true; - refreshAudioActive(); + refreshAudio(); } break; case AUDIO_DEACTIVATE: { audioActive = false; - refreshAudioActive(); + refreshAudio(); } break; } } @@ -206,7 +207,7 @@ struct BridgeClientConnection { if ((0 <= port && port < BRIDGE_NUM_PORTS) && !connections[port]) { this->port = port; connections[this->port] = this; - refreshAudioActive(); + refreshAudio(); } else { this->port = -1; @@ -214,8 +215,8 @@ struct BridgeClientConnection { } void setSampleRate(int sampleRate) { - // TODO this->sampleRate = sampleRate; + refreshAudio(); } void processStream(const float *input, float *output, int frames) { @@ -223,19 +224,22 @@ struct BridgeClientConnection { return; if (!audioListeners[port]) return; + audioListeners[port]->setBlockSize(frames); audioListeners[port]->processStream(input, output, frames); - debug("%d frames", frames); } - void refreshAudioActive() { + void refreshAudio() { if (!(0 <= port && port < BRIDGE_NUM_PORTS)) return; + if (connections[port] != this) + return; if (!audioListeners[port]) return; if (audioActive) audioListeners[port]->setChannels(2, 2); else audioListeners[port]->setChannels(0, 0); + audioListeners[port]->setSampleRate(sampleRate); } }; @@ -267,13 +271,13 @@ static void clientRun(int client) { } -static void serverRun() { +static void serverConnect() { int err; // Initialize sockets #ifdef ARCH_WIN WSADATA wsaData; - err = WSAStartup(MAKEWORD(2,2), &wsaData); + err = WSAStartup(MAKEWORD(2, 2), &wsaData); defer({ WSACleanup(); }); @@ -352,8 +356,7 @@ static void serverRun() { #endif // Accept clients - running = true; - while (running) { + while (serverRunning) { int client = accept(server, NULL, NULL); if (client < 0) { // Wait a bit before attempting to accept another client @@ -369,13 +372,20 @@ static void serverRun() { info("Bridge server closed"); } +static void serverRun() { + while (serverRunning) { + std::this_thread::sleep_for(std::chrono::duration(0.1)); + serverConnect(); + } +} void bridgeInit() { + serverRunning = true; serverThread = std::thread(serverRun); } void bridgeDestroy() { - running = false; + serverRunning = false; serverThread.join(); } @@ -387,7 +397,7 @@ void bridgeAudioSubscribe(int port, AudioIO *audio) { return; audioListeners[port] = audio; if (connections[port]) - connections[port]->refreshAudioActive(); + connections[port]->refreshAudio(); } void bridgeAudioUnsubscribe(int port, AudioIO *audio) {