mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 23:33:34 +02:00
fix rendered scope for new Qt Audio
This commit is contained in:
parent
6765ce2f1f
commit
71aca69410
6 changed files with 90 additions and 56 deletions
assignment-client/src
interface/src
|
@ -78,8 +78,8 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
if (_currentAssignment) {
|
||||
// have the threaded current assignment handle this datagram
|
||||
QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection,
|
||||
Q_ARG(const QByteArray&, QByteArray((char*) packetData, receivedBytes)),
|
||||
Q_ARG(const HifiSockAddr&, senderSockAddr));
|
||||
Q_ARG(QByteArray, QByteArray((char*) packetData, receivedBytes)),
|
||||
Q_ARG(HifiSockAddr, senderSockAddr));
|
||||
} else if (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
|
||||
|
||||
if (_currentAssignment) {
|
||||
|
|
|
@ -133,7 +133,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_lookatIndicatorScale(1.0f),
|
||||
_perfStatsOn(false),
|
||||
_chatEntryOn(false),
|
||||
_audio(STARTUP_JITTER_SAMPLES),
|
||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||
_stopNetworkReceiveThread(false),
|
||||
_voxelProcessor(),
|
||||
_voxelHideShowThread(&_voxels),
|
||||
|
|
|
@ -41,12 +41,16 @@ static const int ICON_SIZE = 24;
|
|||
static const int ICON_LEFT = 20;
|
||||
static const int BOTTOM_PADDING = 110;
|
||||
|
||||
Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
|
||||
Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent) :
|
||||
QObject(parent),
|
||||
_audioInput(NULL),
|
||||
_inputDevice(NULL),
|
||||
_audioOutput(NULL),
|
||||
_outputDevice(NULL),
|
||||
_isBufferSendCallback(false),
|
||||
_nextOutputSamples(NULL),
|
||||
_ringBuffer(true),
|
||||
_scope(scope),
|
||||
_averagedLatency(0.0),
|
||||
_measuredJitter(0),
|
||||
_jitterBufferSamples(initialJitterBufferSamples),
|
||||
|
@ -124,6 +128,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
const int QT_SAMPLE_RATE = 44100;
|
||||
const int SAMPLE_RATE_RATIO = QT_SAMPLE_RATE / SAMPLE_RATE;
|
||||
const int CALLBACK_ACCELERATOR_RATIO = 2;
|
||||
const int CALLBACK_IO_BUFFER_SIZE = BUFFER_LENGTH_BYTES_STEREO * SAMPLE_RATE_RATIO / CALLBACK_ACCELERATOR_RATIO;
|
||||
|
||||
void Audio::start() {
|
||||
|
||||
|
@ -147,7 +152,7 @@ void Audio::start() {
|
|||
}
|
||||
|
||||
_audioInput = new QAudioInput(inputAudioDevice, audioFormat, this);
|
||||
_audioInput->setBufferSize(BUFFER_LENGTH_BYTES_STEREO * SAMPLE_RATE_RATIO / CALLBACK_ACCELERATOR_RATIO);
|
||||
_audioInput->setBufferSize(CALLBACK_IO_BUFFER_SIZE);
|
||||
_inputDevice = _audioInput->start();
|
||||
|
||||
connect(_inputDevice, SIGNAL(readyRead()), SLOT(handleAudioInput()));
|
||||
|
@ -164,15 +169,14 @@ void Audio::start() {
|
|||
}
|
||||
|
||||
_audioOutput = new QAudioOutput(outputDeviceInfo, audioFormat, this);
|
||||
_audioOutput->setBufferSize(BUFFER_LENGTH_BYTES_STEREO * SAMPLE_RATE_RATIO / CALLBACK_ACCELERATOR_RATIO);
|
||||
_audioOutput->setBufferSize(CALLBACK_IO_BUFFER_SIZE);
|
||||
_outputDevice = _audioOutput->start();
|
||||
|
||||
gettimeofday(&_lastReceiveTime, NULL);
|
||||
}
|
||||
|
||||
void Audio::handleAudioInput() {
|
||||
static int16_t stereoInputBuffer[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2 * SAMPLE_RATE_RATIO];
|
||||
static int16_t stereoOutputBuffer[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2 * SAMPLE_RATE_RATIO / CALLBACK_ACCELERATOR_RATIO];
|
||||
static int16_t stereoInputBuffer[CALLBACK_IO_BUFFER_SIZE * 2];
|
||||
static char monoAudioDataPacket[MAX_PACKET_SIZE];
|
||||
static int bufferSizeSamples = _audioInput->bufferSize() / sizeof(int16_t);
|
||||
|
||||
|
@ -180,36 +184,45 @@ void Audio::handleAudioInput() {
|
|||
static int leadingBytes = numBytesPacketHeader + sizeof(glm::vec3) + sizeof(glm::quat) + NUM_BYTES_RFC4122_UUID;
|
||||
static int16_t* monoAudioSamples = (int16_t*) (monoAudioDataPacket + leadingBytes);
|
||||
|
||||
QByteArray inputByteArray = _inputDevice->read(CALLBACK_IO_BUFFER_SIZE);
|
||||
|
||||
if (_isBufferSendCallback) {
|
||||
// this is the second half of a full buffer of data
|
||||
|
||||
// zero out the monoAudioSamples array
|
||||
memset(monoAudioSamples, 0, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||
|
||||
// read out the current samples from the _inputDevice
|
||||
_inputDevice->read((char*) (stereoInputBuffer + bufferSizeSamples), sizeof(stereoInputBuffer) / 2);
|
||||
// copy samples from the inputByteArray to the stereoInputBuffer
|
||||
memcpy((char*) (stereoInputBuffer + bufferSizeSamples), inputByteArray.data(), inputByteArray.size());
|
||||
|
||||
} else {
|
||||
// take samples we have in this callback and store them in the first half of the static buffer
|
||||
// to send off in the next callback
|
||||
_inputDevice->read((char*) stereoInputBuffer, sizeof(stereoInputBuffer) / 2);
|
||||
memcpy((char*) stereoInputBuffer, inputByteArray.data(), inputByteArray.size());
|
||||
}
|
||||
|
||||
// add input data just written to the scope
|
||||
QMetaObject::invokeMethod(_scope, "addStereoSamples", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, inputByteArray), Q_ARG(bool, true));
|
||||
|
||||
QByteArray stereoOutputBuffer;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted) {
|
||||
// if local loopback enabled, copy input to output
|
||||
if (_isBufferSendCallback) {
|
||||
memcpy(stereoOutputBuffer, stereoInputBuffer + bufferSizeSamples, sizeof(stereoOutputBuffer));
|
||||
stereoOutputBuffer.append((char*) (stereoInputBuffer + bufferSizeSamples), CALLBACK_IO_BUFFER_SIZE);
|
||||
} else {
|
||||
memcpy(stereoOutputBuffer, stereoInputBuffer, sizeof(stereoOutputBuffer));
|
||||
stereoOutputBuffer.append((char*) stereoInputBuffer, CALLBACK_IO_BUFFER_SIZE);
|
||||
}
|
||||
} else {
|
||||
// zero out the stereoOutputBuffer
|
||||
memset(stereoOutputBuffer, 0, sizeof(stereoOutputBuffer));
|
||||
stereoOutputBuffer = QByteArray(CALLBACK_IO_BUFFER_SIZE, 0);
|
||||
}
|
||||
|
||||
// add procedural effects to the appropriate input samples
|
||||
addProceduralSounds(monoAudioSamples + (_isBufferSendCallback
|
||||
? BUFFER_LENGTH_SAMPLES_PER_CHANNEL / CALLBACK_ACCELERATOR_RATIO : 0),
|
||||
stereoOutputBuffer,
|
||||
(int16_t*) stereoOutputBuffer.data(),
|
||||
BUFFER_LENGTH_SAMPLES_PER_CHANNEL / CALLBACK_ACCELERATOR_RATIO);
|
||||
|
||||
if (_isBufferSendCallback) {
|
||||
|
@ -300,16 +313,19 @@ void Audio::handleAudioInput() {
|
|||
}
|
||||
|
||||
if (_nextOutputSamples) {
|
||||
|
||||
int16_t* stereoOutputBufferSamples = (int16_t*) stereoOutputBuffer.data();
|
||||
|
||||
// play whatever we have in the audio buffer
|
||||
for (int s = 0; s < PACKET_LENGTH_SAMPLES_PER_CHANNEL / CALLBACK_ACCELERATOR_RATIO; s++) {
|
||||
int16_t leftSample = _nextOutputSamples[s];
|
||||
int16_t rightSample = _nextOutputSamples[s + PACKET_LENGTH_SAMPLES_PER_CHANNEL];
|
||||
|
||||
stereoOutputBuffer[(s * 4)] += leftSample;
|
||||
stereoOutputBuffer[(s * 4) + 2] += leftSample;
|
||||
stereoOutputBufferSamples[(s * 4)] += leftSample;
|
||||
stereoOutputBufferSamples[(s * 4) + 2] += leftSample;
|
||||
|
||||
stereoOutputBuffer[(s * 4) + 1] += rightSample;
|
||||
stereoOutputBuffer[(s * 4) + 3] += rightSample;
|
||||
stereoOutputBufferSamples[(s * 4) + 1] += rightSample;
|
||||
stereoOutputBufferSamples[(s * 4) + 3] += rightSample;
|
||||
}
|
||||
|
||||
if (_isBufferSendCallback) {
|
||||
|
@ -325,11 +341,11 @@ void Audio::handleAudioInput() {
|
|||
}
|
||||
}
|
||||
|
||||
_outputDevice->write((char*) stereoOutputBuffer, sizeof(stereoOutputBuffer));
|
||||
_outputDevice->write(stereoOutputBuffer);
|
||||
|
||||
// add output (@speakers) data just written to the scope
|
||||
// _scope->addSamples(1, outputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
// _scope->addSamples(2, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
QMetaObject::invokeMethod(_scope, "addStereoSamples", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, stereoOutputBuffer), Q_ARG(bool, false));
|
||||
|
||||
_isBufferSendCallback = !_isBufferSendCallback;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class Audio : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
// setup for audio I/O
|
||||
Audio(int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
|
|
|
@ -6,13 +6,16 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Oscilloscope.h"
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include <limits>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "Oscilloscope.h"
|
||||
|
||||
// Reimplemented 4/26/13 (tosh) - don't blame Philip for bugs
|
||||
|
||||
using namespace std;
|
||||
|
@ -65,37 +68,50 @@ Oscilloscope::~Oscilloscope() {
|
|||
delete[] _samples;
|
||||
}
|
||||
|
||||
void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) {
|
||||
void Oscilloscope::addStereoSamples(const QByteArray& audioByteArray, bool isInput) {
|
||||
|
||||
if (! enabled || inputPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
// determine start/end offset of this channel's region
|
||||
unsigned baseOffs = MAX_SAMPLES_PER_CHANNEL * ch;
|
||||
unsigned endOffs = baseOffs + MAX_SAMPLES_PER_CHANNEL;
|
||||
|
||||
// fetch write position for this channel
|
||||
unsigned writePos = _writePos[ch];
|
||||
|
||||
// determine write position after adding the samples
|
||||
unsigned newWritePos = writePos + n;
|
||||
unsigned n2 = 0;
|
||||
if (newWritePos >= endOffs) {
|
||||
// passed boundary of the circular buffer? -> we need to copy two blocks
|
||||
n2 = newWritePos - endOffs;
|
||||
newWritePos = baseOffs + n2;
|
||||
n -= n2;
|
||||
|
||||
unsigned int numSamplesPerChannel = audioByteArray.size() / (sizeof(int16_t) * 2);
|
||||
int16_t samples[numSamplesPerChannel];
|
||||
const int16_t* stereoSamples = (int16_t*) audioByteArray.constData();
|
||||
|
||||
for (int channel = 0; channel < (isInput ? 1 : 2); channel++) {
|
||||
// add samples for each of the channels
|
||||
|
||||
// enumerate the interleaved stereoSamples array and pull out the samples for this channel
|
||||
for (int i = 0; i < audioByteArray.size() / sizeof(int16_t); i += 2) {
|
||||
samples[i / 2] = stereoSamples[i + channel];
|
||||
}
|
||||
|
||||
// determine start/end offset of this channel's region
|
||||
unsigned baseOffs = MAX_SAMPLES_PER_CHANNEL * (channel + !isInput);
|
||||
unsigned endOffs = baseOffs + MAX_SAMPLES_PER_CHANNEL;
|
||||
|
||||
// fetch write position for this channel
|
||||
unsigned writePos = _writePos[channel + !isInput];
|
||||
|
||||
// determine write position after adding the samples
|
||||
unsigned newWritePos = writePos + numSamplesPerChannel;
|
||||
unsigned n2 = 0;
|
||||
if (newWritePos >= endOffs) {
|
||||
// passed boundary of the circular buffer? -> we need to copy two blocks
|
||||
n2 = newWritePos - endOffs;
|
||||
newWritePos = baseOffs + n2;
|
||||
numSamplesPerChannel -= n2;
|
||||
}
|
||||
|
||||
// copy data
|
||||
memcpy(_samples + writePos, samples, numSamplesPerChannel * sizeof(int16_t));
|
||||
if (n2 > 0) {
|
||||
memcpy(_samples + baseOffs, samples + numSamplesPerChannel, n2 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
// set new write position for this channel
|
||||
_writePos[channel + !isInput] = newWritePos;
|
||||
}
|
||||
|
||||
// copy data
|
||||
memcpy(_samples + writePos, data, n * sizeof(short));
|
||||
if (n2 > 0) {
|
||||
memcpy(_samples + baseOffs, data + n, n2 * sizeof(short));
|
||||
}
|
||||
|
||||
// set new write position for this channel
|
||||
_writePos[ch] = newWritePos;
|
||||
}
|
||||
|
||||
void Oscilloscope::render(int x, int y) {
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
class Oscilloscope {
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class Oscilloscope : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Oscilloscope(int width, int height, bool isEnabled);
|
||||
~Oscilloscope();
|
||||
|
||||
void addSamples(unsigned ch, short const* data, unsigned n);
|
||||
|
||||
void render(int x, int y);
|
||||
|
||||
// Switches: On/Off, Stop Time
|
||||
|
@ -57,7 +58,8 @@ public:
|
|||
// Sets the number of input samples per output sample. Without filtering
|
||||
// just uses every nTh sample.
|
||||
void setDownsampleRatio(unsigned n) { assert(n > 0); _downsampleRatio = n; }
|
||||
|
||||
public slots:
|
||||
void addStereoSamples(const QByteArray& audioByteArray, bool isInput);
|
||||
private:
|
||||
// don't copy/assign
|
||||
Oscilloscope(Oscilloscope const&); // = delete;
|
||||
|
|
Loading…
Reference in a new issue