mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 21:42:31 +02:00
In AudioClient, replace all SOXR with AudioSRC. Used for input-to-network, network-to-output, and loopback resampling.
This commit is contained in:
parent
4b9c2ed6b6
commit
c4bc5233b1
2 changed files with 39 additions and 104 deletions
|
@ -47,8 +47,6 @@ extern "C" {
|
|||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <soxr.h>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <PositionalAudioStream.h>
|
||||
|
@ -189,18 +187,6 @@ QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& de
|
|||
return result;
|
||||
}
|
||||
|
||||
soxr_datatype_t soxrDataTypeFromQAudioFormat(const QAudioFormat& audioFormat) {
|
||||
if (audioFormat.sampleType() == QAudioFormat::Float) {
|
||||
return SOXR_FLOAT32_I;
|
||||
} else {
|
||||
if (audioFormat.sampleSize() == 16) {
|
||||
return SOXR_INT16_I;
|
||||
} else {
|
||||
return SOXR_INT32_I;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int numDestinationSamplesRequired(const QAudioFormat& sourceFormat, const QAudioFormat& destinationFormat,
|
||||
int numSourceSamples) {
|
||||
float ratio = (float) destinationFormat.channelCount() / sourceFormat.channelCount();
|
||||
|
@ -350,7 +336,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
|||
// use 22050, resample but closer to 24
|
||||
adjustedAudioFormat.setSampleRate(HALF_FORTY_FOUR);
|
||||
} else if (audioDevice.supportedSampleRates().contains(FORTY_FOUR)) {
|
||||
// use 48000, libsoxr will resample
|
||||
// use 48000, resample
|
||||
adjustedAudioFormat.setSampleRate(FORTY_FOUR);
|
||||
}
|
||||
#endif
|
||||
|
@ -391,10 +377,10 @@ bool sampleChannelConversion(const int16_t* sourceSamples, int16_t* destinationS
|
|||
return false;
|
||||
}
|
||||
|
||||
soxr_error_t possibleResampling(soxr_t resampler,
|
||||
const int16_t* sourceSamples, int16_t* destinationSamples,
|
||||
unsigned int numSourceSamples, unsigned int numDestinationSamples,
|
||||
const QAudioFormat& sourceAudioFormat, const QAudioFormat& destinationAudioFormat) {
|
||||
void possibleResampling(AudioSRC* resampler,
|
||||
const int16_t* sourceSamples, int16_t* destinationSamples,
|
||||
unsigned int numSourceSamples, unsigned int numDestinationSamples,
|
||||
const QAudioFormat& sourceAudioFormat, const QAudioFormat& destinationAudioFormat) {
|
||||
|
||||
if (numSourceSamples > 0) {
|
||||
if (!resampler) {
|
||||
|
@ -403,32 +389,19 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
|||
// no conversion, we can copy the samples directly across
|
||||
memcpy(destinationSamples, sourceSamples, numSourceSamples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
soxr_error_t resampleError = 0;
|
||||
|
||||
if (sourceAudioFormat.channelCount() != destinationAudioFormat.channelCount()) {
|
||||
float channelCountRatio = (float) destinationAudioFormat.channelCount() / sourceAudioFormat.channelCount();
|
||||
float channelCountRatio = (float)destinationAudioFormat.channelCount() / sourceAudioFormat.channelCount();
|
||||
|
||||
int numChannelCoversionSamples = (int) (numSourceSamples * channelCountRatio);
|
||||
int numChannelCoversionSamples = (int)(numSourceSamples * channelCountRatio);
|
||||
int16_t* channelConversionSamples = new int16_t[numChannelCoversionSamples];
|
||||
|
||||
sampleChannelConversion(sourceSamples, channelConversionSamples,
|
||||
numSourceSamples,
|
||||
sourceAudioFormat, destinationAudioFormat);
|
||||
|
||||
size_t numDestinationSamplesActual = 0;
|
||||
resampleError = soxr_process(resampler,
|
||||
channelConversionSamples, numChannelCoversionSamples, NULL,
|
||||
destinationSamples, numDestinationSamples, &numDestinationSamplesActual);
|
||||
|
||||
// return silence instead of playing garbage samples
|
||||
if (numDestinationSamplesActual < numDestinationSamples) {
|
||||
unsigned int nBytes = (numDestinationSamples - numDestinationSamplesActual) * destinationAudioFormat.channelCount() * sizeof(int16_t);
|
||||
memset(&destinationSamples[numDestinationSamplesActual * destinationAudioFormat.channelCount()], 0, nBytes);
|
||||
qCDebug(audioclient) << "SOXR: padded with" << nBytes << "bytes of silence";
|
||||
}
|
||||
resampler->render(channelConversionSamples, destinationSamples, numChannelCoversionSamples);
|
||||
|
||||
delete[] channelConversionSamples;
|
||||
} else {
|
||||
|
@ -441,56 +414,12 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
|||
numAdjustedDestinationSamples /= 2;
|
||||
}
|
||||
|
||||
size_t numAdjustedDestinationSamplesActual = 0;
|
||||
resampleError = soxr_process(resampler,
|
||||
sourceSamples, numAdjustedSourceSamples, NULL,
|
||||
destinationSamples, numAdjustedDestinationSamples, &numAdjustedDestinationSamplesActual);
|
||||
|
||||
// return silence instead of playing garbage samples
|
||||
if (numAdjustedDestinationSamplesActual < numAdjustedDestinationSamples) {
|
||||
unsigned int nBytes = (numAdjustedDestinationSamples - numAdjustedDestinationSamplesActual) * destinationAudioFormat.channelCount() * sizeof(int16_t);
|
||||
memset(&destinationSamples[numAdjustedDestinationSamplesActual * destinationAudioFormat.channelCount()], 0, nBytes);
|
||||
qCDebug(audioclient) << "SOXR: padded with" << nBytes << "bytes of silence";
|
||||
}
|
||||
resampler->render(sourceSamples, destinationSamples, numAdjustedSourceSamples);
|
||||
}
|
||||
|
||||
return resampleError;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
soxr_t soxrResamplerFromInputFormatToOutputFormat(const QAudioFormat& sourceAudioFormat,
|
||||
const QAudioFormat& destinationAudioFormat) {
|
||||
soxr_error_t soxrError;
|
||||
|
||||
// setup soxr_io_spec_t for input and output
|
||||
soxr_io_spec_t inputToNetworkSpec = soxr_io_spec(soxrDataTypeFromQAudioFormat(sourceAudioFormat),
|
||||
soxrDataTypeFromQAudioFormat(destinationAudioFormat));
|
||||
|
||||
// setup soxr_quality_spec_t for quality options
|
||||
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
|
||||
|
||||
int channelCount = (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2)
|
||||
? 2 : 1;
|
||||
|
||||
soxr_t newResampler = soxr_create(sourceAudioFormat.sampleRate(),
|
||||
destinationAudioFormat.sampleRate(),
|
||||
channelCount,
|
||||
&soxrError, &inputToNetworkSpec, &qualitySpec, 0);
|
||||
|
||||
if (soxrError) {
|
||||
qCDebug(audioclient) << "There was an error setting up the soxr resampler -" << "soxr error code was " << soxrError;
|
||||
|
||||
soxr_delete(newResampler);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newResampler;
|
||||
}
|
||||
|
||||
void AudioClient::start() {
|
||||
|
||||
// set up the desired audio format
|
||||
|
@ -546,7 +475,7 @@ void AudioClient::stop() {
|
|||
switchOutputToAudioDevice(QAudioDeviceInfo());
|
||||
|
||||
if (_loopbackResampler) {
|
||||
soxr_delete(_loopbackResampler);
|
||||
delete _loopbackResampler;
|
||||
_loopbackResampler = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -767,11 +696,12 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
|||
// do we need to setup a resampler?
|
||||
if (_inputFormat.sampleRate() != _outputFormat.sampleRate() && !_loopbackResampler) {
|
||||
qCDebug(audioclient) << "Attemping to create a resampler for input format to output format for audio loopback.";
|
||||
_loopbackResampler = soxrResamplerFromInputFormatToOutputFormat(_inputFormat, _outputFormat);
|
||||
|
||||
if (!_loopbackResampler) {
|
||||
return;
|
||||
}
|
||||
assert(_inputFormat.sampleSize() == 16);
|
||||
assert(_outputFormat.sampleSize() == 16);
|
||||
int channelCount = (_inputFormat.channelCount() == 2 && _outputFormat.channelCount() == 2) ? 2 : 1;
|
||||
|
||||
_loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount);
|
||||
}
|
||||
|
||||
static QByteArray reverbAlone; // Intermediary for local reverb with no echo
|
||||
|
@ -1099,7 +1029,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
|||
|
||||
if (_inputToNetworkResampler) {
|
||||
// if we were using an input to network resampler, delete it here
|
||||
soxr_delete(_inputToNetworkResampler);
|
||||
delete _inputToNetworkResampler;
|
||||
_inputToNetworkResampler = NULL;
|
||||
}
|
||||
|
||||
|
@ -1111,15 +1041,17 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
|||
qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat;
|
||||
|
||||
// we've got the best we can get for input
|
||||
// if required, setup a soxr resampler for this input to our desired network format
|
||||
// if required, setup a resampler for this input to our desired network format
|
||||
if (_inputFormat != _desiredInputFormat
|
||||
&& _inputFormat.sampleRate() != _desiredInputFormat.sampleRate()) {
|
||||
qCDebug(audioclient) << "Attemping to create a soxr resampler for input format to network format.";
|
||||
_inputToNetworkResampler = soxrResamplerFromInputFormatToOutputFormat(_inputFormat, _desiredInputFormat);
|
||||
qCDebug(audioclient) << "Attemping to create a resampler for input format to network format.";
|
||||
|
||||
assert(_inputFormat.sampleSize() == 16);
|
||||
assert(_desiredInputFormat.sampleSize() == 16);
|
||||
int channelCount = (_inputFormat.channelCount() == 2 && _desiredInputFormat.channelCount() == 2) ? 2 : 1;
|
||||
|
||||
_inputToNetworkResampler = new AudioSRC(_inputFormat.sampleRate(), _desiredInputFormat.sampleRate(), channelCount);
|
||||
|
||||
if (!_inputToNetworkResampler) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qCDebug(audioclient) << "No resampling required for audio input to match desired network format.";
|
||||
}
|
||||
|
@ -1194,13 +1126,13 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
|||
|
||||
if (_networkToOutputResampler) {
|
||||
// if we were using an input to network resampler, delete it here
|
||||
soxr_delete(_networkToOutputResampler);
|
||||
delete _networkToOutputResampler;
|
||||
_networkToOutputResampler = NULL;
|
||||
}
|
||||
|
||||
if (_loopbackResampler) {
|
||||
// if we were using an input to output resample, delete it here
|
||||
soxr_delete(_loopbackResampler);
|
||||
delete _loopbackResampler;
|
||||
_loopbackResampler = NULL;
|
||||
}
|
||||
|
||||
|
@ -1212,15 +1144,17 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
|||
qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat;
|
||||
|
||||
// we've got the best we can get for input
|
||||
// if required, setup a soxr resampler for this input to our desired network format
|
||||
// if required, setup a resampler for this input to our desired network format
|
||||
if (_desiredOutputFormat != _outputFormat
|
||||
&& _desiredOutputFormat.sampleRate() != _outputFormat.sampleRate()) {
|
||||
qCDebug(audioclient) << "Attemping to create a resampler for network format to output format.";
|
||||
_networkToOutputResampler = soxrResamplerFromInputFormatToOutputFormat(_desiredOutputFormat, _outputFormat);
|
||||
|
||||
if (!_networkToOutputResampler) {
|
||||
return false;
|
||||
}
|
||||
assert(_desiredOutputFormat.sampleSize() == 16);
|
||||
assert(_outputFormat.sampleSize() == 16);
|
||||
int channelCount = (_desiredOutputFormat.channelCount() == 2 && _outputFormat.channelCount() == 2) ? 2 : 1;
|
||||
|
||||
_networkToOutputResampler = new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount);
|
||||
|
||||
} else {
|
||||
qCDebug(audioclient) << "No resampling required for network output to match actual output format.";
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "AudioIOStats.h"
|
||||
#include "AudioNoiseGate.h"
|
||||
#include "AudioSRC.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( push )
|
||||
|
@ -72,7 +73,7 @@ static const quint64 DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_PERIOD = 10 * 1000; /
|
|||
class QAudioInput;
|
||||
class QAudioOutput;
|
||||
class QIODevice;
|
||||
struct soxr;
|
||||
|
||||
typedef struct ty_gverb ty_gverb;
|
||||
|
||||
typedef glm::vec3 (*AudioPositionGetter)();
|
||||
|
@ -262,10 +263,10 @@ private:
|
|||
AudioEffectOptions* _reverbOptions;
|
||||
ty_gverb* _gverb;
|
||||
|
||||
// possible soxr streams needed for resample
|
||||
soxr* _inputToNetworkResampler;
|
||||
soxr* _networkToOutputResampler;
|
||||
soxr* _loopbackResampler;
|
||||
// possible streams needed for resample
|
||||
AudioSRC* _inputToNetworkResampler;
|
||||
AudioSRC* _networkToOutputResampler;
|
||||
AudioSRC* _loopbackResampler;
|
||||
|
||||
// Adds Reverb
|
||||
ty_gverb* createGverbFilter();
|
||||
|
|
Loading…
Reference in a new issue