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