Merge pull request #3489 from Atlante45/radio_js

AudioInjector stereo fix
This commit is contained in:
Philip Rosedale 2014-09-26 11:25:13 -07:00
commit 60d6a0bf0d
7 changed files with 50 additions and 20 deletions

View file

@ -10,7 +10,7 @@
// //
var modelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/entities/radio/Speakers2Finished.fbx"; var modelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/entities/radio/Speakers.fbx";
var soundURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/FamilyStereo.raw"; var soundURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/FamilyStereo.raw";
var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0); var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0);
@ -20,7 +20,7 @@ audioOptions.loop = true;
audioOptions.isStereo = true; audioOptions.isStereo = true;
var injector = null; var injector = null;
var sound = new Sound(soundURL); var sound = new Sound(soundURL, audioOptions.isStereo);
var entity = null; var entity = null;
var properties = null; var properties = null;
@ -31,14 +31,16 @@ function update() {
print("Sound file downloaded"); print("Sound file downloaded");
var position = Vec3.sum(MyAvatar.position, var position = Vec3.sum(MyAvatar.position,
Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiplyQbyV(MyAvatar.orientation,
{ x: 0, y: 0.3, z: -1 })); { x: 0, y: -0.3, z: -2 }));
var rotation = Quat.multiply(MyAvatar.orientation, var rotation = Quat.multiply(MyAvatar.orientation,
Quat.fromPitchYawRollDegrees(0, -90, 0)); Quat.fromPitchYawRollDegrees(0, -90, 0));
entity = Entities.addEntity({ entity = Entities.addEntity({
type: "Model", type: "Model",
position: position, position: position,
rotation: rotation, rotation: rotation,
dimensions: { x: 0.5, y: 0.5, z: 0.5 }, dimensions: { x: 0.391,
y: 1.000,
z: 1.701 },
modelURL: modelURL modelURL: modelURL
}); });
properties = Entities.getEntityProperties(entity); properties = Entities.getEntityProperties(entity);

View file

@ -78,11 +78,13 @@ void AudioInjector::injectAudio() {
// pack the position for injected audio // pack the position for injected audio
int positionOptionOffset = injectAudioPacket.size(); int positionOptionOffset = injectAudioPacket.size();
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()), sizeof(_options.getPosition())); packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()),
sizeof(_options.getPosition()));
// pack our orientation for injected audio // pack our orientation for injected audio
int orientationOptionOffset = injectAudioPacket.size(); int orientationOptionOffset = injectAudioPacket.size();
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()), sizeof(_options.getOrientation())); packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()),
sizeof(_options.getOrientation()));
// pack zero for radius // pack zero for radius
float radius = 0; float radius = 0;
@ -103,7 +105,7 @@ void AudioInjector::injectAudio() {
quint16 outgoingInjectedAudioSequenceNumber = 0; quint16 outgoingInjectedAudioSequenceNumber = 0;
while (_currentSendPosition < soundByteArray.size() && !_shouldStop) { while (_currentSendPosition < soundByteArray.size() && !_shouldStop) {
int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
soundByteArray.size() - _currentSendPosition); soundByteArray.size() - _currentSendPosition);
memcpy(injectAudioPacket.data() + positionOptionOffset, memcpy(injectAudioPacket.data() + positionOptionOffset,
&_options.getPosition(), &_options.getPosition(),
@ -116,10 +118,12 @@ void AudioInjector::injectAudio() {
injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy); injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy);
// pack the sequence number // pack the sequence number
memcpy(injectAudioPacket.data() + numPreSequenceNumberBytes, &outgoingInjectedAudioSequenceNumber, sizeof(quint16)); memcpy(injectAudioPacket.data() + numPreSequenceNumberBytes,
&outgoingInjectedAudioSequenceNumber, sizeof(quint16));
// copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet
memcpy(injectAudioPacket.data() + numPreAudioDataBytes, soundByteArray.data() + _currentSendPosition, bytesToCopy); memcpy(injectAudioPacket.data() + numPreAudioDataBytes,
soundByteArray.data() + _currentSendPosition, bytesToCopy);
// grab our audio mixer from the NodeList, if it exists // grab our audio mixer from the NodeList, if it exists
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();

View file

@ -13,6 +13,9 @@
AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) {
if (sound->isStereo()) {
const_cast<AudioInjectorOptions*>(injectorOptions)->setIsStereo(true);
}
AudioInjector* injector = new AudioInjector(sound, *injectorOptions); AudioInjector* injector = new AudioInjector(sound, *injectorOptions);
QThread* injectorThread = new QThread(); QThread* injectorThread = new QThread();

View file

@ -30,7 +30,9 @@ InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, const In
const uchar MAX_INJECTOR_VOLUME = 255; const uchar MAX_INJECTOR_VOLUME = 255;
int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { int InjectedAudioStream::parseStreamProperties(PacketType type,
const QByteArray& packetAfterSeqNum,
int& numAudioSamples) {
// setup a data stream to read from this packet // setup a data stream to read from this packet
QDataStream packetStream(packetAfterSeqNum); QDataStream packetStream(packetAfterSeqNum);
@ -38,6 +40,9 @@ int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray
packetStream.skipRawData(NUM_BYTES_RFC4122_UUID); packetStream.skipRawData(NUM_BYTES_RFC4122_UUID);
packetStream >> _isStereo; packetStream >> _isStereo;
if (isStereo()) {
_ringBuffer.resizeForFrameSize(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO);
}
// pull the loopback flag and set our boolean // pull the loopback flag and set our boolean
uchar shouldLoopback; uchar shouldLoopback;

View file

@ -31,7 +31,8 @@
// procedural audio version of Sound // procedural audio version of Sound
Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) : Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) :
QObject(parent) QObject(parent),
_isStereo(false)
{ {
static char monoAudioData[MAX_PACKET_SIZE]; static char monoAudioData[MAX_PACKET_SIZE];
static int16_t* monoAudioSamples = (int16_t*)(monoAudioData); static int16_t* monoAudioSamples = (int16_t*)(monoAudioData);
@ -69,8 +70,9 @@ Sound::Sound(float volume, float frequency, float duration, float decay, QObject
} }
} }
Sound::Sound(const QUrl& sampleURL, QObject* parent) : Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) :
QObject(parent), QObject(parent),
_isStereo(isStereo),
_hasDownloaded(false) _hasDownloaded(false)
{ {
// assume we have a QApplication or QCoreApplication instance and use the // assume we have a QApplication or QCoreApplication instance and use the
@ -82,12 +84,14 @@ Sound::Sound(const QUrl& sampleURL, QObject* parent) :
QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL)); QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL));
connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished); connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished);
connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError))); connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
} }
Sound::Sound(const QByteArray byteArray, QObject* parent) : Sound::Sound(const QByteArray byteArray, QObject* parent) :
QObject(parent), QObject(parent),
_byteArray(byteArray), _byteArray(byteArray),
_isStereo(false),
_hasDownloaded(true) _hasDownloaded(true)
{ {
} }
@ -149,11 +153,20 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data(); int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
int16_t* destinationSamples = (int16_t*) _byteArray.data(); int16_t* destinationSamples = (int16_t*) _byteArray.data();
for (int i = 1; i < numSourceSamples; i += 2) {
if (i + 1 >= numSourceSamples) { if (_isStereo) {
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2); for (int i = 0; i < numSourceSamples; i += 4) {
} else { destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2);
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2) + (sourceSamples[i + 1] / 4); destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2);
}
} else {
for (int i = 1; i < numSourceSamples; i += 2) {
if (i + 1 >= numSourceSamples) {
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2);
} else {
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2)
+ (sourceSamples[i + 1] / 4);
}
} }
} }
} }

View file

@ -20,17 +20,19 @@ class Sound : public QObject {
Q_PROPERTY(bool downloaded READ hasDownloaded) Q_PROPERTY(bool downloaded READ hasDownloaded)
public: public:
Sound(const QUrl& sampleURL, QObject* parent = NULL); Sound(const QUrl& sampleURL, bool isStereo = false, QObject* parent = NULL);
Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL); Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL);
Sound(const QByteArray byteArray, QObject* parent = NULL); Sound(const QByteArray byteArray, QObject* parent = NULL);
void append(const QByteArray byteArray); void append(const QByteArray byteArray);
bool isStereo() const { return _isStereo; }
bool hasDownloaded() const { return _hasDownloaded; } bool hasDownloaded() const { return _hasDownloaded; }
const QByteArray& getByteArray() { return _byteArray; } const QByteArray& getByteArray() { return _byteArray; }
private: private:
QByteArray _byteArray; QByteArray _byteArray;
bool _isStereo;
bool _hasDownloaded; bool _hasDownloaded;
void trimFrames(); void trimFrames();

View file

@ -48,7 +48,8 @@ EntityScriptingInterface ScriptEngine::_entityScriptingInterface;
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) { static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
QUrl soundURL = QUrl(context->argument(0).toString()); QUrl soundURL = QUrl(context->argument(0).toString());
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership); bool isStereo = context->argument(1).toBool();
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL, isStereo), QScriptEngine::ScriptOwnership);
return soundScriptValue; return soundScriptValue;
} }