Browse Source

Fix abstractions of audio structure. Some testing.

tags/v2.0.0
Andrew Belt 5 years ago
parent
commit
e1aaa6f6a7
4 changed files with 187 additions and 126 deletions
  1. +31
    -26
      include/audio.hpp
  2. +39
    -24
      src/app/AudioWidget.cpp
  3. +70
    -64
      src/audio.cpp
  4. +47
    -12
      src/rtaudio.cpp

+ 31
- 26
include/audio.hpp View File

@@ -27,9 +27,19 @@ struct Driver {
virtual std::vector<int> getDeviceIds() {
return {};
}

/** Gets the name of a device without subscribing to it. */
virtual std::string getDeviceName(int deviceId) {
return "";
}
virtual int getDeviceNumInputs(int deviceId) {
return 0;
}
virtual int getDeviceNumOutputs(int deviceId) {
return 0;
}
std::string getDeviceDetail(int deviceId, int offset, int maxChannels);

virtual Device* subscribe(int deviceId, Port* port) {
return NULL;
}
@@ -47,7 +57,17 @@ struct Device {
void subscribe(Port* port);
void unsubscribe(Port* port);

// Called by Port.
virtual std::string getName() {
return "";
}
virtual int getNumInputs() {
return 0;
}
virtual int getNumOutputs() {
return 0;
}
std::string getDetail(int offset, int maxChannels);

virtual std::vector<int> getSampleRates() {
return {};
}
@@ -64,13 +84,6 @@ struct Device {
}
virtual void setBlockSize(int blockSize) {}

virtual int getNumInputs() {
return 0;
}
virtual int getNumOutputs() {
return 0;
}

// Called by this Device class, forwards to subscribed Ports.
void processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames);
void onOpenStream();
@@ -82,45 +95,35 @@ struct Device {
////////////////////

struct Port {
/** Not owned */
Driver* driver = NULL;
Device* device = NULL;

// Port settings
int offset = 0;
int maxChannels = 8;

// private
int driverId = -1;
int deviceId = -1;
/** Not owned */
Driver* driver = NULL;
Device* device = NULL;

Port();
virtual ~Port();

std::vector<int> getDriverIds();
Driver* getDriver() {
return driver;
}
int getDriverId() {
return driverId;
}
void setDriverId(int driverId);
std::string getDriverName(int driverId);

std::vector<int> getDeviceIds() {
if (!driver)
return {};
return driver->getDeviceIds();
Device* getDevice() {
return device;
}
int getDeviceId() {
return deviceId;
}
void setDeviceId(int deviceId);

std::string getDeviceName(int deviceId) {
if (!driver)
return "";
return driver->getDeviceName(deviceId);
}
std::string getDeviceDetail(int deviceId, int offset);

std::vector<int> getSampleRates() {
if (!device)
return {};
@@ -178,6 +181,8 @@ void init();
void destroy();
/** Registers a new audio driver. Takes pointer ownership. */
void addDriver(int driverId, Driver* driver);
std::vector<int> getDriverIds();
Driver* getDriver(int driverId);


} // namespace audio


+ 39
- 24
src/app/AudioWidget.cpp View File

@@ -22,25 +22,27 @@ struct AudioDriverChoice : LedDisplayChoice {

ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("Audio driver"));
for (int driverId : port->getDriverIds()) {
for (int driverId : audio::getDriverIds()) {
AudioDriverItem* item = new AudioDriverItem;
item->port = port;
item->driverId = driverId;
item->text = port->getDriverName(driverId);
item->text = audio::getDriver(driverId)->getName();
item->rightText = CHECKMARK(item->driverId == port->getDriverId());
menu->addChild(item);
}
}
void step() override {
text = (box.size.x >= 200.0) ? "Driver: " : "";
std::string driverName = port ? port->getDriverName(port->getDriverId()) : "";
text = "";
if (box.size.x >= 200.0)
text += "Driver: ";
std::string driverName = (port && port->driver) ? port->getDriver()->getName() : "";
if (driverName != "") {
text += driverName;
color.a = 1.f;
color.a = 1.0;
}
else {
text += "(No driver)";
color.a = 0.5f;
color.a = 0.5;
}
}
};
@@ -60,7 +62,7 @@ struct AudioDeviceChoice : LedDisplayChoice {
audio::Port* port;

void onAction(const event::Action& e) override {
if (!port)
if (!port || !port->driver)
return;

ui::Menu* menu = createMenu();
@@ -70,12 +72,12 @@ struct AudioDeviceChoice : LedDisplayChoice {
item->port = port;
item->deviceId = -1;
item->text = "(No device)";
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId());
item->rightText = CHECKMARK(port->getDeviceId() == -1);
menu->addChild(item);
}
for (int deviceId : port->getDeviceIds()) {
int channels = std::max(port->getNumInputs(), port->getNumOutputs());
/** Prevents devices with a ridiculous number of channels from being displayed */
for (int deviceId : port->driver->getDeviceIds()) {
int channels = std::max(port->driver->getDeviceNumInputs(deviceId), port->driver->getDeviceNumOutputs(deviceId));
// Prevents devices with a ridiculous number of channels from being displayed
const int maxTotalChannels = 128;
channels = std::min(maxTotalChannels, channels);

@@ -84,22 +86,24 @@ struct AudioDeviceChoice : LedDisplayChoice {
item->port = port;
item->deviceId = deviceId;
item->offset = offset;
item->text = port->getDeviceDetail(deviceId, offset);
item->text = port->driver->getDeviceDetail(deviceId, offset, port->maxChannels);
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId() && item->offset == port->offset);
menu->addChild(item);
}
}
}
void step() override {
text = (box.size.x >= 200.0) ? "Device: " : "";
std::string detail = (port) ? port->getDeviceDetail(port->deviceId, port->offset) : "";
text = "";
if (box.size.x >= 200.0)
text += "Device: ";
std::string detail = (port && port->device) ? port->device->getDetail(port->offset, port->maxChannels) : "";
if (detail != "") {
text += detail;
color.a = (detail == "") ? 0.5f : 1.f;
color.a = 1.0;
}
else {
text += "(No device)";
color.a = 0.5f;
color.a = 0.5;
}
}
};
@@ -135,13 +139,19 @@ struct AudioSampleRateChoice : LedDisplayChoice {
}
}
void step() override {
text = (box.size.x >= 100.0) ? "Rate: " : "";
if (port) {
text += string::f("%g kHz", port->getSampleRate() / 1000.0);
text = "";
if (box.size.x >= 100.0)
text += "Rate: ";
int sampleRate = port ? port->getSampleRate() : 0;
if (sampleRate > 0) {
text += string::f("%g", sampleRate / 1000.0);
color.a = 1.0;
}
else {
text += "0 kHz";
text += "---";
color.a = 0.5;
}
text += " kHz";
}
};

@@ -177,12 +187,17 @@ struct AudioBlockSizeChoice : LedDisplayChoice {
}
}
void step() override {
text = (box.size.x >= 100.0) ? "Block size: " : "";
if (port) {
text += string::f("%d", port->getBlockSize());
text = "";
if (box.size.x >= 100.0)
text += "Block size: ";
int blockSize = port ? port->getBlockSize() : 0;
if (blockSize > 0) {
text += string::f("%d", blockSize);
color.a = 1.0;
}
else {
text += "0";
text += "---";
color.a = 0.5;
}
}
};


+ 70
- 64
src/audio.cpp View File

@@ -8,6 +8,31 @@ namespace audio {

static std::vector<std::pair<int, Driver*>> drivers;

static std::string getDetailTemplate(std::string name, int numInputs, int numOutputs, int offset, int maxChannels) {
std::string text = name;
text += " (";
if (offset < numInputs) {
text += string::f("%d-%d in", offset + 1, std::min(offset + maxChannels, numInputs));
}
if (offset < numInputs && offset < numOutputs) {
text += ", ";
}
if (offset < numOutputs) {
text += string::f("%d-%d out", offset + 1, std::min(offset + maxChannels, numOutputs));
}
text += ")";
return text;
}

////////////////////
// Driver
////////////////////

std::string Driver::getDeviceDetail(int deviceId, int offset, int maxChannels) {
if (deviceId < 0)
return "";
return getDetailTemplate(getDeviceName(deviceId), getDeviceNumInputs(deviceId), getDeviceNumOutputs(deviceId), offset, maxChannels);
}

////////////////////
// Device
@@ -23,6 +48,10 @@ void Device::unsubscribe(Port* port) {
subscribed.erase(it);
}

std::string Device::getDetail(int offset, int maxChannels) {
return getDetailTemplate(getName(), getNumInputs(), getNumOutputs(), offset, maxChannels);
}

void Device::processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames) {
for (Port* port : subscribed) {
port->processInput(input + port->offset, inputStride, frames);
@@ -59,14 +88,6 @@ Port::~Port() {
setDriverId(-1);
}

std::vector<int> Port::getDriverIds() {
std::vector<int> driverIds;
for (auto& pair : drivers) {
driverIds.push_back(pair.first);
}
return driverIds;
}

void Port::setDriverId(int driverId) {
// Unset device and driver
setDeviceId(-1);
@@ -75,32 +96,17 @@ void Port::setDriverId(int driverId) {

if (driverId == -1) {
// Set first driver as default
if (!drivers.empty()) {
driver = drivers[0].second;
this->driverId = drivers[0].first;
}
driver = drivers[0].second;
this->driverId = drivers[0].first;
}
else {
// Set driver with driverId
for (auto& pair : drivers) {
if (pair.first == driverId) {
driver = pair.second;
this->driverId = driverId;
break;
}
}
// Find driver by ID
driver = audio::getDriver(driverId);
if (driver)
this->driverId = driverId;
}
}

std::string Port::getDriverName(int driverId) {
for (auto& pair : drivers) {
if (pair.first == driverId) {
return pair.second->getName();
}
}
return "";
}

void Port::setDeviceId(int deviceId) {
// Destroy device
if (driver && this->deviceId >= 0) {
@@ -116,26 +122,6 @@ void Port::setDeviceId(int deviceId) {
}
}

std::string Port::getDeviceDetail(int deviceId, int offset) {
if (!driver || !device)
return "";
std::string text = getDeviceName(getDeviceId());
text += " (";
int numInputs = device->getNumInputs();
int numOutputs = device->getNumOutputs();
if (offset < numInputs) {
text += string::f("%d-%d in", offset + 1, std::min(offset + maxChannels, numInputs));
}
if (offset < numInputs && offset < numOutputs) {
text += ", ";
}
if (offset < numOutputs) {
text += string::f("%d-%d out", offset + 1, std::min(offset + maxChannels, numOutputs));
}
text += ")";
return text;
}

int Port::getNumInputs() {
if (!device)
return 0;
@@ -150,13 +136,15 @@ int Port::getNumOutputs() {

json_t* Port::toJson() {
json_t* rootJ = json_object();
json_object_set_new(rootJ, "driver", json_integer(getDriverId()));
std::string deviceName = getDeviceName(getDeviceId());
if (!deviceName.empty())
json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
json_object_set_new(rootJ, "sampleRate", json_integer(getSampleRate()));
json_object_set_new(rootJ, "blockSize", json_integer(getBlockSize()));
json_object_set_new(rootJ, "offset", json_integer(offset));
if (driver) {
json_object_set_new(rootJ, "driver", json_integer(getDriverId()));
std::string deviceName = driver->getDeviceName(getDeviceId());
if (!deviceName.empty())
json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
json_object_set_new(rootJ, "sampleRate", json_integer(getSampleRate()));
json_object_set_new(rootJ, "blockSize", json_integer(getBlockSize()));
json_object_set_new(rootJ, "offset", json_integer(offset));
}
return rootJ;
}

@@ -165,14 +153,16 @@ void Port::fromJson(json_t* rootJ) {
if (driverJ)
setDriverId(json_number_value(driverJ));

json_t* deviceNameJ = json_object_get(rootJ, "deviceName");
if (deviceNameJ) {
std::string deviceName = json_string_value(deviceNameJ);
// Search for device ID with equal name
for (int deviceId : getDeviceIds()) {
if (getDeviceName(deviceId) == deviceName) {
setDeviceId(deviceId);
break;
if (driver) {
json_t* deviceNameJ = json_object_get(rootJ, "deviceName");
if (deviceNameJ) {
std::string deviceName = json_string_value(deviceNameJ);
// Search for device ID with equal name
for (int deviceId : driver->getDeviceIds()) {
if (driver->getDeviceName(deviceId) == deviceName) {
setDeviceId(deviceId);
break;
}
}
}
}
@@ -210,6 +200,22 @@ void addDriver(int driverId, Driver* driver) {
drivers.push_back(std::make_pair(driverId, driver));
}

std::vector<int> getDriverIds() {
std::vector<int> driverIds;
for (auto& pair : drivers) {
driverIds.push_back(pair.first);
}
return driverIds;
}

Driver* getDriver(int driverId) {
for (auto& pair : drivers) {
if (pair.first == driverId)
return pair.second;
}
return NULL;
}


} // namespace audio
} // namespace rack

+ 47
- 12
src/rtaudio.cpp View File

@@ -125,6 +125,16 @@ struct RtAudioDevice : audio::Device {
onCloseStream();
}

std::string getName() override {
return deviceInfo.name;
}
int getNumInputs() override {
return inputParameters.nChannels;
}
int getNumOutputs() override {
return outputParameters.nChannels;
}

std::vector<int> getSampleRates() override {
std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
return sampleRates;
@@ -139,7 +149,13 @@ struct RtAudioDevice : audio::Device {
}

std::vector<int> getBlockSizes() override {
return {32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096};
std::vector<int> blockSizes;
for (int i = 5; i < 12; i++) {
blockSizes.push_back(1 << i);
blockSizes.push_back((1 << i) / 2 * 3);
}
blockSizes.push_back(1 << 12);
return blockSizes;
}
int getBlockSize() override {
return blockSize;
@@ -150,13 +166,6 @@ struct RtAudioDevice : audio::Device {
openStream();
}

int getNumInputs() override {
return inputParameters.nChannels;
}
int getNumOutputs() override {
return outputParameters.nChannels;
}

static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
RtAudioDevice* device = (RtAudioDevice*) userData;
assert(device);
@@ -204,11 +213,37 @@ struct RtAudioDriver : audio::Driver {
return "";
}

int getDeviceNumInputs(int deviceId) override {
if (deviceId >= 0) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
return deviceInfo.inputChannels;
}
return 0;
}

int getDeviceNumOutputs(int deviceId) override {
if (deviceId >= 0) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
return deviceInfo.outputChannels;
}
return 0;
}

audio::Device* subscribe(int deviceId, audio::Port* port) override {
RtAudioDevice* device = devices[deviceId];
if (!device) {
devices[deviceId] = device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
// TODO Error check
RtAudioDevice* device;
auto it = devices.find(deviceId);
if (it == devices.end()) {
try {
device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
devices[deviceId] = device;
}
catch (Exception& e) {
WARN("Could not subscribe to audio device: %s", e.what());
return NULL;
}
}
else {
device = it->second;
}

device->subscribe(port);


Loading…
Cancel
Save