Browse Source

Allow audio interfaces with no input to be used. Fix sample rate conversion.

tags/v2.0.0
Andrew Belt 5 years ago
parent
commit
9b24182542
2 changed files with 63 additions and 37 deletions
  1. +2
    -2
      include/dsp/resampler.hpp
  2. +61
    -35
      src/core/AudioInterface.cpp

+ 2
- 2
include/dsp/resampler.hpp View File

@@ -80,8 +80,8 @@ struct SampleRateConverter {
assert(outFrames);
if (st) {
// Resample each channel at a time
spx_uint32_t inLen;
spx_uint32_t outLen;
spx_uint32_t inLen = 0;
spx_uint32_t outLen = 0;
for (int i = 0; i < channels; i++) {
inLen = *inFrames;
outLen = *outFrames;


+ 61
- 35
src/core/AudioInterface.cpp View File

@@ -31,8 +31,8 @@ struct AudioInterface : Module, audio::Port {
NUM_LIGHTS
};

dsp::DoubleRingBuffer<dsp::Frame<NUM_AUDIO_INPUTS>, 8192> inputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<NUM_AUDIO_OUTPUTS>, 8192> outputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<NUM_AUDIO_INPUTS>, 32768> inputBuffer;
dsp::DoubleRingBuffer<dsp::Frame<NUM_AUDIO_OUTPUTS>, 32768> outputBuffer;

dsp::SampleRateConverter<NUM_AUDIO_INPUTS> inputSrc;
dsp::SampleRateConverter<NUM_AUDIO_OUTPUTS> outputSrc;
@@ -53,6 +53,11 @@ struct AudioInterface : Module, audio::Port {
setDeviceId(-1, 0);
}

void onSampleRateChange(const SampleRateChangeEvent& e) override {
inputBuffer.clear();
outputBuffer.clear();
}

void process(const ProcessArgs& args) override {
// Get inputs
if (!inputBuffer.full()) {
@@ -108,52 +113,73 @@ struct AudioInterface : Module, audio::Port {
std::memset(output, 0, sizeof(float) * numOutputs * frames);

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

// audio input -> module output
dsp::Frame<NUM_AUDIO_OUTPUTS> inputAudioBuffer[frames];
std::memset(inputAudioBuffer, 0, sizeof(inputAudioBuffer));
for (int i = 0; i < frames; i++) {
for (int j = 0; j < std::min(numInputs, NUM_AUDIO_OUTPUTS); j++) {
inputAudioBuffer[i].samples[j] = input[i * numInputs + j];
int engineFrames = 0;

if (numInputs > 0) {
// audio input -> module output
dsp::Frame<NUM_AUDIO_OUTPUTS> inputAudioBuffer[frames];
std::memset(inputAudioBuffer, 0, sizeof(inputAudioBuffer));
for (int i = 0; i < frames; i++) {
for (int j = 0; j < std::min(numInputs, NUM_AUDIO_OUTPUTS); j++) {
inputAudioBuffer[i].samples[j] = input[i * numInputs + j];
}
}
int inputAudioFrames = frames;
int outputFrames = outputBuffer.capacity();
outputSrc.process(inputAudioBuffer, &inputAudioFrames, outputBuffer.endData(), &outputFrames);
outputBuffer.endIncr(outputFrames);
engineFrames = outputBuffer.size();
}
int inputAudioFrames = frames;
int outputFrames = outputBuffer.capacity();
outputSrc.process(inputAudioBuffer, &inputAudioFrames, outputBuffer.endData(), &outputFrames);
outputBuffer.endIncr(outputFrames);

// Step engine estimated number of steps
if (APP->engine->getPrimaryModule() == this) {
APP->engine->step(outputFrames);
else {
// 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);
}

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

// module input -> audio output
dsp::Frame<NUM_AUDIO_OUTPUTS> outputAudioBuffer[frames];
int inputFrames = inputBuffer.size();
int outputAudioFrames = frames;
inputSrc.process(inputBuffer.startData(), &inputFrames, outputAudioBuffer, &outputAudioFrames);
inputBuffer.startIncr(inputFrames);
for (int i = 0; i < frames; i++) {
for (int j = 0; j < std::min(numOutputs, NUM_AUDIO_INPUTS); j++) {
output[i * numOutputs + j] = outputAudioBuffer[i].samples[j];
if (numOutputs > 0) {
// module input -> audio output
dsp::Frame<NUM_AUDIO_OUTPUTS> outputAudioBuffer[frames];
int inputFrames = inputBuffer.size();
int outputAudioFrames = frames;
inputSrc.process(inputBuffer.startData(), &inputFrames, outputAudioBuffer, &outputAudioFrames);
inputBuffer.startIncr(inputFrames);
for (int i = 0; i < outputAudioFrames; i++) {
for (int j = 0; j < std::min(numOutputs, NUM_AUDIO_INPUTS); j++) {
output[i * numOutputs + j] = outputAudioBuffer[i].samples[j];
}
}
}

DEBUG("%p %d: frames %d, %d -> %d outputBuffer %d, %d -> %d inputBuffer %d",
this, APP->engine->getPrimaryModule() == this, frames,
inputAudioFrames, outputFrames, outputBuffer.size(),
inputFrames, outputAudioFrames, inputBuffer.size());
// If we're left with too many output samples, flush the buffer.
// if (inputBuffer.size() >= 2.f * ) {
// inputBuffer.clear();
// }

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

void onOpenStream() override {
inputBuffer.clear();
outputBuffer.clear();
}

void onCloseStream() override {
// Reset outputs
for (int i = 0; i < NUM_AUDIO_OUTPUTS; i++) {
outputs[AUDIO_OUTPUTS + i].setVoltage(0.f);
}
inputBuffer.clear();
outputBuffer.clear();
}

void onChannelsChange() override {


Loading…
Cancel
Save