Merge pull request #1385 from birarda/master

audio fixes for clipping and off-axis
This commit is contained in:
Philip Rosedale 2013-12-17 11:25:55 -08:00
commit 610d0f4680
3 changed files with 43 additions and 15 deletions

View file

@ -164,7 +164,6 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
if ((s / 2) < numSamplesDelay) {
// pull the earlier sample for the delayed channel
int earlierSample = (*bufferToAdd)[(s / 2) - numSamplesDelay] * attenuationCoefficient * weakChannelAmplitudeRatio;
_clientSamples[s + delayedChannelOffset] = glm::clamp(_clientSamples[s + delayedChannelOffset] + earlierSample,
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
}
@ -175,11 +174,11 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
if ((s / 2) + numSamplesDelay < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
// place the curernt sample at the right spot in the delayed channel
int16_t clampedSample = glm::clamp((int) (_clientSamples[s + numSamplesDelay + delayedChannelOffset]
// place the current sample at the right spot in the delayed channel
int16_t clampedSample = glm::clamp((int) (_clientSamples[s + (numSamplesDelay * 2) + delayedChannelOffset]
+ (currentSample * weakChannelAmplitudeRatio)),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + numSamplesDelay + delayedChannelOffset] = clampedSample;
_clientSamples[s + (numSamplesDelay * 2) + delayedChannelOffset] = clampedSample;
}
}
}

View file

@ -52,6 +52,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
_outputFormat(),
_outputDevice(NULL),
_numOutputCallbackBytes(0),
_loopbackAudioOutput(NULL),
_loopbackOutputDevice(NULL),
_inputRingBuffer(0),
_ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL),
_scope(scope),
@ -201,19 +203,20 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples,
// upsample from 24 to 48
// for now this only supports a stereo to stereo conversion - this is our case for network audio to output
int sourceIndex = 0;
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
int dtsSampleRateFactor = (destinationAudioFormat.sampleRate() / sourceAudioFormat.sampleRate());
for (int i = 0; i < numDestinationSamples; i += destinationAudioFormat.channelCount() * destinationToSourceFactor) {
for (int i = 0; i < numDestinationSamples; i += destinationAudioFormat.channelCount() * dtsSampleRateFactor) {
sourceIndex = (i / destinationToSourceFactor);
// fill the L/R channels and make the rest silent
for (int j = i; j < i + (destinationToSourceFactor * destinationAudioFormat.channelCount()); j++) {
for (int j = i; j < i + (dtsSampleRateFactor * destinationAudioFormat.channelCount()); j++) {
if (j % destinationAudioFormat.channelCount() == 0) {
// left channel
destinationSamples[j] = sourceSamples[sourceIndex];
} else if (j % destinationAudioFormat.channelCount() == 1) {
// right channel
destinationSamples[j] = sourceSamples[sourceIndex + 1];
destinationSamples[j] = sourceSamples[sourceIndex + (sourceAudioFormat.channelCount() > 1 ? 1 : 0)];
} else {
// channels above 2, fill with silence
destinationSamples[j] = 0;
@ -263,9 +266,13 @@ void Audio::start() {
_inputDevice = _audioInput->start();
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput()));
// setup our general output device for audio-mixer audio
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
_outputDevice = _audioOutput->start();
// setup a loopback audio output device
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
gettimeofday(&_lastReceiveTime, NULL);
}
@ -290,6 +297,30 @@ void Audio::handleAudioInput() {
QByteArray inputByteArray = _inputDevice->readAll();
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio)) {
// if this person wants local loopback add that to the locally injected audio
if (!_loopbackOutputDevice) {
// we didn't have the loopback output device going so set that up now
_loopbackOutputDevice = _loopbackAudioOutput->start();
}
if (_inputFormat == _outputFormat) {
_loopbackOutputDevice->write(inputByteArray);
} else {
static float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate())
* (_outputFormat.channelCount() / _inputFormat.channelCount());
QByteArray loopBackByteArray(inputByteArray.size() * loopbackOutputToInputRatio, 0);
linearResampling((int16_t*) inputByteArray.data(), (int16_t*) loopBackByteArray.data(),
inputByteArray.size() / sizeof(int16_t),
loopBackByteArray.size() / sizeof(int16_t), _inputFormat, _outputFormat);
_loopbackOutputDevice->write(loopBackByteArray);
}
}
_inputRingBuffer.writeData(inputByteArray.data(), inputByteArray.size());
while (_inputRingBuffer.samplesAvailable() > inputSamplesRequired) {
@ -324,11 +355,6 @@ void Audio::handleAudioInput() {
Q_ARG(QByteArray, QByteArray((char*) monoAudioSamples,
NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL)),
Q_ARG(bool, false), Q_ARG(bool, true));
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio)) {
// if this person wants local loopback add that to the locally injected audio
memcpy(_localInjectedSamples, monoAudioSamples, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
}
} else {
// our input loudness is 0, since we're muted
_lastInputLoudness = 0;
@ -438,8 +464,8 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
ringBufferSamples[i * 2] = glm::clamp(ringBufferSamples[i * 2] + _localInjectedSamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
ringBufferSamples[(i * 2) + 1] += glm::clamp(ringBufferSamples[(i * 2) + 1] + _localInjectedSamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
ringBufferSamples[(i * 2) + 1] = glm::clamp(ringBufferSamples[(i * 2) + 1] + _localInjectedSamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
}
// copy the packet from the RB to the output

View file

@ -78,8 +78,11 @@ private:
QAudioFormat _outputFormat;
QIODevice* _outputDevice;
int _numOutputCallbackBytes;
QAudioOutput* _loopbackAudioOutput;
QIODevice* _loopbackOutputDevice;
AudioRingBuffer _inputRingBuffer;
AudioRingBuffer _ringBuffer;
Oscilloscope* _scope;
StDev _stdev;
timeval _lastReceiveTime;