From 784b23d05c2210d645d500adb766e9e011e6415a Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Jan 2017 10:33:04 -0800 Subject: [PATCH] Partial support for floating-point audio output --- libraries/audio-client/src/AudioClient.cpp | 43 +++++++++++++--- libraries/audio/src/AudioRingBuffer.h | 59 ++++++++++++++-------- 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 1e3dc11338..e2d2dd499b 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -433,8 +433,21 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, for (int channelCount : (desiredAudioFormat.channelCount() == 1 ? inputChannels : outputChannels)) { for (int sampleRate : sampleRates) { + // int16_t samples adjustedAudioFormat.setChannelCount(channelCount); adjustedAudioFormat.setSampleRate(sampleRate); + adjustedAudioFormat.setSampleSize(16); + adjustedAudioFormat.setSampleType(QAudioFormat::SignedInt); + + if (audioDevice.isFormatSupported(adjustedAudioFormat)) { + return true; + } + + // float samples + adjustedAudioFormat.setChannelCount(channelCount); + adjustedAudioFormat.setSampleRate(sampleRate); + adjustedAudioFormat.setSampleSize(32); + adjustedAudioFormat.setSampleType(QAudioFormat::Float); if (audioDevice.isFormatSupported(adjustedAudioFormat)) { return true; @@ -1545,11 +1558,15 @@ float AudioClient::gainForSource(float distance, float volume) { return gain; } -qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) { +qint64 AudioClient::AudioOutputIODevice::readData(char* data, qint64 maxSize) { + + // data can be int16_t* or float* + int sampleSize = _audio->_outputFormat.sampleSize() / 8; + bool isFloat = _audio->_outputFormat.sampleType() == QAudioFormat::SampleType::Float; // samples requested from OUTPUT_CHANNEL_COUNT int deviceChannelCount = _audio->_outputFormat.channelCount(); - int samplesRequested = (int)(maxSize / AudioConstants::SAMPLE_SIZE) * OUTPUT_CHANNEL_COUNT / deviceChannelCount; + int samplesRequested = (int)(maxSize / sampleSize) * OUTPUT_CHANNEL_COUNT / deviceChannelCount; int samplesPopped; int bytesWritten; @@ -1559,14 +1576,24 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) { AudioRingBuffer::ConstIterator lastPopOutput = _receivedAudioStream.getLastPopOutput(); // if required, upmix or downmix to deviceChannelCount - if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) { - lastPopOutput.readSamples((int16_t*)data, samplesPopped); - } else if (deviceChannelCount > OUTPUT_CHANNEL_COUNT) { - lastPopOutput.readSamplesWithUpmix((int16_t*)data, samplesPopped, deviceChannelCount - OUTPUT_CHANNEL_COUNT); + if (isFloat) { + if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) { + lastPopOutput.readSamples((float*)data, samplesPopped); + } else if (deviceChannelCount > OUTPUT_CHANNEL_COUNT) { + lastPopOutput.readSamplesWithUpmix((float*)data, samplesPopped, deviceChannelCount - OUTPUT_CHANNEL_COUNT); + } else { + lastPopOutput.readSamplesWithDownmix((float*)data, samplesPopped); + } } else { - lastPopOutput.readSamplesWithDownmix((int16_t*)data, samplesPopped); + if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) { + lastPopOutput.readSamples((int16_t*)data, samplesPopped); + } else if (deviceChannelCount > OUTPUT_CHANNEL_COUNT) { + lastPopOutput.readSamplesWithUpmix((int16_t*)data, samplesPopped, deviceChannelCount - OUTPUT_CHANNEL_COUNT); + } else { + lastPopOutput.readSamplesWithDownmix((int16_t*)data, samplesPopped); + } } - bytesWritten = (samplesPopped * AudioConstants::SAMPLE_SIZE) * deviceChannelCount / OUTPUT_CHANNEL_COUNT; + bytesWritten = (samplesPopped * sampleSize) * deviceChannelCount / OUTPUT_CHANNEL_COUNT; } else { // nothing on network, don't grab anything from injectors, and just return 0s // this will flood the log: qCDebug(audioclient, "empty/partial network buffer"); diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 29e7a9e998..38ca319156 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -103,10 +103,11 @@ public: ConstIterator operator+(int i); ConstIterator operator-(int i); - void readSamples(int16_t* dest, int numSamples); - void readSamplesWithFade(int16_t* dest, int numSamples, float fade); - void readSamplesWithUpmix(int16_t* dest, int numSamples, int numExtraChannels); - void readSamplesWithDownmix(int16_t* dest, int numSamples); + // dest can be int16_t* or float* + template void readSamples(T* dest, int numSamples); + template void readSamplesWithFade(T* dest, int numSamples, float fade); + template void readSamplesWithUpmix(T* dest, int numSamples, int numExtraChannels); + template void readSamplesWithDownmix(T* dest, int numSamples); private: int16_t* atShiftedBy(int i); @@ -203,6 +204,28 @@ inline int16_t* AudioRingBuffer::ConstIterator::atShiftedBy(int i) { return _bufferFirst + i; } +inline AudioRingBuffer::ConstIterator AudioRingBuffer::nextOutput() const { + return ConstIterator(_buffer, _bufferLength, _nextOutput); +} + +inline AudioRingBuffer::ConstIterator AudioRingBuffer::lastFrameWritten() const { + return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples; +} + +// +// dest can be int16_t* or float* +// +template +inline void AudioRingBuffer::ConstIterator::readSamples(T* dest, int numSamples) { + int16_t* at = _at; + for (int i = 0; i < numSamples; i++) { + *dest++ = (T)*at; + at = (at == _bufferLast) ? _bufferFirst : at + 1; + } +} + +// fast path for int16_t* +template<> inline void AudioRingBuffer::ConstIterator::readSamples(int16_t* dest, int numSamples) { auto samplesToEnd = _bufferLast - _at + 1; @@ -218,16 +241,17 @@ inline void AudioRingBuffer::ConstIterator::readSamples(int16_t* dest, int numSa } } -inline void AudioRingBuffer::ConstIterator::readSamplesWithFade(int16_t* dest, int numSamples, float fade) { +template +inline void AudioRingBuffer::ConstIterator::readSamplesWithFade(T* dest, int numSamples, float fade) { int16_t* at = _at; for (int i = 0; i < numSamples; i++) { - *dest = (float)*at * fade; - ++dest; + *dest++ = (T)(*at * fade); at = (at == _bufferLast) ? _bufferFirst : at + 1; } } -inline void AudioRingBuffer::ConstIterator::readSamplesWithUpmix(int16_t* dest, int numSamples, int numExtraChannels) { +template +inline void AudioRingBuffer::ConstIterator::readSamplesWithUpmix(T* dest, int numSamples, int numExtraChannels) { int16_t* at = _at; for (int i = 0; i < numSamples/2; i++) { @@ -238,15 +262,16 @@ inline void AudioRingBuffer::ConstIterator::readSamplesWithUpmix(int16_t* dest, at = (at == _bufferLast) ? _bufferFirst : at + 1; // write 2 + N samples - *dest++ = left; - *dest++ = right; + *dest++ = (T)left; + *dest++ = (T)right; for (int n = 0; n < numExtraChannels; n++) { - *dest++ = 0; + *dest++ = (T)0; } } } -inline void AudioRingBuffer::ConstIterator::readSamplesWithDownmix(int16_t* dest, int numSamples) { +template +inline void AudioRingBuffer::ConstIterator::readSamplesWithDownmix(T* dest, int numSamples) { int16_t* at = _at; for (int i = 0; i < numSamples/2; i++) { @@ -257,16 +282,8 @@ inline void AudioRingBuffer::ConstIterator::readSamplesWithDownmix(int16_t* dest at = (at == _bufferLast) ? _bufferFirst : at + 1; // write 1 sample - *dest++ = (int16_t)((left + right) / 2); + *dest++ = (T)((left + right) / 2); } } -inline AudioRingBuffer::ConstIterator AudioRingBuffer::nextOutput() const { - return ConstIterator(_buffer, _bufferLength, _nextOutput); -} - -inline AudioRingBuffer::ConstIterator AudioRingBuffer::lastFrameWritten() const { - return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples; -} - #endif // hifi_AudioRingBuffer_h