Browse Source

Migrate to RtAudio from portaudio

tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
e4f18e7c0c
3 changed files with 75 additions and 97 deletions
  1. +1
    -1
      Makefile
  2. +8
    -19
      dep/Makefile
  3. +66
    -77
      src/core/AudioInterface.cpp

+ 1
- 1
Makefile View File

@@ -14,7 +14,7 @@ ifeq ($(ARCH), lin)
LDFLAGS += -rdynamic \
-lpthread -lGL -ldl \
$(shell pkg-config --libs gtk+-2.0) \
-Ldep/lib -lGLEW -lglfw -ljansson -lsamplerate -lcurl -lzip -lportaudio -lrtmidi
-Ldep/lib -lGLEW -lglfw -ljansson -lsamplerate -lcurl -lzip -lrtaudio -lrtmidi
TARGET = Rack
endif



+ 8
- 19
dep/Makefile View File

@@ -30,7 +30,7 @@ ifeq ($(ARCH),lin)
libcurl = lib/libcurl.so
libzip = lib/libzip.so
rtmidi = lib/librtmidi.so
portaudio = lib/libportaudio.so
rtaudio = lib/librtaudio.so
endif

ifeq ($(ARCH),mac)
@@ -41,7 +41,6 @@ ifeq ($(ARCH),mac)
libcurl = lib/libcurl.dylib
libzip = lib/libzip.dylib
rtmidi = lib/librtmidi.dylib
portaudio = lib/libportaudio.dylib
endif

ifeq ($(ARCH),win)
@@ -52,13 +51,12 @@ ifeq ($(ARCH),win)
libcurl = bin/libcurl-4.dll
libzip = bin/libzip-5.dll
rtmidi = bin/librtmidi-4.dll
portaudio = bin/portaudio_x64.dll
endif


.NOTPARALLEL:

all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(portaudio)
all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(rtaudio)
@echo ""
@echo "#######################################"
@echo "# Built all dependencies successfully #"
@@ -122,21 +120,12 @@ $(rtmidi):
$(MAKE) -C rtmidi-3.0.0
$(MAKE) -C rtmidi-3.0.0 install

$(portaudio):
ifeq ($(ARCH),win)
$(WGET) https://github.com/adfernandes/precompiled-portaudio-windows/raw/master/portaudio-r1891-build.zip
$(UNZIP) portaudio-r1891-build.zip
mv portaudio-r1891-build portaudio
cp portaudio/lib/x64/ReleaseMinDependency/portaudio_x64.lib "$(LOCAL)/lib"
cp portaudio/lib/x64/ReleaseMinDependency/portaudio_x64.dll "$(LOCAL)/bin"
cp portaudio/include/*.h "$(LOCAL)/include"
else
$(WGET) http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz
$(UNTAR) pa_stable_v190600_20161030.tgz
cd portaudio && ./configure --prefix="$(LOCAL)" --disable-debug --disable-dependency-tracking --enable-mac-universal=no
$(MAKE) -C portaudio
$(MAKE) -C portaudio install
endif
$(rtaudio):
$(WGET) http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-5.0.0.tar.gz
$(UNTAR) rtaudio-5.0.0.tar.gz
cd rtaudio-5.0.0 && ./configure --prefix="$(LOCAL)"
$(MAKE) -C rtaudio-5.0.0
$(MAKE) -C rtaudio-5.0.0 install

clean:
git clean -ffdxi

+ 66
- 77
src/core/AudioInterface.cpp View File

@@ -1,27 +1,18 @@
#include <assert.h>
#include <mutex>
#include <thread>
#include <portaudio.h>
#include "core.hpp"
#include "dsp/samplerate.hpp"
#include "dsp/ringbuffer.hpp"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-override"
#include <rtaudio/RtAudio.h>
#pragma GCC diagnostic pop

using namespace rack;

static bool initialized = false;

void audioInit() {
if (initialized)
return;

PaError err = Pa_Initialize();
if (err) {
warn("Failed to initialize PortAudio: %s", Pa_GetErrorText(err));
return;
}
initialized = true;
}
using namespace rack;


struct AudioInterface : Module {
@@ -37,7 +28,7 @@ struct AudioInterface : Module {
NUM_OUTPUTS = AUDIO1_OUTPUT + 8
};

PaStream *stream = NULL;
RtAudio stream;
// Stream properties
int deviceId = -1;
float sampleRate = 44100.0;
@@ -58,9 +49,7 @@ struct AudioInterface : Module {
// in device's sample rate
DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer;

AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
audioInit();
}
AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
~AudioInterface() {
closeDevice();
}
@@ -125,9 +114,6 @@ struct AudioInterface : Module {


void AudioInterface::step() {
if (!stream)
return;

// Read/write stream if we have enough input, OR the output buffer is empty if we have no input
if (numOutputs > 0) {
while (inputSrcBuffer.size() >= blockSize && streamRunning) {
@@ -215,21 +201,28 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames
}

int AudioInterface::getDeviceCount() {
return Pa_GetDeviceCount();
return stream.getDeviceCount();
}

std::string AudioInterface::getDeviceName(int deviceId) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceId);
if (!info)
if (deviceId < 0)
return "";
const PaHostApiInfo *apiInfo = Pa_GetHostApiInfo(info->hostApi);
return stringf("%s: %s (%d in, %d out)", apiInfo->name, info->name, info->maxInputChannels, info->maxOutputChannels);

try {
RtAudio::DeviceInfo deviceInfo = stream.getDeviceInfo(deviceId);
return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels);
}
catch (RtAudioError &e) {
warn("Failed to query audio device: %s", e.what());
return "";
}
}

static int paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
AudioInterface *p = (AudioInterface *) userData;
p->stepStream((const float *) inputBuffer, (float *) outputBuffer, framesPerBuffer);
return paContinue;
static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) {
AudioInterface *audioInterface = (AudioInterface *) userData;
assert(audioInterface);
audioInterface->stepStream((const float *) inputBuffer, (float *) outputBuffer, nFrames);
return 0;
}

void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
@@ -241,51 +234,52 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {

// Open new device
if (deviceId >= 0) {
PaError err;
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId);
if (!deviceInfo) {
warn("Failed to query audio device");
RtAudio::DeviceInfo deviceInfo;
try {
deviceInfo = stream.getDeviceInfo(deviceId);
}
catch (RtAudioError &e) {
warn("Failed to query audio device: %s", e.what());
return;
}

numOutputs = mini(deviceInfo->maxOutputChannels, 8);
numInputs = mini(deviceInfo->maxInputChannels, 8);

PaStreamParameters outputParameters;
outputParameters.device = deviceId;
outputParameters.channelCount = numOutputs;
outputParameters.sampleFormat = paFloat32;
outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;

PaStreamParameters inputParameters;
inputParameters.device = deviceId;
inputParameters.channelCount = numInputs;
inputParameters.sampleFormat = paFloat32;
inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;

// Don't use stream parameters if 0 input or output channels
err = Pa_OpenStream(&stream,
numInputs == 0 ? NULL : &inputParameters,
numOutputs == 0 ? NULL : &outputParameters,
sampleRate, blockSize, paNoFlag, paCallback, this);
if (err) {
warn("Failed to open audio stream: %s", Pa_GetErrorText(err));
numOutputs = mini(deviceInfo.outputChannels, 8);
numInputs = mini(deviceInfo.inputChannels, 8);

RtAudio::StreamParameters outParameters;
outParameters.deviceId = deviceId;
outParameters.nChannels = numOutputs;

RtAudio::StreamParameters inParameters;
inParameters.deviceId = deviceId;
inParameters.nChannels = numInputs;

RtAudio::StreamOptions options;
options.flags |= RTAUDIO_MINIMIZE_LATENCY;

try {
// Don't use stream parameters if 0 input or output channels
stream.openStream(
numOutputs == 0 ? NULL : &outParameters,
numInputs == 0 ? NULL : &inParameters,
RTAUDIO_FLOAT32, sampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL);
}
catch (RtAudioError &e) {
warn("Failed to open audio stream: %s", e.what());
return;
}

err = Pa_StartStream(stream);
if (err) {
warn("Failed to start audio stream: %s", Pa_GetErrorText(err));
try {
stream.startStream();
}
catch (RtAudioError &e) {
warn("Failed to start audio stream: %s", e.what());
return;
}
// This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early
streamRunning = true;

// Correct sample rate
const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream);
this->sampleRate = streamInfo->sampleRate;
this->sampleRate = stream.getStreamSampleRate();
this->deviceId = deviceId;
}
}
@@ -293,23 +287,19 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
void AudioInterface::closeDevice() {
std::lock_guard<std::mutex> lock(bufferMutex);

if (stream) {
PaError err;
if (stream.isStreamOpen()) {
streamRunning = false;
err = Pa_AbortStream(stream);
// err = Pa_StopStream(stream);
if (err) {
warn("Failed to stop audio stream: %s", Pa_GetErrorText(err));
try {
stream.abortStream();
stream.closeStream();
}

err = Pa_CloseStream(stream);
if (err) {
warn("Failed to close audio stream: %s", Pa_GetErrorText(err));
catch (RtAudioError &e) {
warn("Failed to abort stream %s", e.what());
return;
}
}

// Reset stream settings
stream = NULL;
deviceId = -1;
numOutputs = 0;
numInputs = 0;
@@ -427,7 +417,6 @@ AudioInterfaceWidget::AudioInterfaceWidget() {
AudioInterface *module = new AudioInterface();
setModule(module);
box.size = Vec(15*12, 380);

{
Panel *panel = new LightPanel();
panel->box.size = box.size;


Loading…
Cancel
Save