Browse Source

Remove Bridge audio/MIDI driver.

tags/v2.0.0
Andrew Belt 5 years ago
parent
commit
a34b6ef16e
5 changed files with 2 additions and 556 deletions
  1. +0
    -15
      include/bridge.hpp
  2. +0
    -56
      include/bridgeprotocol.hpp
  3. +2
    -28
      src/audio.cpp
  4. +0
    -454
      src/bridge.cpp
  5. +0
    -3
      src/main.cpp

+ 0
- 15
include/bridge.hpp View File

@@ -1,15 +0,0 @@
#pragma once
#include <bridgeprotocol.hpp>
#include <audio.hpp>


namespace rack {


void bridgeInit();
void bridgeDestroy();
void bridgeAudioSubscribe(int channel, audio::Port* port);
void bridgeAudioUnsubscribe(int channel, audio::Port* port);


} // namespace rack

+ 0
- 56
include/bridgeprotocol.hpp View File

@@ -1,56 +0,0 @@
#pragma once
#include <stdint.h>


namespace rack {


/** 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;
const int BRIDGE_NUM_PORTS = 16;
/** Number of VST/AU automation parameters */
const int BRIDGE_NUM_PARAMS = 16;
/** An arbitrary number which prevents connection from other protocols (like WebSockets) and old Bridge versions */
const uint32_t BRIDGE_HELLO = 0xff00fefd;
const int BRIDGE_INPUTS = 8;
const int BRIDGE_OUTPUTS = 8;


/** All commands are called from the client and served by the server
send
- uint8_t cmd
*/
enum BridgeCommand {
NO_COMMAND = 0,
/** Requests the server to shut down the client */
QUIT_COMMAND,
/** Sets the port
send
- uint8_t port
*/
PORT_SET_COMMAND,
/** Sends a 3-byte MIDI command
send
- uint8_t msg[3]
*/
MIDI_MESSAGE_COMMAND,
/** Sets the audio sample rate
send
- uint32_t sampleRate
*/
AUDIO_SAMPLE_RATE_SET_COMMAND,
/** Sends and receives an audio buffer
send
- uint32_t frames
- float input[BRIDGE_INPUTS * frames]
recv
- float output[BRIDGE_OUTPUTS * frames]
*/
AUDIO_PROCESS_COMMAND,
NUM_COMMANDS
};


} // namespace rack

+ 2
- 28
src/audio.cpp View File

@@ -1,7 +1,6 @@
#include <audio.hpp>
#include <string.hpp>
#include <math.hpp>
#include <bridge.hpp>
#include <system.hpp>


@@ -10,7 +9,7 @@ namespace audio {


Port::Port() {
setDriverId(RtAudio::UNSPECIFIED);
setDriverId(0);
}

Port::~Port() {
@@ -24,14 +23,12 @@ std::vector<int> Port::getDriverIds() {
for (RtAudio::Api api : apis) {
drivers.push_back((int) api);
}
// Add fake Bridge driver
drivers.push_back(BRIDGE_DRIVER);
return drivers;
}

std::string Port::getDriverName(int driverId) {
switch (driverId) {
case RtAudio::UNSPECIFIED: return "Unspecified";
case 0: return "Default";
case RtAudio::LINUX_ALSA: return "ALSA";
case RtAudio::LINUX_PULSE: return "PulseAudio";
case RtAudio::LINUX_OSS: return "OSS";
@@ -41,7 +38,6 @@ std::string Port::getDriverName(int driverId) {
case RtAudio::WINDOWS_ASIO: return "ASIO";
case RtAudio::WINDOWS_DS: return "DirectSound";
case RtAudio::RTAUDIO_DUMMY: return "Dummy Audio";
case BRIDGE_DRIVER: return "Bridge";
default: return "Unknown";
}
}
@@ -62,18 +58,12 @@ void Port::setDriverId(int driverId) {
rtAudio = new RtAudio((RtAudio::Api) driverId);
this->driverId = (int) rtAudio->getCurrentApi();
}
else if (driverId == BRIDGE_DRIVER) {
this->driverId = BRIDGE_DRIVER;
}
}

int Port::getDeviceCount() {
if (rtAudio) {
return rtAudio->getDeviceCount();
}
else if (driverId == BRIDGE_DRIVER) {
return BRIDGE_NUM_PORTS;
}
return 0;
}

@@ -109,9 +99,6 @@ int Port::getDeviceChannels(int deviceId) {
if (getDeviceInfo(deviceId, &deviceInfo))
return std::max((int) deviceInfo.inputChannels, (int) deviceInfo.outputChannels);
}
else if (driverId == BRIDGE_DRIVER) {
return std::max(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
}
return 0;
}

@@ -124,9 +111,6 @@ std::string Port::getDeviceName(int deviceId) {
if (getDeviceInfo(deviceId, &deviceInfo))
return deviceInfo.name;
}
else if (driverId == BRIDGE_DRIVER) {
return string::f("%d", deviceId + 1);
}
return "";
}

@@ -148,9 +132,6 @@ std::string Port::getDeviceDetail(int deviceId, int offset) {
return deviceDetail;
}
}
else if (driverId == BRIDGE_DRIVER) {
return string::f("Port %d", deviceId + 1);
}
return "";
}

@@ -288,10 +269,6 @@ void Port::openStream() {
this->sampleRate = rtAudio->getStreamSampleRate();
onOpenStream();
}
else if (driverId == BRIDGE_DRIVER) {
setChannels(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
bridgeAudioSubscribe(deviceId, this);
}
}

void Port::closeStream() {
@@ -318,9 +295,6 @@ void Port::closeStream() {
}
deviceInfo = RtAudio::DeviceInfo();
}
else if (driverId == BRIDGE_DRIVER) {
bridgeAudioUnsubscribe(deviceId, this);
}

onCloseStream();
}


+ 0
- 454
src/bridge.cpp View File

@@ -1,454 +0,0 @@
#include <bridge.hpp>
#include <midi.hpp>
#include <string.hpp>
#include <dsp/ringbuffer.hpp>

#include <unistd.h>
#if defined ARCH_WIN
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#endif

#include <thread>


namespace rack {


struct BridgeMidiDriver;


struct BridgeClientConnection;
static BridgeClientConnection* connections[BRIDGE_NUM_PORTS] = {};
static audio::Port* audioListeners[BRIDGE_NUM_PORTS] = {};
static std::thread serverThread;
static bool serverRunning = false;
static BridgeMidiDriver* driver = NULL;


struct BridgeMidiInputDevice : midi::InputDevice {
};


struct BridgeMidiDriver : midi::Driver {
BridgeMidiInputDevice devices[16];

std::string getName() override {
return "Bridge";
}

std::vector<int> getInputDeviceIds() override {
std::vector<int> deviceIds;
for (int i = 0; i < 16; i++) {
deviceIds.push_back(i);
}
return deviceIds;
}

std::string getInputDeviceName(int deviceId) override {
if (deviceId < 0)
return "";
return string::f("Port %d", deviceId + 1);
}

midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override {
if (!(0 <= deviceId && deviceId < 16))
return NULL;

devices[deviceId].subscribe(input);
return &devices[deviceId];
}

void unsubscribeInput(int deviceId, midi::Input* input) override {
if (!(0 <= deviceId && deviceId < 16))
return;

devices[deviceId].unsubscribe(input);
}
};


struct BridgeClientConnection {
int client;
bool ready = false;

int port = -1;
int sampleRate = 0;

~BridgeClientConnection() {
setPort(-1);
}

/** Returns true if successful */
bool send(const void* buffer, int length) {
if (length <= 0)
return false;

#if defined ARCH_LIN
int flags = MSG_NOSIGNAL;
#else
int flags = 0;
#endif
ssize_t remaining = 0;
while (remaining < length) {
ssize_t actual = ::send(client, (const char*) buffer, length, flags);
if (actual <= 0) {
ready = false;
return false;
}
remaining += actual;
}
return true;
}

template <typename T>
bool send(T x) {
return send(&x, sizeof(x));
}

/** Returns true if successful */
bool recv(void* buffer, int length) {
if (length <= 0)
return false;

#if defined ARCH_LIN
int flags = MSG_NOSIGNAL;
#else
int flags = 0;
#endif
ssize_t remaining = 0;
while (remaining < length) {
ssize_t actual = ::recv(client, (char*) buffer + remaining, length - remaining, flags);
if (actual <= 0) {
ready = false;
return false;
}
remaining += actual;
}
return true;
}

template <typename T>
bool recv(T* x) {
return recv(x, sizeof(*x));
}

void flush() {
// Turn off Nagle
int flag = 1;
setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int));
// Turn on Nagle
flag = 0;
setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int));
}

void run() {
INFO("Bridge client connected");

// Check hello key
uint32_t hello = -1;
recv<uint32_t>(&hello);
if (hello != BRIDGE_HELLO) {
INFO("Bridge client protocol mismatch %x %x", hello, BRIDGE_HELLO);
return;
}

// Process commands until no longer ready
ready = true;
while (ready) {
step();
}

INFO("Bridge client closed");
}

/** Accepts a command from the client */
void step() {
uint8_t command;
if (!recv<uint8_t>(&command)) {
return;
}

switch (command) {
default:
case NO_COMMAND: {
WARN("Bridge client: bad command %d detected, closing", command);
ready = false;
} break;

case QUIT_COMMAND: {
ready = false;
} break;

case PORT_SET_COMMAND: {
uint8_t port = -1;
recv<uint8_t>(&port);
setPort(port);
} break;

case MIDI_MESSAGE_COMMAND: {
midi::Message message;
if (!recv(&message.bytes, 3)) {
return;
}
processMidi(message);
} break;

case AUDIO_SAMPLE_RATE_SET_COMMAND: {
uint32_t sampleRate = 0;
recv<uint32_t>(&sampleRate);
setSampleRate(sampleRate);
} break;

case AUDIO_PROCESS_COMMAND: {
uint32_t frames = 0;
recv<uint32_t>(&frames);
if (frames == 0 || frames > (1 << 16)) {
ready = false;
return;
}

float input[BRIDGE_INPUTS * frames];
if (!recv(&input, BRIDGE_INPUTS * frames * sizeof(float))) {
DEBUG("Failed to receive");
return;
}

float output[BRIDGE_OUTPUTS * frames];
std::memset(&output, 0, sizeof(output));
processStream(input, output, frames);
if (!send(&output, BRIDGE_OUTPUTS * frames * sizeof(float))) {
DEBUG("Failed to send");
return;
}
// flush();
} break;
}
}

void setPort(int port) {
// Unbind from existing port
if (0 <= this->port && connections[this->port] == this) {
connections[this->port] = NULL;
}

// Bind to new port
if ((0 <= port && port < BRIDGE_NUM_PORTS) && !connections[port]) {
this->port = port;
connections[this->port] = this;
refreshAudio();
}
else {
this->port = -1;
}
}

void processMidi(midi::Message message) {
if (!(0 <= port && port < BRIDGE_NUM_PORTS))
return;
if (!driver)
return;
driver->devices[port].onMessage(message);
}

void setSampleRate(int sampleRate) {
this->sampleRate = sampleRate;
refreshAudio();
}

void processStream(const float* input, float* output, int frames) {
if (!(0 <= port && port < BRIDGE_NUM_PORTS))
return;
if (!audioListeners[port])
return;
audioListeners[port]->setBlockSize(frames);
audioListeners[port]->processStream(input, output, frames);
}

void refreshAudio() {
if (!(0 <= port && port < BRIDGE_NUM_PORTS))
return;
if (connections[port] != this)
return;
if (!audioListeners[port])
return;
audioListeners[port]->setSampleRate(sampleRate);
}
};


static void clientRun(int client) {
DEFER({
#if defined ARCH_WIN
if (shutdown(client, SD_SEND)) {
WARN("Bridge client shutdown() failed");
}
if (closesocket(client)) {
WARN("Bridge client closesocket() failed");
}
#else
if (close(client)) {
WARN("Bridge client close() failed");
}
#endif
});

#if defined ARCH_MAC
// Avoid SIGPIPE
int flag = 1;
if (setsockopt(client, SOL_SOCKET, SO_NOSIGPIPE, &flag, sizeof(int))) {
WARN("Bridge client setsockopt() failed");
return;
}
#endif

// Disable non-blocking
#if defined ARCH_WIN
unsigned long blockingMode = 0;
if (ioctlsocket(client, FIONBIO, &blockingMode)) {
WARN("Bridge client ioctlsocket() failed");
return;
}
#else
if (fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) & ~O_NONBLOCK)) {
WARN("Bridge client fcntl() failed");
return;
}
#endif

BridgeClientConnection connection;
connection.client = client;
connection.run();
}


static void serverConnect() {
// Initialize sockets
#if defined ARCH_WIN
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
WARN("Bridge server WSAStartup() failed");
return;
}
DEFER({
WSACleanup();
});
#endif

// Get address
struct sockaddr_in addr;
std::memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(BRIDGE_PORT);
#if defined ARCH_WIN
addr.sin_addr.s_addr = inet_addr(BRIDGE_HOST);
#else
inet_pton(AF_INET, BRIDGE_HOST, &addr.sin_addr);
#endif

// Open socket
int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server < 0) {
WARN("Bridge server socket() failed");
return;
}
DEFER({
if (close(server)) {
WARN("Bridge server close() failed");
return;
}
INFO("Bridge server closed");
});

#if defined ARCH_MAC || defined ARCH_LIN
int reuseAddrFlag = 1;
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &reuseAddrFlag, sizeof(reuseAddrFlag));
#endif

// Bind socket to address
if (bind(server, (struct sockaddr*) &addr, sizeof(addr))) {
WARN("Bridge server bind() failed");
return;
}

// Listen for clients
if (listen(server, 20)) {
WARN("Bridge server listen() failed");
return;
}
INFO("Bridge server started");

// Enable non-blocking
#if defined ARCH_WIN
unsigned long blockingMode = 1;
if (ioctlsocket(server, FIONBIO, &blockingMode)) {
WARN("Bridge server ioctlsocket() failed");
return;
}
#else
int flags = fcntl(server, F_GETFL, 0);
fcntl(server, F_SETFL, flags | O_NONBLOCK);
#endif

// Accept clients
while (serverRunning) {
int client = accept(server, NULL, NULL);
if (client < 0) {
// Wait a bit before attempting to accept another client
std::this_thread::sleep_for(std::chrono::duration<double>(0.1));
continue;
}

// Launch client thread
std::thread clientThread(clientRun, client);
clientThread.detach();
}
}

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

driver = new BridgeMidiDriver;
midi::addDriver(BRIDGE_DRIVER, driver);
}

void bridgeDestroy() {
serverRunning = false;
serverThread.join();
}

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
if (audioListeners[port])
return;
audioListeners[port] = audio;
if (connections[port])
connections[port]->refreshAudio();
}

void bridgeAudioUnsubscribe(int port, audio::Port* audio) {
if (!(0 <= port && port < BRIDGE_NUM_PORTS))
return;
if (audioListeners[port] != audio)
return;
audioListeners[port] = NULL;
}


} // namespace rack

+ 0
- 3
src/main.cpp View File

@@ -5,7 +5,6 @@
#include <rtmidi.hpp>
#include <keyboard.hpp>
#include <gamepad.hpp>
#include <bridge.hpp>
#include <settings.hpp>
#include <engine/Engine.hpp>
#include <app/common.hpp>
@@ -158,7 +157,6 @@ int main(int argc, char* argv[]) {
network::init();
midi::init();
rtmidiInit();
bridgeInit();
keyboard::init();
gamepad::init();
plugin::init();
@@ -216,7 +214,6 @@ int main(int argc, char* argv[]) {
ui::destroy();
}
plugin::destroy();
bridgeDestroy();
midi::destroy();
INFO("Destroying logger");
logger::destroy();


Loading…
Cancel
Save