Browse Source

Add automatic audio activation/deactivation when device pauses for >200ms

tags/v0.6.0
Andrew Belt 7 years ago
parent
commit
5c8cadbbf9
4 changed files with 37 additions and 34 deletions
  1. +0
    -4
      include/bridgeprotocol.hpp
  2. +36
    -11
      src/Core/AudioInterface.cpp
  3. +1
    -1
      src/audio.cpp
  4. +0
    -18
      src/bridge.cpp

+ 0
- 4
include/bridgeprotocol.hpp View File

@@ -50,10 +50,6 @@ enum BridgeCommand {
- float output[BRIDGE_OUTPUTS * frames] - float output[BRIDGE_OUTPUTS * frames]
*/ */
AUDIO_PROCESS_COMMAND, AUDIO_PROCESS_COMMAND,
/** Resumes the audio buffer, forcing Rack to wait on an audio buffer */
AUDIO_ACTIVATE,
/** Pauses the audio buffer, allowing Rack to not wait on an audio buffer */
AUDIO_DEACTIVATE,
NUM_COMMANDS NUM_COMMANDS
}; };




+ 36
- 11
src/Core/AudioInterface.cpp View File

@@ -31,6 +31,7 @@ struct AudioInterfaceIO : AudioIO {
DoubleRingBuffer<Frame<INPUTS>, (1<<15)> inputBuffer; DoubleRingBuffer<Frame<INPUTS>, (1<<15)> inputBuffer;
// Audio thread consumes, engine thread produces // Audio thread consumes, engine thread produces
DoubleRingBuffer<Frame<OUTPUTS>, (1<<15)> outputBuffer; DoubleRingBuffer<Frame<OUTPUTS>, (1<<15)> outputBuffer;
bool active = false;


~AudioInterfaceIO() { ~AudioInterfaceIO() {
// Close stream here before destructing AudioInterfaceIO, so the mutexes are still valid when waiting to close. // Close stream here before destructing AudioInterfaceIO, so the mutexes are still valid when waiting to close.
@@ -38,6 +39,13 @@ struct AudioInterfaceIO : AudioIO {
} }


void processStream(const float *input, float *output, int frames) override { void processStream(const float *input, float *output, int frames) override {
// Reactivate idle stream
if (!active) {
active = true;
inputBuffer.clear();
outputBuffer.clear();
}

if (numInputs > 0) { if (numInputs > 0) {
// TODO Do we need to wait on the input to be consumed here? Experimentally, it works fine if we don't. // TODO Do we need to wait on the input to be consumed here? Experimentally, it works fine if we don't.
for (int i = 0; i < frames; i++) { for (int i = 0; i < frames; i++) {
@@ -144,35 +152,50 @@ struct AudioInterface : Module {




void AudioInterface::step() { void AudioInterface::step() {
Frame<INPUTS> inputFrame;
memset(&inputFrame, 0, sizeof(inputFrame));

// Update sample rate if changed by audio driver // Update sample rate if changed by audio driver
if (audioIO.sampleRate != lastSampleRate) { if (audioIO.sampleRate != lastSampleRate) {
onSampleRateChange(); onSampleRateChange();
lastSampleRate = audioIO.sampleRate; lastSampleRate = audioIO.sampleRate;
} }


if (audioIO.numInputs > 0) {
// Convert inputs if needed
if (inputBuffer.empty()) {
// Inputs: audio engine -> rack engine
if (audioIO.active && audioIO.numInputs > 0) {
// Wait until inputs are present
// Give up after a timeout in case the audio device is being unresponsive.
std::unique_lock<std::mutex> lock(audioIO.engineMutex);
auto cond = [&] {
return (!audioIO.inputBuffer.empty());
};
auto timeout = std::chrono::milliseconds(200);
if (audioIO.engineCv.wait_for(lock, timeout, cond)) {
// Convert inputs
int inLen = audioIO.inputBuffer.size(); int inLen = audioIO.inputBuffer.size();
int outLen = inputBuffer.capacity(); int outLen = inputBuffer.capacity();
inputSrc.process(audioIO.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen); inputSrc.process(audioIO.inputBuffer.startData(), &inLen, inputBuffer.endData(), &outLen);
audioIO.inputBuffer.startIncr(inLen); audioIO.inputBuffer.startIncr(inLen);
inputBuffer.endIncr(outLen); inputBuffer.endIncr(outLen);
} }
else {
// Give up on pulling input
audioIO.active = false;
debug("Audio Interface underflow");
}
} }


// Take input from buffer // Take input from buffer
Frame<INPUTS> inputFrame;
if (!inputBuffer.empty()) { if (!inputBuffer.empty()) {
inputFrame = inputBuffer.shift(); inputFrame = inputBuffer.shift();
} }
else {
memset(&inputFrame, 0, sizeof(inputFrame));
}
for (int i = 0; i < INPUTS; i++) { for (int i = 0; i < INPUTS; i++) {
outputs[AUDIO_OUTPUT + i].value = 10.f * inputFrame.samples[i]; outputs[AUDIO_OUTPUT + i].value = 10.f * inputFrame.samples[i];
} }


if (audioIO.numOutputs > 0) {
// Outputs: rack engine -> audio engine
if (audioIO.active && audioIO.numOutputs > 0) {
// Get and push output SRC frame // Get and push output SRC frame
if (!outputBuffer.full()) { if (!outputBuffer.full()) {
Frame<OUTPUTS> outputFrame; Frame<OUTPUTS> outputFrame;
@@ -183,13 +206,13 @@ void AudioInterface::step() {
} }


if (outputBuffer.full()) { if (outputBuffer.full()) {
// Wait until outputs are needed.
// Wait until enough outputs are consumed
// Give up after a timeout in case the audio device is being unresponsive. // Give up after a timeout in case the audio device is being unresponsive.
std::unique_lock<std::mutex> lock(audioIO.engineMutex); std::unique_lock<std::mutex> lock(audioIO.engineMutex);
auto cond = [&] { auto cond = [&] {
return (audioIO.outputBuffer.size() < (size_t) audioIO.blockSize); return (audioIO.outputBuffer.size() < (size_t) audioIO.blockSize);
}; };
auto timeout = std::chrono::milliseconds(100);
auto timeout = std::chrono::milliseconds(200);
if (audioIO.engineCv.wait_for(lock, timeout, cond)) { if (audioIO.engineCv.wait_for(lock, timeout, cond)) {
// Push converted output // Push converted output
int inLen = outputBuffer.size(); int inLen = outputBuffer.size();
@@ -200,6 +223,8 @@ void AudioInterface::step() {
} }
else { else {
// Give up on pushing output // Give up on pushing output
audioIO.active = false;
outputBuffer.clear();
debug("Audio Interface underflow"); debug("Audio Interface underflow");
} }
} }
@@ -210,9 +235,9 @@ void AudioInterface::step() {


// Turn on light if at least one port is enabled in the nearby pair // Turn on light if at least one port is enabled in the nearby pair
for (int i = 0; i < INPUTS / 2; i++) for (int i = 0; i < INPUTS / 2; i++)
lights[INPUT_LIGHT + i].value = (audioIO.numOutputs >= 2*i+1);
lights[INPUT_LIGHT + i].value = (audioIO.active && audioIO.numOutputs >= 2*i+1);
for (int i = 0; i < OUTPUTS / 2; i++) for (int i = 0; i < OUTPUTS / 2; i++)
lights[OUTPUT_LIGHT + i].value = (audioIO.numInputs >= 2*i+1);
lights[OUTPUT_LIGHT + i].value = (audioIO.active && audioIO.numInputs >= 2*i+1);
} }






+ 1
- 1
src/audio.cpp View File

@@ -279,7 +279,7 @@ void AudioIO::openStream() {
onOpenStream(); onOpenStream();
} }
else if (driver == BRIDGE_DRIVER) { else if (driver == BRIDGE_DRIVER) {
setChannels(0, 0);
setChannels(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
bridgeAudioSubscribe(device, this); bridgeAudioSubscribe(device, this);
} }
} }


+ 0
- 18
src/bridge.cpp View File

@@ -34,7 +34,6 @@ struct BridgeClientConnection {


int port = -1; int port = -1;
int sampleRate = 0; int sampleRate = 0;
bool audioActive = false;


~BridgeClientConnection() { ~BridgeClientConnection() {
setPort(-1); setPort(-1);
@@ -177,24 +176,12 @@ struct BridgeClientConnection {
send(&output, BRIDGE_OUTPUTS * frames * sizeof(float)); send(&output, BRIDGE_OUTPUTS * frames * sizeof(float));
// flush(); // flush();
} break; } break;

case AUDIO_ACTIVATE: {
audioActive = true;
refreshAudio();
} break;

case AUDIO_DEACTIVATE: {
audioActive = false;
refreshAudio();
} break;
} }
} }


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


@@ -238,10 +225,6 @@ struct BridgeClientConnection {
return; return;
if (!audioListeners[port]) if (!audioListeners[port])
return; return;
if (audioActive)
audioListeners[port]->setChannels(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
else
audioListeners[port]->setChannels(0, 0);
audioListeners[port]->setSampleRate(sampleRate); audioListeners[port]->setSampleRate(sampleRate);
} }
}; };
@@ -405,7 +388,6 @@ void bridgeAudioUnsubscribe(int port, AudioIO *audio) {
if (audioListeners[port] != audio) if (audioListeners[port] != audio)
return; return;
audioListeners[port] = NULL; audioListeners[port] = NULL;
audio->setChannels(0, 0);
} }






Loading…
Cancel
Save