Browse Source

Audio Interface: made buffers lock-free, removed mutexes from openStream() and closeStream(), added timeouts for spin locks

tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
4f703e3944
1 changed files with 31 additions and 34 deletions
  1. +31
    -34
      src/core/AudioInterface.cpp

+ 31
- 34
src/core/AudioInterface.cpp View File

@@ -36,10 +36,6 @@ struct AudioInterface : Module {
int blockSize = 256;
int numOutputs = 0;
int numInputs = 0;
bool streamRunning = false;

// Used because the GUI thread and Rack thread can both interact with this class
std::timed_mutex bufferMutex;

SampleRateConverter<8> inputSrc;
SampleRateConverter<8> outputSrc;
@@ -118,19 +114,24 @@ struct AudioInterface : Module {
void AudioInterface::step() {
// 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) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
const float maxTime = 10e-3;
const float spinTime = 100e-6;
for (float time = 0.0; time < maxTime; time += spinTime) {
if (inputSrcBuffer.size() < blockSize)
break;
std::this_thread::sleep_for(std::chrono::duration<float>(spinTime));
}
}
else if (numInputs > 0) {
while (outputBuffer.empty() && streamRunning) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
const float maxTime = 10e-3;
const float spinTime = 100e-6;
for (float time = 0.0; time < maxTime; time += spinTime) {
if (!outputBuffer.empty())
break;
std::this_thread::sleep_for(std::chrono::duration<float>(spinTime));
}
}

if (!bufferMutex.try_lock_for(std::chrono::duration<float>(10e-3)))
return;

// Get input and pass it through the sample rate converter
if (numOutputs > 0) {
if (!inputBuffer.full()) {
@@ -160,26 +161,25 @@ void AudioInterface::step() {
outputs[AUDIO1_OUTPUT + i].value = 10.0 * f.samples[i];
}
}

bufferMutex.unlock();
}

void AudioInterface::stepStream(const float *input, float *output, int numFrames) {
if (gPaused) {
memset(output, 0, sizeof(float) * numOutputs * numFrames);
return;
}
// if (gPaused) {
// memset(output, 0, sizeof(float) * numOutputs * numFrames);
// return;
// }

if (numOutputs > 0) {
// Wait for enough input before proceeding
while (inputSrcBuffer.size() < numFrames && streamRunning) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
const float maxTime = 10e-3;
const float spinTime = 100e-6;
for (float time = 0.0; time < maxTime; time += spinTime) {
if (inputSrcBuffer.size() >= numFrames)
break;
std::this_thread::sleep_for(std::chrono::duration<float>(spinTime));
}
}

if (!bufferMutex.try_lock_for(std::chrono::duration<float>(10e-3)))
return;

// input stream -> output buffer
if (numInputs > 0) {
Frame<8> inputFrames[numFrames];
@@ -200,15 +200,18 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames
// input buffer -> output stream
if (numOutputs > 0) {
for (int i = 0; i < numFrames; i++) {
if (inputSrcBuffer.empty())
break;
Frame<8> f = inputSrcBuffer.shift();
Frame<8> f;
if (inputSrcBuffer.empty()) {
memset(&f, 0, sizeof(f));
}
else {
f = inputSrcBuffer.shift();
}
for (int c = 0; c < numOutputs; c++) {
output[i*numOutputs + c] = (c < 8) ? clampf(f.samples[c], -1.0, 1.0) : 0.0;
output[i*numOutputs + c] = clampf(f.samples[c], -1.0, 1.0);
}
}
}
bufferMutex.unlock();
}

int AudioInterface::getDeviceCount() {
@@ -238,7 +241,6 @@ static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrame

void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
closeDevice();
std::lock_guard<std::timed_mutex> lock(bufferMutex);

this->sampleRate = sampleRate;
this->blockSize = blockSize;
@@ -266,7 +268,7 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
inParameters.nChannels = numInputs;

RtAudio::StreamOptions options;
// options.flags |= RTAUDIO_SCHEDULE_REALTIME;
options.flags |= RTAUDIO_SCHEDULE_REALTIME;

try {
// Don't use stream parameters if 0 input or output channels
@@ -281,8 +283,6 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
return;
}

streamRunning = true;

try {
debug("Starting audio stream %d", deviceId);
stream.startStream();
@@ -298,10 +298,7 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
}

void AudioInterface::closeDevice() {
std::lock_guard<std::timed_mutex> lock(bufferMutex);

if (stream.isStreamOpen()) {
streamRunning = false;
try {
debug("Aborting audio stream %d", deviceId);
stream.abortStream();


Loading…
Cancel
Save