@@ -40,7 +40,9 @@ struct AudioIO { | |||
std::string getDeviceDetail(int device, int offset); | |||
void setDevice(int device, int offset); | |||
std::vector<int> getSampleRates(); | |||
void setSampleRate(int sampleRate); | |||
std::vector<int> getBlockSizes(); | |||
void setBlockSize(int blockSize); | |||
void setChannels(int numOutputs, int numInputs); | |||
@@ -49,8 +51,6 @@ struct AudioIO { | |||
void openStream(); | |||
void closeStream(); | |||
std::vector<int> getSampleRates(); | |||
virtual void processStream(const float *input, float *output, int frames) {} | |||
virtual void onCloseStream() {} | |||
virtual void onOpenStream() {} | |||
@@ -98,7 +98,11 @@ struct AudioSampleRateChoice : LedDisplayChoice { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Sample rate")); | |||
for (int sampleRate : audioWidget->audioIO->getSampleRates()) { | |||
std::vector<int> sampleRates = audioWidget->audioIO->getSampleRates(); | |||
if (sampleRates.empty()) { | |||
menu->addChild(construct<MenuLabel>(&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>(&MenuLabel::text, "Block size")); | |||
std::vector<int> blockSizes = {64, 128, 256, 512, 1024, 2048, 4096}; | |||
std::vector<int> blockSizes = audioWidget->audioIO->getBlockSizes(); | |||
if (blockSizes.empty()) { | |||
menu->addChild(construct<MenuLabel>(&MenuLabel::text, "(None available)")); | |||
} | |||
for (int blockSize : blockSizes) { | |||
AudioBlockSizeItem *item = new AudioBlockSizeItem(); | |||
item->audioIO = audioWidget->audioIO; | |||
@@ -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<int> AudioIO::getSampleRates() { | |||
if (rtAudio) { | |||
try { | |||
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); | |||
std::vector<int> 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<int> 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<int> AudioIO::getSampleRates() { | |||
if (rtAudio) { | |||
try { | |||
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device); | |||
std::vector<int> 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)); | |||
@@ -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<double>(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) { | |||