Browse Source

Add and test secondary module audio interface flushing.

tags/v2.0.0
Andrew Belt 6 years ago
parent
commit
61f6d8164d
2 changed files with 31 additions and 17 deletions
  1. +29
    -17
      src/core/AudioInterface.cpp
  2. +2
    -0
      src/engine/Engine.cpp

+ 29
- 17
src/core/AudioInterface.cpp View File

@@ -75,6 +75,11 @@ struct AudioInterface : Module, audio::Port {
outputs[AUDIO_OUTPUTS + i].setVoltage(10.f * outputFrame.samples[i]); outputs[AUDIO_OUTPUTS + i].setVoltage(10.f * outputFrame.samples[i]);
} }
} }
else {
for (int i = 0; i < NUM_AUDIO_OUTPUTS; i++) {
outputs[AUDIO_OUTPUTS + i].setVoltage(0.f);
}
}


// 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 < NUM_AUDIO_INPUTS / 2; i++) { for (int i = 0; i < NUM_AUDIO_INPUTS / 2; i++) {
@@ -108,21 +113,30 @@ struct AudioInterface : Module, audio::Port {
if (!APP->engine->getPrimaryModule()) { if (!APP->engine->getPrimaryModule()) {
APP->engine->setPrimaryModule(this); APP->engine->setPrimaryModule(this);
} }
bool isPrimary = (APP->engine->getPrimaryModule() == this);


// Clear output in case the audio driver uses this buffer in another thread before this method returns. (Not sure if any do this in practice.) // Clear output in case the audio driver uses this buffer in another thread before this method returns. (Not sure if any do this in practice.)
std::memset(output, 0, sizeof(float) * numOutputs * frames); std::memset(output, 0, sizeof(float) * numOutputs * frames);


// Initialize sample rate converters // Initialize sample rate converters
int engineSampleRate = (int) APP->engine->getSampleRate(); int engineSampleRate = (int) APP->engine->getSampleRate();
double sampleRateRatio = (double) engineSampleRate / sampleRate;
outputSrc.setRates((int) sampleRate, engineSampleRate); outputSrc.setRates((int) sampleRate, engineSampleRate);
outputSrc.setChannels(numInputs); outputSrc.setChannels(numInputs);
inputSrc.setRates(engineSampleRate, (int) sampleRate); inputSrc.setRates(engineSampleRate, (int) sampleRate);
inputSrc.setChannels(numOutputs); inputSrc.setChannels(numOutputs);


int engineFrames = 0;
// Consider engine buffers "too full" if they contain a bit more than the audio device's number of frames, converted to engine sample rate.
int maxEngineFrames = (int) std::ceil(frames * sampleRateRatio * 1.5);
// If this is a secondary audio module and the engine output buffer is too full, flush it.
if (!isPrimary && (int) outputBuffer.size() > maxEngineFrames) {
outputBuffer.clear();
// DEBUG("%p: flushing engine output", this);
}


int requestedEngineFrames;
if (numInputs > 0) { if (numInputs > 0) {
// audio input -> module output
// audio input -> engine output
dsp::Frame<NUM_AUDIO_OUTPUTS> inputAudioBuffer[frames]; dsp::Frame<NUM_AUDIO_OUTPUTS> inputAudioBuffer[frames];
std::memset(inputAudioBuffer, 0, sizeof(inputAudioBuffer)); std::memset(inputAudioBuffer, 0, sizeof(inputAudioBuffer));
for (int i = 0; i < frames; i++) { for (int i = 0; i < frames; i++) {
@@ -135,22 +149,21 @@ struct AudioInterface : Module, audio::Port {
int outputFrames = outputBuffer.capacity(); int outputFrames = outputBuffer.capacity();
outputSrc.process(inputAudioBuffer, &inputAudioFrames, outputBuffer.endData(), &outputFrames); outputSrc.process(inputAudioBuffer, &inputAudioFrames, outputBuffer.endData(), &outputFrames);
outputBuffer.endIncr(outputFrames); outputBuffer.endIncr(outputFrames);
engineFrames = outputBuffer.size();
// Request exactly as many frames as we have.
requestedEngineFrames = outputBuffer.size();
} }
else { else {
// Upper bound on number of frames so that `outputAudioFrames >= frames` at the end of this method. // Upper bound on number of frames so that `outputAudioFrames >= frames` at the end of this method.
double ratio = (double) engineSampleRate / sampleRate;
engineFrames = std::ceil(frames * ratio - inputBuffer.size());
engineFrames = std::max(engineFrames, 0);
requestedEngineFrames = (int) std::ceil(frames * sampleRateRatio) - inputBuffer.size();
} }


// Step engine to consume the entire output buffer
if (APP->engine->getPrimaryModule() == this && engineFrames > 0) {
APP->engine->step(engineFrames);
// Step engine
if (isPrimary && requestedEngineFrames > 0) {
APP->engine->step(requestedEngineFrames);
} }


if (numOutputs > 0) { if (numOutputs > 0) {
// module input -> audio output
// engine input -> audio output
dsp::Frame<NUM_AUDIO_OUTPUTS> outputAudioBuffer[frames]; dsp::Frame<NUM_AUDIO_OUTPUTS> outputAudioBuffer[frames];
int inputFrames = inputBuffer.size(); int inputFrames = inputBuffer.size();
int outputAudioFrames = frames; int outputAudioFrames = frames;
@@ -165,14 +178,13 @@ struct AudioInterface : Module, audio::Port {
} }
} }


// If we're left with too many output samples, flush the buffer.
// if (inputBuffer.size() >= 2.f * ) {
// inputBuffer.clear();
// }
// If this is a secondary audio module and the engine input buffer is too full, flush it.
if (!isPrimary && (int) inputBuffer.size() > maxEngineFrames) {
inputBuffer.clear();
// DEBUG("%p: flushing engine input", this);
}


// DEBUG("%p %d: frames %d\toutputBuffer %d inputBuffer %d engineFrames %d\t",
// this, APP->engine->getPrimaryModule() == this, frames,
// outputBuffer.size(), inputBuffer.size(), engineFrames);
// DEBUG("%p %s:\tframes %d requestedEngineFrames %d\toutputBuffer %d inputBuffer %d\t", this, isPrimary ? "primary" : "secondary", frames, requestedEngineFrames, outputBuffer.size(), inputBuffer.size());
} }


void onOpenStream() override { void onOpenStream() override {


+ 2
- 0
src/engine/Engine.cpp View File

@@ -422,6 +422,7 @@ void Engine::clear() {




void Engine::step(int frames) { void Engine::step(int frames) {
// Configure thread
initMXCSR(); initMXCSR();
random::init(); random::init();


@@ -993,6 +994,7 @@ void Engine::fromJson(json_t* rootJ) {




void EngineWorker::run() { void EngineWorker::run() {
// Configure thread
system::setThreadName(string::f("Worker %d", id)); system::setThreadName(string::f("Worker %d", id));
initMXCSR(); initMXCSR();
random::init(); random::init();


Loading…
Cancel
Save