Partial support for floating-point audio output

This commit is contained in:
Ken Cooke 2017-01-19 10:33:04 -08:00
parent 98699885f4
commit 784b23d05c
2 changed files with 73 additions and 29 deletions
libraries
audio-client/src
audio/src

View file

@ -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");

View file

@ -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<typename T> void readSamples(T* dest, int numSamples);
template<typename T> void readSamplesWithFade(T* dest, int numSamples, float fade);
template<typename T> void readSamplesWithUpmix(T* dest, int numSamples, int numExtraChannels);
template<typename T> 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<typename T>
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<typename T>
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<typename T>
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<typename T>
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