From d083e75d2d44a2ca758c87f497a35662ac0066af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 09:59:10 -0800 Subject: [PATCH 01/24] groundwork for better locally looped audio --- interface/src/Audio.cpp | 20 ++++--------------- interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 3 ++- .../audio/src/AudioScriptingInterface.cpp | 12 ----------- libraries/audio/src/AudioScriptingInterface.h | 1 - 5 files changed, 7 insertions(+), 31 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 726d1e609a..3289e64ed4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,22 +1334,10 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -void Audio::handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& injectorOptions) { - if (audioByteArray.size() > 0) { - QAudioFormat localFormat = _outputFormat; - - if (!injectorOptions.isStereo()) { - localFormat.setChannelCount(1); - } - - QAudioOutput* localSoundOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); - - QIODevice* localIODevice = localSoundOutput->start(); - qDebug() << "Writing" << audioByteArray.size() << "to" << localIODevice; - localIODevice->write(audioByteArray); - } else { - qDebug() << "Audio::handleAudioByteArray called with an empty byte array. Sound is likely still downloading."; - } +QAudioOutput* Audio::newLocalOutputInterface(bool isStereo) { + QAudioFormat localFormat = _outputFormat; + localFormat.setChannelCount(isStereo ? 2 : 1); + return new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat); } void Audio::renderToolBox(int x, int y, bool boxed) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ecbef026c4..02ea6db498 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options); + virtual QAudioOutput* newLocalOutputInterface(bool isStereo); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 1ee71ee32d..82710277b3 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -13,6 +13,7 @@ #define hifi_AbstractAudioInterface_h #include +#include #include "AudioInjectorOptions.h" @@ -24,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options) = 0; + virtual QAudioOutput* newLocalOutputInterface(bool isStereo) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 33afcdb095..318db1871b 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -37,18 +37,6 @@ void AudioScriptingInterface::stopAllInjectors() { } } -void AudioScriptingInterface::playLocalSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { - if (sound->isStereo()) { - const_cast(injectorOptions)->setIsStereo(true); - } - - // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly - QMetaObject::invokeMethod(_localLoopbackInterface, "handleAudioByteArray", - Qt::AutoConnection, - Q_ARG(QByteArray, sound->getByteArray()), - Q_ARG(const AudioInjectorOptions&, *injectorOptions)); -} - AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { if (sound->isStereo()) { diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 5cd0f9e99a..ffbef646ec 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,6 @@ public slots: static float getLoudness(AudioInjector* injector); - void playLocalSound(Sound *sound, const AudioInjectorOptions* injectorOptions = NULL); AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); void stopInjector(AudioInjector* injector); From a8681cd5b65cf8ace44a62adda777a8548cbadcb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:24:21 -0800 Subject: [PATCH 02/24] changes to allow AudioInjectorOptions to operate as a hash from js --- libraries/audio/src/AudioInjector.cpp | 28 ++++---- libraries/audio/src/AudioInjectorOptions.cpp | 67 ++++++++++++------- libraries/audio/src/AudioInjectorOptions.h | 55 ++++----------- .../audio/src/AudioScriptingInterface.cpp | 6 +- libraries/audio/src/AudioScriptingInterface.h | 3 + libraries/avatars/src/Player.cpp | 10 +-- libraries/script-engine/src/ScriptEngine.cpp | 5 +- 7 files changed, 85 insertions(+), 89 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 45e1eb57e1..2d13568664 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -75,7 +75,7 @@ void AudioInjector::injectAudio() { packetStream << QUuid::createUuid(); // pack the stereo/mono type of the stream - packetStream << _options.isStereo(); + packetStream << _options.stereo; // pack the flag for loopback uchar loopbackFlag = (uchar) true; @@ -83,13 +83,13 @@ void AudioInjector::injectAudio() { // pack the position for injected audio int positionOptionOffset = injectAudioPacket.size(); - packetStream.writeRawData(reinterpret_cast(&_options.getPosition()), - sizeof(_options.getPosition())); + packetStream.writeRawData(reinterpret_cast(&_options.position), + sizeof(_options.position)); // pack our orientation for injected audio int orientationOptionOffset = injectAudioPacket.size(); - packetStream.writeRawData(reinterpret_cast(&_options.getOrientation()), - sizeof(_options.getOrientation())); + packetStream.writeRawData(reinterpret_cast(&_options.orientation), + sizeof(_options.orientation)); // pack zero for radius float radius = 0; @@ -97,23 +97,23 @@ void AudioInjector::injectAudio() { // pack 255 for attenuation byte int volumeOptionOffset = injectAudioPacket.size(); - quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume(); + quint8 volume = MAX_INJECTOR_VOLUME * _options.volume; packetStream << volume; - packetStream << _options.ignorePenumbra(); + packetStream << _options.ignorePenumbra; QElapsedTimer timer; timer.start(); int nextFrame = 0; int numPreAudioDataBytes = injectAudioPacket.size(); - bool shouldLoop = _options.getLoop(); + bool shouldLoop = _options.loop; // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks quint16 outgoingInjectedAudioSequenceNumber = 0; while (_currentSendPosition < soundByteArray.size() && !_shouldStop) { - int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, + int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, soundByteArray.size() - _currentSendPosition); // Measure the loudness of this frame @@ -125,12 +125,12 @@ void AudioInjector::injectAudio() { _loudness /= (float)(bytesToCopy / sizeof(int16_t)); memcpy(injectAudioPacket.data() + positionOptionOffset, - &_options.getPosition(), - sizeof(_options.getPosition())); + &_options.position, + sizeof(_options.position)); memcpy(injectAudioPacket.data() + orientationOptionOffset, - &_options.getOrientation(), - sizeof(_options.getOrientation())); - volume = MAX_INJECTOR_VOLUME * _options.getVolume(); + &_options.orientation, + sizeof(_options.orientation)); + volume = MAX_INJECTOR_VOLUME * _options.volume; memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume)); // resize the QByteArray to the right size diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 670bea2fef..2a532b92b7 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -9,33 +9,54 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "AudioInjectorOptions.h" -AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : - QObject(parent), - _position(0.0f, 0.0f, 0.0f), - _volume(1.0f), - _loop(false), - _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), - _isStereo(false), - _ignorePenumbra(false) +AudioInjectorOptions::AudioInjectorOptions() : + position(0.0f, 0.0f, 0.0f), + volume(1.0f), + loop(false), + orientation(glm::vec3(0.0f, 0.0f, 0.0f)), + stereo(false), + ignorePenumbra(false) { + } -AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { - _position = other._position; - _volume = other._volume; - _loop = other._loop; - _orientation = other._orientation; - _isStereo = other._isStereo; - _ignorePenumbra = other._ignorePenumbra; +QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { + QScriptValue obj = engine->newObject(); + obj.setProperty("position", vec3toScriptValue(engine, injectorOptions.position)); + obj.setProperty("volume", injectorOptions.volume); + obj.setProperty("loop", injectorOptions.loop); + obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); + obj.setProperty("stereo", injectorOptions.stereo); + obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + return obj; } -void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) { - _position = other._position; - _volume = other._volume; - _loop = other._loop; - _orientation = other._orientation; - _isStereo = other._isStereo; - _ignorePenumbra = other._ignorePenumbra; -} \ No newline at end of file +void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) { + if (object.property("position").isValid()) { + vec3FromScriptValue(object.property("position"), injectorOptions.position); + } + + if (object.property("volume").isValid()) { + injectorOptions.volume = object.property("volume").toNumber(); + } + + if (object.property("loop").isValid()) { + injectorOptions.loop = object.property("loop").toBool(); + } + + if (object.property("orientation").isValid()) { + quatFromScriptValue(object.property("orientation"), injectorOptions.orientation); + } + + if (object.property("stereo").isValid()) { + injectorOptions.stereo = object.property("stereo").toBool(); + } + + if (object.property("ignorePenumbra").isValid()) { + injectorOptions.ignorePenumbra = object.property("ignorePenumbra").toBool(); + } + } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 1ccd85be7e..c3e2da991a 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -12,54 +12,25 @@ #ifndef hifi_AudioInjectorOptions_h #define hifi_AudioInjectorOptions_h -#include +#include #include #include -#include - -class AudioInjectorOptions : public QObject { - Q_OBJECT - - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) - Q_PROPERTY(float volume READ getVolume WRITE setVolume) - Q_PROPERTY(bool loop READ getLoop WRITE setLoop) - Q_PROPERTY(bool isStereo READ isStereo WRITE setIsStereo) - Q_PROPERTY(bool ignorePenumbra READ ignorePenumbra WRITE setIgnorePenumbra) +class AudioInjectorOptions { public: - AudioInjectorOptions(QObject* parent = 0); - AudioInjectorOptions(const AudioInjectorOptions& other); - void operator=(const AudioInjectorOptions& other); - - const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3& position) { _position = position; } - - float getVolume() const { return _volume; } - void setVolume(float volume) { _volume = volume; } - - bool getLoop() const { return _loop; } - void setLoop(bool loop) { _loop = loop; } - - const glm::quat& getOrientation() const { return _orientation; } - void setOrientation(const glm::quat& orientation) { _orientation = orientation; } - - const bool isStereo() const { return _isStereo; } - void setIsStereo(const bool isStereo) { _isStereo = isStereo; } - - const bool ignorePenumbra() const {return _ignorePenumbra; } - void setIgnorePenumbra(bool ignorePenumbra) { _ignorePenumbra = ignorePenumbra; } - -private: - glm::vec3 _position; - float _volume; - bool _loop; - glm::quat _orientation; - bool _isStereo; - bool _ignorePenumbra; + AudioInjectorOptions(); + glm::vec3 position; + float volume; + bool loop; + glm::quat orientation; + bool stereo; + bool ignorePenumbra; }; -Q_DECLARE_METATYPE(AudioInjectorOptions) +Q_DECLARE_METATYPE(AudioInjectorOptions); + +QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions); +void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions); #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 318db1871b..bf2c16cc53 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -11,6 +11,10 @@ #include "AudioScriptingInterface.h" +void registerAudioMetaTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); +} + AudioScriptingInterface& AudioScriptingInterface::getInstance() { static AudioScriptingInterface staticInstance; return staticInstance; @@ -40,7 +44,7 @@ void AudioScriptingInterface::stopAllInjectors() { AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { if (sound->isStereo()) { - const_cast(injectorOptions)->setIsStereo(true); + const_cast(injectorOptions)->stereo = true; } AudioInjector* injector = new AudioInjector(sound, *injectorOptions); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index ffbef646ec..a41ca645dd 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -44,4 +44,7 @@ private: QList< QPointer > _activeInjectors; AbstractAudioInterface* _localLoopbackInterface; }; + +void registerAudioMetaTypes(QScriptEngine* engine); + #endif // hifi_AudioScriptingInterface_h diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 47d1b04421..709591b62b 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -166,8 +166,8 @@ void Player::pausePlayer() { void Player::setupAudioThread() { _audioThread = new QThread(); - _options.setPosition(_avatar->getPosition()); - _options.setOrientation(_avatar->getOrientation()); + _options.position = _avatar->getPosition(); + _options.orientation = _avatar->getOrientation(); _injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater); _injector->moveToThread(_audioThread); _audioThread->start(); @@ -292,8 +292,8 @@ void Player::play() { qDebug() << "WARNING: Player couldn't find head data."; } - _options.setPosition(_avatar->getPosition()); - _options.setOrientation(_avatar->getOrientation()); + _options.position = _avatar->getPosition(); + _options.orientation = _avatar->getOrientation(); _injector->setOptions(_options); } @@ -360,7 +360,7 @@ void Player::setCurrentTime(unsigned int currentTime) { } void Player::setVolume(float volume) { - _options.setVolume(volume); + _options.volume = volume; if (_injector) { _injector->setOptions(_options); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 7445822f55..2b1acf7592 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -234,7 +234,6 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin return true; } -Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*) Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString) void ScriptEngine::init() { @@ -254,6 +253,7 @@ void ScriptEngine::init() { registerMenuItemProperties(this); registerAnimationTypes(this); registerAvatarTypes(this); + registerAudioMetaTypes(this); Bitstream::registerTypes(this); qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue); @@ -275,9 +275,6 @@ void ScriptEngine::init() { QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); globalObject().setProperty("Sound", soundMetaObject); - QScriptValue injectionOptionValue = scriptValueFromQMetaObject(); - globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); From 05174ffdf34862735e9bf5f05af12c4e24a7af5e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:26:53 -0800 Subject: [PATCH 03/24] update airGuitar.js to new AudioInjectionOptions format --- examples/airGuitar.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index c0e06add30..2c3d0409fa 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -132,15 +132,16 @@ function checkHands(deltaTime) { } function playChord(position, volume) { - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = volume; if (Audio.isInjectorPlaying(soundPlaying)) { print("stopped sound"); Audio.stopInjector(soundPlaying); } + print("Played sound: " + whichChord + " at volume " + options.volume); - soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], options); + soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], { + position: position, + volume: volume + }); } function keyPressEvent(event) { From c684a1cf006e58751d809502c402735ad22d7373 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:28:33 -0800 Subject: [PATCH 04/24] update audioBall to new hash injector format --- examples/audioBall.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/audioBall.js b/examples/audioBall.js index 7e7126be06..ca666285a9 100644 --- a/examples/audioBall.js +++ b/examples/audioBall.js @@ -32,10 +32,10 @@ function updateEntity(deltaTime) { if (Math.random() < CHANCE_OF_PLAYING_SOUND) { // play a sound at the location of the entity - var options = new AudioInjectionOptions(); - options.position = entityPosition; - options.volume = 0.75; - Audio.playSound(sound, options); + Audio.playSound(sound, { + position: entityPosition, + volume: 0.75 + }); } var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR; From 12e15eab6a831d5ab019630d8e86b801a5f122de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:29:29 -0800 Subject: [PATCH 05/24] update avatarCollision to new hash injector format --- examples/avatarCollision.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/avatarCollision.js b/examples/avatarCollision.js index 6c0886464c..4bd0adf69a 100644 --- a/examples/avatarCollision.js +++ b/examples/avatarCollision.js @@ -17,9 +17,11 @@ var SOUND_TRIGGER_CLEAR = 1000; // milliseconds var SOUND_TRIGGER_DELAY = 200; // milliseconds var soundExpiry = 0; var DateObj = new Date(); -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.5; -audioOptions.position = { x: 0, y: 0, z: 0 }; + +var audioOptions = { + volume: 0.5, + position: { x: 0, y: 0, z: 0 } +} var hitSounds = new Array(); hitSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw"); From d4b74e6ecf2380a85125af7dde5007ea037cfa1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:30:16 -0800 Subject: [PATCH 06/24] update birdSongs to new injector hash format --- examples/birdSongs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index 94e013d92b..b1ccbf8f3f 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -33,13 +33,13 @@ function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play var whichBird = Math.floor(Math.random() * birds.length); //print("playing sound # " + whichBird); - var options = new AudioInjectionOptions(); var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) }; - options.position = position; - options.volume = BIRD_MASTER_VOLUME; - // + var options = { + position: position, + volume: BIRD_MASTER_VOLUME + }; var entityId = Entities.addEntity({ type: "Sphere", position: position, From ef2c181c9808c73e1125550d87ab7f74d1a2fda9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:55:07 -0800 Subject: [PATCH 07/24] repairs to audio classes for Sound* to QScriptValue --- libraries/audio/src/AudioInjector.cpp | 8 ++++++++ libraries/audio/src/AudioInjector.h | 3 +++ libraries/audio/src/AudioScriptingInterface.cpp | 10 ++++------ libraries/audio/src/AudioScriptingInterface.h | 2 +- libraries/audio/src/Sound.cpp | 9 +++++++++ libraries/audio/src/Sound.h | 6 ++++++ libraries/script-engine/src/ScriptEngine.cpp | 8 -------- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 2d13568664..239d9eb596 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,6 +21,14 @@ #include "AudioInjector.h" +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { + return engine->newQObject(in); +} + +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { + out = qobject_cast(object.toQObject()); +} + AudioInjector::AudioInjector(QObject* parent) : QObject(parent), _sound(NULL), diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 68acd3b887..e53e2dbcad 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -50,4 +50,7 @@ private: Q_DECLARE_METATYPE(AudioInjector*) +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in); +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out); + #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index bf2c16cc53..7605b5d6af 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -13,6 +13,7 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); + qScriptRegisterMetaType(engine, soundToScriptValue, soundFromScriptValue); } AudioScriptingInterface& AudioScriptingInterface::getInstance() { @@ -23,7 +24,7 @@ AudioScriptingInterface& AudioScriptingInterface::getInstance() { AudioScriptingInterface::AudioScriptingInterface() : _localLoopbackInterface(NULL) { - qRegisterMetaType("AudioInjectorOptions"); + } void AudioScriptingInterface::stopAllInjectors() { @@ -41,12 +42,9 @@ void AudioScriptingInterface::stopAllInjectors() { } } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, AudioInjectorOptions& injectorOptions) { - if (sound->isStereo()) { - const_cast(injectorOptions)->stereo = true; - } - AudioInjector* injector = new AudioInjector(sound, *injectorOptions); + AudioInjector* injector = new AudioInjector(sound, injectorOptions); QThread* injectorThread = new QThread(); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index a41ca645dd..efcb0172c3 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,7 @@ public slots: static float getLoudness(AudioInjector* injector); - AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + AudioInjector* playSound(Sound* sound, AudioInjectorOptions& injectorOptions); void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 2266385425..bb134ad198 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -29,6 +29,15 @@ #include "AudioEditBuffer.h" #include "Sound.h" + +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in) { + return engine->newQObject(in); +} + +void soundFromScriptValue(const QScriptValue &object, Sound* &out) { + out = qobject_cast(object.toQObject()); +} + // procedural audio version of Sound Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) : QObject(parent), diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index b8fdc6b458..ade3ad324f 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -14,6 +14,7 @@ #include #include +#include class Sound : public QObject { Q_OBJECT @@ -44,4 +45,9 @@ private slots: void replyError(QNetworkReply::NetworkError code); }; +Q_DECLARE_METATYPE(Sound*) + +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in); +void soundFromScriptValue(const QScriptValue &object, Sound* &out); + #endif // hifi_Sound_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2b1acf7592..3f89cdf9ba 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -74,14 +74,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { out = qobject_cast(object.toQObject()); } -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { - return engine->newQObject(in); -} - -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { - out = qobject_cast(object.toQObject()); -} - QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { return engine->newQObject(in); } From 853c0197a178189d4c232c365bf206ab5973edbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:55:45 -0800 Subject: [PATCH 08/24] repairs to birdSongs for new hash injector format --- examples/birdSongs.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index b1ccbf8f3f..680cb025ad 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -33,20 +33,22 @@ function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play var whichBird = Math.floor(Math.random() * birds.length); //print("playing sound # " + whichBird); - var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), - y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), - z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) }; + var position = { + x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), + y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), + z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) + }; var options = { position: position, volume: BIRD_MASTER_VOLUME }; var entityId = Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }, - color: birds[whichBird].color, - lifetime: 10 - }); + type: "Sphere", + position: position, + dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }, + color: birds[whichBird].color, + lifetime: 10 + }); if (useLights) { var lightId = Entities.addEntity({ From bfc25767edc1c7732fc6401f9a3f4d96471c0bfc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:57:07 -0800 Subject: [PATCH 09/24] repairs to bot_procedrual for hash injector options format --- examples/bot_procedural.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/bot_procedural.js b/examples/bot_procedural.js index f445162038..80f83fcdfa 100644 --- a/examples/bot_procedural.js +++ b/examples/bot_procedural.js @@ -134,13 +134,11 @@ function playRandomSound() { } function playRandomFootstepSound() { - - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - var options = new AudioInjectionOptions(); - options.position = Avatar.position; - options.volume = 1.0; - Audio.playSound(footstepSounds[whichSound], options); - + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + Audio.playSound(footstepSounds[whichSound], { + position: Avatar.position, + volume: 1.0 + }); } // ************************************ Facial Animation ********************************** From 3d1bb68c725f02ff18f45753dbbb011b2e04e03e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:04:33 -0800 Subject: [PATCH 10/24] fix for playSound argument to match QScriptValue conversion --- libraries/audio/src/AudioScriptingInterface.cpp | 2 +- libraries/audio/src/AudioScriptingInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 7605b5d6af..eee43ec18c 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -42,7 +42,7 @@ void AudioScriptingInterface::stopAllInjectors() { } } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, AudioInjectorOptions& injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { AudioInjector* injector = new AudioInjector(sound, injectorOptions); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index efcb0172c3..2af690e772 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,7 @@ public slots: static float getLoudness(AudioInjector* injector); - AudioInjector* playSound(Sound* sound, AudioInjectorOptions& injectorOptions); + AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); From 89ae8f53ba2d471f57df898cf2568e062b1bc495 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:05:35 -0800 Subject: [PATCH 11/24] use new AudioInjectionOptions format in botProceduralWayPoints --- examples/botProceduralWayPoints.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/botProceduralWayPoints.js b/examples/botProceduralWayPoints.js index fc9c0dda74..0f8b369470 100644 --- a/examples/botProceduralWayPoints.js +++ b/examples/botProceduralWayPoints.js @@ -172,13 +172,11 @@ function playRandomSound() { } function playRandomFootstepSound() { - - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - var options = new AudioInjectionOptions(); - options.position = Avatar.position; - options.volume = 1.0; - Audio.playSound(footstepSounds[whichSound], options); - + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + Audio.playSound(footstepSounds[whichSound], { + position: Avatar.position, + volume: 1.0 + }); } // Facial Animation From d81609f0459709959e5cb02c4f7cab335b0a1630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:16:45 -0800 Subject: [PATCH 12/24] use hash in place of AudioInjectionOptions in other js files --- examples/clap.js | 8 +++---- examples/drumStick.js | 7 +++++-- examples/editVoxels.js | 8 ++++--- examples/entityBirds.js | 8 +++---- examples/entityScripts/playSoundOnClick.js | 9 ++++---- .../entityScripts/playSoundOnEnterOrLeave.js | 11 +++++----- examples/frisbee.js | 8 +++---- examples/grenadeLauncher.js | 5 +++-- examples/gun.js | 5 +++-- examples/headMove.js | 10 +++------ examples/inWorldTestTone.js | 8 +++---- examples/playSound.js | 11 +++++----- examples/playSoundLoop.js | 10 +++++---- examples/playSoundOrbit.js | 21 +++++++++---------- examples/playSoundWave.js | 9 ++++---- examples/radio.js | 10 +++++---- examples/spaceInvadersExample.js | 13 ++++++------ examples/toyball.js | 15 +++---------- examples/walk.js | 8 ++++--- 19 files changed, 89 insertions(+), 95 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index 9cc79a1c92..bf71f13cea 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -89,11 +89,11 @@ function maybePlaySound(deltaTime) { } function playClap(volume, position) { - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = 1.0; var clip = Math.floor(Math.random() * numberOfSounds); - Audio.playSound(claps[clip], options); + Audio.playSound(claps[clip], { + position: position, + volume: volume + }); } var FASTEST_CLAP_INTERVAL = 150.0; diff --git a/examples/drumStick.js b/examples/drumStick.js index d0560057c0..1af9ffc3dd 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -63,8 +63,11 @@ function checkSticks(deltaTime) { // Waiting for change in velocity direction or slowing to trigger drum sound if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) { state[palm] = 0; - var options = new AudioInjectionOptions(); - options.position = Controller.getSpatialControlPosition(palm * 2 + 1); + + var options = { + position: Controller.getSpatialControlPosition(palm * 2 + 1); + } + if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; } options.volume = strokeSpeed[palm]; diff --git a/examples/editVoxels.js b/examples/editVoxels.js index e450f2d1d4..0747b9269f 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -68,9 +68,11 @@ var numColors = 9; var whichColor = 0; // Starting color is 'Copy' mode // Create sounds for for every script actions that require one -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 1.0; -audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ); // start with audio slightly above the avatar +// start with audio slightly above the avatar +var audioOptions = { + position: Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ), + volume: 1.0 +}; function SoundArray() { this.audioOptions = audioOptions diff --git a/examples/entityBirds.js b/examples/entityBirds.js index bbc35a5f58..d18513ba49 100644 --- a/examples/entityBirds.js +++ b/examples/entityBirds.js @@ -135,10 +135,10 @@ function updateBirds(deltaTime) { // Tweeting behavior if (birds[i].tweeting == 0) { if (Math.random() < CHANCE_OF_TWEETING) { - var options = new AudioInjectionOptions(); - options.position = properties.position; - options.volume = 0.75; - Audio.playSound(birds[i].tweetSound, options); + Audio.playSound(birds[i].tweetSound, { + position: properties.position, + volume: 0.75 + }); birds[i].tweeting = 10; } } else { diff --git a/examples/entityScripts/playSoundOnClick.js b/examples/entityScripts/playSoundOnClick.js index b261bb269a..fea68db2c3 100644 --- a/examples/entityScripts/playSoundOnClick.js +++ b/examples/entityScripts/playSoundOnClick.js @@ -15,10 +15,9 @@ var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); this.clickDownOnEntity = function(entityID, mouseEvent) { print("clickDownOnEntity()..."); - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); }; }) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index 228a8a36d0..ab8bcbd2bd 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -14,12 +14,11 @@ (function(){ var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); - function playSound(entityID) { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + function playSound(entityID) { + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); }; this.enterEntity = function(entityID) { diff --git a/examples/frisbee.js b/examples/frisbee.js index c534a8b3fb..7e266de34b 100644 --- a/examples/frisbee.js +++ b/examples/frisbee.js @@ -177,10 +177,10 @@ function playSound(sound, position) { if (!SOUNDS_ENABLED) { return; } - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = 1.0; - Audio.playSound(sound, options); + + Audio.playSound(sound,{ + position: position + }); } function cleanupFrisbees() { diff --git a/examples/grenadeLauncher.js b/examples/grenadeLauncher.js index bca067326a..e95d8dd79d 100644 --- a/examples/grenadeLauncher.js +++ b/examples/grenadeLauncher.js @@ -44,8 +44,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/ var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.9; +var audioOptions { + volume: 0.9 +} var shotsFired = 0; diff --git a/examples/gun.js b/examples/gun.js index 385664226c..76084ce013 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -43,8 +43,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/ var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.9; +var audioOptions = { + volume: 0.9 +} var shotsFired = 0; diff --git a/examples/headMove.js b/examples/headMove.js index b1f1c4ab7d..957686bb20 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -72,15 +72,11 @@ var WATCH_AVATAR_DISTANCE = 2.5; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); function playSound() { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 1.0; - Audio.playSound(sound, options); + Audio.playSound(sound, { + position: MyAvatar.position + }); } - - function pullBack() { saveCameraState(); cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -hipsToEyes, z: -hipsToEyes * WATCH_AVATAR_DISTANCE })); diff --git a/examples/inWorldTestTone.js b/examples/inWorldTestTone.js index 590bb6c342..b3bf91d14d 100644 --- a/examples/inWorldTestTone.js +++ b/examples/inWorldTestTone.js @@ -19,11 +19,9 @@ var soundPlaying = false; function update(deltaTime) { if (!Audio.isInjectorPlaying(soundPlaying)) { - var options = new AudioInjectionOptions(); - options.position = { x:0, y:0, z:0 }; - options.volume = 1.0; - options.loop = true; - soundPlaying = Audio.playSound(sound, options); + soundPlaying = Audio.playSound(sound, { + loop: true + }); print("Started sound loop"); } } diff --git a/examples/playSound.js b/examples/playSound.js index 4130db5b16..efcda0b42b 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -15,12 +15,11 @@ var bird = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); function maybePlaySound(deltaTime) { if (Math.random() < 0.01) { - // Set the location and other info for the sound to play - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + // Set the location and other info for the sound to play + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); } } diff --git a/examples/playSoundLoop.js b/examples/playSoundLoop.js index 3122f13f37..b84c475d1a 100644 --- a/examples/playSoundLoop.js +++ b/examples/playSoundLoop.js @@ -20,10 +20,12 @@ var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw" //var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav"); var soundPlaying = false; -var options = new AudioInjectionOptions(); -options.position = Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation)); -options.volume = 0.5; -options.loop = true; +var options = { + position: Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation)), + volume: 0.5, + loop: true +} + var playing = false; var ball = false; diff --git a/examples/playSoundOrbit.js b/examples/playSoundOrbit.js index 2c44a4535a..d98f7d0768 100644 --- a/examples/playSoundOrbit.js +++ b/examples/playSoundOrbit.js @@ -19,24 +19,23 @@ var distance = 1; var debug = 0; function playSound() { - var options = new AudioInjectionOptions(); - currentTime += deltaTime; + currentTime += deltaTime; var s = distance * Math.sin(currentTime); var c = distance * Math.cos(currentTime); - var soundOffset = { x:s, y:0, z:c }; + var soundOffset = { x:s, y:0, z:c }; - if (debug) { - print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z); - } + if (debug) { + print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z); + } - var avatarPosition = MyAvatar.position; - var soundPosition = Vec3.sum(avatarPosition,soundOffset); + var avatarPosition = MyAvatar.position; + var soundPosition = Vec3.sum(avatarPosition,soundOffset); - options.position = soundPosition - options.volume = 1.0; - Audio.playSound(soundClip, options); + Audio.playSound(soundClip, { + position: soundPosition + }); } Script.setInterval(playSound, 250); diff --git a/examples/playSoundWave.js b/examples/playSoundWave.js index f152effb47..c5e69f5cd6 100644 --- a/examples/playSoundWave.js +++ b/examples/playSoundWave.js @@ -14,11 +14,10 @@ Script.include("libraries/globals.js"); var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav"); function playSound() { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(soundClip, options); + Audio.playSound(soundClip, { + position: MyAvatar.position, + volume: 0.5 + }); } Script.setInterval(playSound, 10000); diff --git a/examples/radio.js b/examples/radio.js index 293867398a..fc09fb184e 100644 --- a/examples/radio.js +++ b/examples/radio.js @@ -15,10 +15,12 @@ var modelURL = HIFI_PUBLIC_BUCKET + "models/entities/radio/Speakers.fbx"; var soundURL = HIFI_PUBLIC_BUCKET + "sounds/FamilyStereo.raw"; var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0); -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.5; -audioOptions.loop = true; -audioOptions.isStereo = true; +var audioOptions = { + volume: 0.5, + loop: true, + stereo: true +} + var injector = null; var sound = new Sound(soundURL, audioOptions.isStereo); diff --git a/examples/spaceInvadersExample.js b/examples/spaceInvadersExample.js index 8d69f066d6..dd5ac9e875 100644 --- a/examples/spaceInvadersExample.js +++ b/examples/spaceInvadersExample.js @@ -217,7 +217,8 @@ function update(deltaTime) { if (invaderStepOfCycle % stepsPerSound == 0) { // play the move sound - var options = new AudioInjectionOptions(); + var options = {}; + if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -225,7 +226,7 @@ function update(deltaTime) { } else { options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2); } - options.volume = 1.0; + Audio.playSound(moveSounds[currentMoveSound], options); // get ready for next move sound @@ -330,7 +331,7 @@ function fireMissile() { lifetime: 5 }); - var options = new AudioInjectionOptions(); + var options = {} if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -338,7 +339,7 @@ function fireMissile() { } else { options.position = missilePosition; } - options.volume = 1.0; + Audio.playSound(shootSound, options); missileFired = true; @@ -380,7 +381,7 @@ function deleteIfInvader(possibleInvaderEntity) { Entities.deleteEntity(myMissile); // play the hit sound - var options = new AudioInjectionOptions(); + var options = {}; if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -388,7 +389,7 @@ function deleteIfInvader(possibleInvaderEntity) { } else { options.position = getInvaderPosition(row, column); } - options.volume = 1.0; + Audio.playSound(hitSound, options); } } diff --git a/examples/toyball.js b/examples/toyball.js index b41dd2bda5..1cd6de16eb 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -113,10 +113,7 @@ function checkControllerSide(whichSide) { inHand: true }; Entities.editEntity(closestEntity, properties); - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); + Audio.playSound(catchSound, { position: ballPosition }); return; // exit early } @@ -156,10 +153,7 @@ function checkControllerSide(whichSide) { } // Play a new ball sound - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(newSound, options); + Audio.playSound(newSound, { position: ballPosition}); return; // exit early } @@ -207,10 +201,7 @@ function checkControllerSide(whichSide) { rightHandEntity = false; } - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(throwSound, options); + Audio.playSound(throwSound, { position: ballPosition }); } } } diff --git a/examples/walk.js b/examples/walk.js index a9e8f401d6..ac0a2b1d39 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -285,9 +285,11 @@ function resetJoints() { // play footstep sound function playFootstep(side) { - var options = new AudioInjectionOptions(); - options.position = Camera.getPosition(); - options.volume = 0.5; + var options = { + position: Camera.getPosition(), + volume: 0.5 + } + var walkNumber = 2; // 0 to 2 if(side===DIRECTION_RIGHT && playFootStepSounds) { Audio.playSound(footsteps[walkNumber+1], options); From 1f452c8baa3050bd6eb5fa2ad1b8b36edc432630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:17:45 -0800 Subject: [PATCH 13/24] replace AudioInjectionOptions with hash in playSoundOnEnterOrLeave --- examples/entityScripts/playSoundOnEnterOrLeave.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index ab8bcbd2bd..6ee961af0a 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -25,7 +25,7 @@ playSound(); }; - this.leaveEntity = function(entityID) { + this.leaveEntity = function(entityID) { playSound(); }; }) From d0e8c294dab7fb2549fc0aa02b0caa3e240fd872 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:22:16 -0800 Subject: [PATCH 14/24] handle passing of local audio interface to AudioInjector --- interface/src/Application.cpp | 2 +- libraries/audio/src/AudioInjector.h | 5 +++++ libraries/audio/src/AudioScriptingInterface.cpp | 3 ++- libraries/audio/src/AudioScriptingInterface.h | 6 ++---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7f80407a6b..77cfcfd548 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -417,7 +417,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon->show(); // set the local loopback interface for local sounds from audio scripts - AudioScriptingInterface::getInstance().setLocalLoopbackInterface(&_audio); + AudioScriptingInterface::getInstance().setLocalAudioInterface(&_audio); #ifdef HAVE_RTMIDI // setup the MIDIManager diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index e53e2dbcad..12e4c62d5d 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -21,6 +21,8 @@ #include "AudioInjectorOptions.h" #include "Sound.h" +class AbstractAudioInterface; + class AudioInjector : public QObject { Q_OBJECT public: @@ -29,6 +31,8 @@ public: bool isFinished() const { return _isFinished; } int getCurrentSendPosition() const { return _currentSendPosition; } + + void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); void stop() { _shouldStop = true; } @@ -45,6 +49,7 @@ private: float _loudness; bool _isFinished; int _currentSendPosition; + AbstractAudioInterface* _localAudioInterface; }; diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index eee43ec18c..cb010ef11d 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -22,7 +22,7 @@ AudioScriptingInterface& AudioScriptingInterface::getInstance() { } AudioScriptingInterface::AudioScriptingInterface() : - _localLoopbackInterface(NULL) + _localAudioInterface(NULL) { } @@ -45,6 +45,7 @@ void AudioScriptingInterface::stopAllInjectors() { AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { AudioInjector* injector = new AudioInjector(sound, injectorOptions); + injector->setLocalAudioInterface(_localAudioInterface); QThread* injectorThread = new QThread(); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 2af690e772..0017806b40 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -18,8 +18,6 @@ #include "AudioInjector.h" #include "Sound.h" -const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; - class AudioScriptingInterface : public QObject { Q_OBJECT public: @@ -27,7 +25,7 @@ public: void stopAllInjectors(); - void setLocalLoopbackInterface(AbstractAudioInterface* audioInterface) { _localLoopbackInterface = audioInterface; } + void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } public slots: static float getLoudness(AudioInjector* injector); @@ -42,7 +40,7 @@ public slots: private: AudioScriptingInterface(); QList< QPointer > _activeInjectors; - AbstractAudioInterface* _localLoopbackInterface; + AbstractAudioInterface* _localAudioInterface; }; void registerAudioMetaTypes(QScriptEngine* engine); From cd3877b5847301e213fb0dbe3a81a436666c097e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 14:14:43 -0800 Subject: [PATCH 15/24] handle local audio output via AudioInjector directly for control --- examples/lobby.js | 6 +++- interface/src/Audio.cpp | 9 ++++-- interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/audio/src/AudioInjector.cpp | 30 +++++++++++++++++++- libraries/audio/src/AudioInjector.h | 3 ++ libraries/audio/src/AudioInjectorOptions.cpp | 8 +++++- libraries/audio/src/AudioInjectorOptions.h | 1 + 8 files changed, 53 insertions(+), 8 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 63ea1654a9..e6db57bdd5 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -37,7 +37,8 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; -var HELMET_ATTACHMENT_URL = "https://hifi-public.s3.amazonaws.com/models/attachments/IronManMaskOnly.fbx" +var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -87,6 +88,9 @@ function drawLobby() { // add an attachment on this avatar so other people see them in the lobby MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); + + // start the drone sound + Audio.playSound(droneSound, { stereo: true, localOnly: true }); } } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 3289e64ed4..58c3972bcb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,10 +1334,13 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QAudioOutput* Audio::newLocalOutputInterface(bool isStereo) { - QAudioFormat localFormat = _outputFormat; +QIODevice* Audio::newLocalOutputDevice(bool isStereo) { + QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); - return new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat); + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), + localFormat); + + return localOutput->start(); } void Audio::renderToolBox(int x, int y, bool boxed) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 02ea6db498..83688cf84a 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QAudioOutput* newLocalOutputInterface(bool isStereo); + virtual QIODevice* newLocalOutputDevice(bool isStereo); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 82710277b3..e413bfc8f1 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -25,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QAudioOutput* newLocalOutputInterface(bool isStereo) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 239d9eb596..9b2720b90c 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -58,9 +58,37 @@ float AudioInjector::getLoudness() { return _loudness; } +void AudioInjector::injectAudio() { + if (_options.localOnly) { + injectLocally(); + } else { + injectToMixer(); + } +} + +void AudioInjector::injectLocally() { + if (_localAudioInterface) { + + QIODevice* localBuffer = NULL; + + QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QIODevice*, localBuffer), + Q_ARG(bool, _options.stereo)); + + if (localBuffer) { + // immediately write the byte array to the local device + localBuffer->write(_sound->getByteArray()); + } else { + qDebug() << "AudioInject::injectLocally did not get a valid QIODevice from _localAudioInterface"; + } + } else { + qDebug() << "AudioInject::injectLocally cannot inject locally with no local audio interface present."; + } +} + const uchar MAX_INJECTOR_VOLUME = 0xFF; -void AudioInjector::injectAudio() { +void AudioInjector::injectToMixer() { QByteArray soundByteArray = _sound->getByteArray(); if (_currentSendPosition < 0 || diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 12e4c62d5d..5a0a35d599 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -43,6 +43,9 @@ public slots: signals: void finished(); private: + void injectToMixer(); + void injectLocally(); + Sound* _sound; AudioInjectorOptions _options; bool _shouldStop; diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 2a532b92b7..df435cf2cc 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -19,7 +19,8 @@ AudioInjectorOptions::AudioInjectorOptions() : loop(false), orientation(glm::vec3(0.0f, 0.0f, 0.0f)), stereo(false), - ignorePenumbra(false) + ignorePenumbra(false), + localOnly(false) { } @@ -32,6 +33,7 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); obj.setProperty("stereo", injectorOptions.stereo); obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + obj.setProperty("localOnly", injectorOptions.localOnly); return obj; } @@ -59,4 +61,8 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt if (object.property("ignorePenumbra").isValid()) { injectorOptions.ignorePenumbra = object.property("ignorePenumbra").toBool(); } + + if (object.property("localOnly").isValid()) { + injectorOptions.localOnly = object.property("localOnly").toBool(); + } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index c3e2da991a..4fd3a0b7ae 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -26,6 +26,7 @@ public: glm::quat orientation; bool stereo; bool ignorePenumbra; + bool localOnly; }; Q_DECLARE_METATYPE(AudioInjectorOptions); From 83529c1fed313ebee6c7fed182cf097cb7dd672e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 14:45:33 -0800 Subject: [PATCH 16/24] fix QIODevice fail in AudioInjector by passing explicit size --- interface/src/Audio.cpp | 6 +++-- interface/src/Audio.h | 6 +---- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/audio/src/AudioInjector.cpp | 25 +++++++++++++------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 58c3972bcb..8fecb4ee8e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,11 +1334,13 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo) { +QIODevice* Audio::newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) { QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), - localFormat); + localFormat, this); + localOutput->setBufferSize(numBytes); return localOutput->start(); } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 83688cf84a..460be0a567 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo); + virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector); void sendDownstreamAudioStatsPacket(); @@ -256,10 +256,6 @@ private: float _iconColor; qint64 _iconPulseTimeReference; - /// Audio callback in class context. - inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); - - bool _processSpatialAudio; /// Process received audio by spatial audio hooks unsigned int _spatialAudioStart; /// Start of spatial audio interval (in sample rate time base) unsigned int _spatialAudioFinish; /// End of spatial audio interval (in sample rate time base) diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index e413bfc8f1..5b42108430 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -25,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 9b2720b90c..e83cd5350a 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -71,18 +71,27 @@ void AudioInjector::injectLocally() { QIODevice* localBuffer = NULL; - QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, localBuffer), - Q_ARG(bool, _options.stereo)); + const QByteArray& soundByteArray = _sound->getByteArray(); - if (localBuffer) { - // immediately write the byte array to the local device - localBuffer->write(_sound->getByteArray()); + if (soundByteArray.size() > 0) { + QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QIODevice*, localBuffer), + Q_ARG(bool, _options.stereo), + Q_ARG(int, soundByteArray.size()), + Q_ARG(QObject*, this)); + + if (localBuffer) { + // immediately write the byte array to the local device + qDebug() << "Writing" << localBuffer->write(soundByteArray) << "bytes to local audio device"; + } else { + qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; + } } else { - qDebug() << "AudioInject::injectLocally did not get a valid QIODevice from _localAudioInterface"; + qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray"; } + } else { - qDebug() << "AudioInject::injectLocally cannot inject locally with no local audio interface present."; + qDebug() << "AudioInjector::injectLocally cannot inject locally with no local audio interface present."; } } From 0e30c65e60b85577d617cd95fbb3a7c99ef90b6a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 15:12:11 -0800 Subject: [PATCH 17/24] handle cleanup of local injection, volume --- examples/lobby.js | 6 ++++- interface/src/Application.cpp | 9 +++---- interface/src/Audio.cpp | 26 +++++++++++++++--- interface/src/Audio.h | 8 +++--- libraries/audio/src/AbstractAudioInterface.h | 4 ++- libraries/audio/src/AudioInjector.cpp | 28 +++++++++++++------- libraries/audio/src/AudioInjector.h | 4 +-- 7 files changed, 60 insertions(+), 25 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index e6db57bdd5..c921e744f1 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,6 +39,7 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") +var currentDrone; function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -90,7 +91,7 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - Audio.playSound(droneSound, { stereo: true, localOnly: true }); + currentDrone = Audio.playSound(droneSound, { stereo: true, localOnly: true }); } } @@ -121,6 +122,9 @@ function cleanupLobby() { Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); + currentDrone.stop(); + currentDrone = null; + panelWall = false; orbShell = false; reticle = false; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 77cfcfd548..d2d5ff2480 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -453,23 +453,22 @@ Application::~Application() { // ask the datagram processing thread to quit and wait until it is done _nodeThread->quit(); _nodeThread->wait(); + + // kill any audio injectors that are still around + AudioScriptingInterface::getInstance().stopAllInjectors(); // stop the audio process QMetaObject::invokeMethod(&_audio, "stop"); - + // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); _audio.thread()->wait(); - - // kill any audio injectors that are still around - AudioScriptingInterface::getInstance().stopAllInjectors(); _octreeProcessor.terminate(); _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); _entityEditSender.terminate(); - VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8fecb4ee8e..08a29a08ff 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -32,19 +32,21 @@ #include #include +#include + +#include #include #include #include #include #include -#include - -#include "Audio.h" #include "Menu.h" #include "Util.h" #include "PositionalAudioStream.h" +#include "Audio.h" + static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; @@ -1334,17 +1336,33 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) { +QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) { QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); localOutput->setBufferSize(numBytes); + localOutput->setVolume(volume); + + // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done + _injectedOutputInterfaces.insert(injector, localOutput); + + connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); return localOutput->start(); } +void Audio::cleanupLocalOutputInterface() { + QAudioOutput* outputInterface = _injectedOutputInterfaces.value(sender()); + if (outputInterface) { + qDebug() << "Stopping a QAudioOutput interface since injector" << sender() << "is finished"; + + outputInterface->stop(); + outputInterface->deleteLater(); + } +} + void Audio::renderToolBox(int x, int y, bool boxed) { glEnable(GL_TEXTURE_2D); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 460be0a567..cc404723d8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector); + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector); void sendDownstreamAudioStatsPacket(); @@ -180,11 +180,11 @@ signals: void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); +private slots: + void cleanupLocalOutputInterface(); private: void outputFormatChanged(); -private: - QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; @@ -365,6 +365,8 @@ private: AudioOutputIODevice _audioOutputIODevice; WeakRecorderPointer _recorder; + + QHash _injectedOutputInterfaces; }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 5b42108430..104abae554 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -17,6 +17,8 @@ #include "AudioInjectorOptions.h" +class AudioInjector; + class AbstractAudioInterface : public QObject { Q_OBJECT public: @@ -25,7 +27,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e83cd5350a..a0914ca741 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -36,7 +36,8 @@ AudioInjector::AudioInjector(QObject* parent) : _shouldStop(false), _loudness(0.0f), _isFinished(false), - _currentSendPosition(0) + _currentSendPosition(0), + _localDevice(NULL) { } @@ -67,22 +68,21 @@ void AudioInjector::injectAudio() { } void AudioInjector::injectLocally() { - if (_localAudioInterface) { - - QIODevice* localBuffer = NULL; - + if (_localAudioInterface) { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, localBuffer), + Q_RETURN_ARG(QIODevice*, _localDevice), Q_ARG(bool, _options.stereo), + Q_ARG(qreal, _options.volume), Q_ARG(int, soundByteArray.size()), - Q_ARG(QObject*, this)); + Q_ARG(AudioInjector*, this)); - if (localBuffer) { + if (_localDevice) { // immediately write the byte array to the local device - qDebug() << "Writing" << localBuffer->write(soundByteArray) << "bytes to local audio device"; + qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device"; + _localDevice->write(soundByteArray); } else { qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; } @@ -220,3 +220,13 @@ void AudioInjector::injectToMixer() { _isFinished = true; emit finished(); } + +void AudioInjector::stop() { + _shouldStop = true; + + if (_localDevice) { + // we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up + _isFinished = true; + emit finished(); + } +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 5a0a35d599..98d391e494 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -35,7 +35,7 @@ public: void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); - void stop() { _shouldStop = true; } + void stop(); void setOptions(AudioInjectorOptions& options); void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness(); @@ -53,7 +53,7 @@ private: bool _isFinished; int _currentSendPosition; AbstractAudioInterface* _localAudioInterface; - + QIODevice* _localDevice; }; Q_DECLARE_METATYPE(AudioInjector*) From a5a02b5f8a5c6d80a43aa97bd543f08c708c5f27 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:34:00 -0800 Subject: [PATCH 18/24] add AudioInjectorLocalBuffer for more control --- examples/lobby.js | 3 +- interface/src/Audio.cpp | 32 ++++++++------ interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 3 +- libraries/audio/src/AudioInjector.cpp | 42 ++++++++++++------ libraries/audio/src/AudioInjector.h | 7 ++- .../audio/src/AudioInjectorLocalBuffer.cpp | 43 +++++++++++++++++++ .../audio/src/AudioInjectorLocalBuffer.h | 35 +++++++++++++++ 8 files changed, 136 insertions(+), 31 deletions(-) create mode 100644 libraries/audio/src/AudioInjectorLocalBuffer.cpp create mode 100644 libraries/audio/src/AudioInjectorLocalBuffer.h diff --git a/examples/lobby.js b/examples/lobby.js index c921e744f1..eb2611fd29 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -38,7 +38,8 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" -var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") + +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") var currentDrone; function reticlePosition() { diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 08a29a08ff..a5f6bd897f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1336,21 +1336,25 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) { - QAudioFormat localFormat = _desiredOutputFormat; - localFormat.setChannelCount(isStereo ? 2 : 1); +bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) { + if (injector->getLocalBuffer()) { + QAudioFormat localFormat = _desiredOutputFormat; + localFormat.setChannelCount(isStereo ? 2 : 1); + + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), + localFormat, this); + localOutput->setVolume(volume); + + // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done + _injectedOutputInterfaces.insert(injector, localOutput); + + connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); + + localOutput->start(injector->getLocalBuffer()); + return localOutput->state() == QAudio::ActiveState; + } - QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), - localFormat, this); - localOutput->setBufferSize(numBytes); - localOutput->setVolume(volume); - - // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done - _injectedOutputInterfaces.insert(injector, localOutput); - - connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); - - return localOutput->start(); + return false; } void Audio::cleanupLocalOutputInterface() { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index cc404723d8..d6e26864e6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector); + virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 104abae554..b5a7be9849 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -18,6 +18,7 @@ #include "AudioInjectorOptions.h" class AudioInjector; +class AudioInjectorLocalBuffer; class AbstractAudioInterface : public QObject { Q_OBJECT @@ -27,7 +28,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0; + virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index a0914ca741..ddd4f05630 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -37,7 +37,7 @@ AudioInjector::AudioInjector(QObject* parent) : _loudness(0.0f), _isFinished(false), _currentSendPosition(0), - _localDevice(NULL) + _localBuffer(NULL) { } @@ -47,10 +47,17 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO _shouldStop(false), _loudness(0.0f), _isFinished(false), - _currentSendPosition(0) + _currentSendPosition(0), + _localBuffer(NULL) { } +AudioInjector::~AudioInjector() { + if (_localBuffer) { + _localBuffer->stop(); + } +} + void AudioInjector::setOptions(AudioInjectorOptions& options) { _options = options; } @@ -72,19 +79,25 @@ void AudioInjector::injectLocally() { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { - QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, _localDevice), + bool successfulOutput = false; + + _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); + _localBuffer->open(QIODevice::ReadOnly); + _localBuffer->setIsLooping(_options.loop); + + qDebug() << "Passing off AudioInjectorLocatBuffer to localAudioInterface"; + + QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, successfulOutput), Q_ARG(bool, _options.stereo), Q_ARG(qreal, _options.volume), - Q_ARG(int, soundByteArray.size()), Q_ARG(AudioInjector*, this)); - if (_localDevice) { - // immediately write the byte array to the local device - qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device"; - _localDevice->write(soundByteArray); - } else { - qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; + + + if (!successfulOutput) { + qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; } } else { qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray"; @@ -224,8 +237,11 @@ void AudioInjector::injectToMixer() { void AudioInjector::stop() { _shouldStop = true; - if (_localDevice) { - // we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up + if (_localBuffer) { + // we're only a local injector, so we can say we are finished right away too + + _localBuffer->stop(); + _isFinished = true; emit finished(); } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 98d391e494..607aeb500e 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -18,6 +18,7 @@ #include #include +#include "AudioInjectorLocalBuffer.h" #include "AudioInjectorOptions.h" #include "Sound.h" @@ -28,10 +29,14 @@ class AudioInjector : public QObject { public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); + ~AudioInjector(); bool isFinished() const { return _isFinished; } int getCurrentSendPosition() const { return _currentSendPosition; } + AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; } + bool isLocalOnly() const { return _options.localOnly; } + void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); @@ -53,7 +58,7 @@ private: bool _isFinished; int _currentSendPosition; AbstractAudioInterface* _localAudioInterface; - QIODevice* _localDevice; + AudioInjectorLocalBuffer* _localBuffer; }; Q_DECLARE_METATYPE(AudioInjector*) diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp new file mode 100644 index 0000000000..19c92276f9 --- /dev/null +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -0,0 +1,43 @@ +// +// AudioInjectorLocalBuffer.cpp +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-11. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AudioInjectorLocalBuffer.h" + +AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) : + QIODevice(parent), + _rawAudioArray(rawAudioArray), + _isLooping(false), + _isStopped(false) +{ + +} + +void AudioInjectorLocalBuffer::stop() { + _isStopped = true; + QIODevice::close(); +} + +qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { + if (!_isStopped) { + int bytesToEnd = _rawAudioArray.size() - pos(); + + int bytesToRead = maxSize; + + if (maxSize > bytesToEnd) { + bytesToRead = bytesToEnd; + } + + memcpy(data, _rawAudioArray.data() + pos(), bytesToRead); + return bytesToRead; + } else { + return 0; + } +} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h new file mode 100644 index 0000000000..6d234066ef --- /dev/null +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -0,0 +1,35 @@ +// +// AudioInjectorLocalBuffer.h +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-11. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioInjectorLocalBuffer_h +#define hifi_AudioInjectorLocalBuffer_h + +#include + +class AudioInjectorLocalBuffer : public QIODevice { + Q_OBJECT +public: + AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent); + + void stop(); + + qint64 readData(char* data, qint64 maxSize); + qint64 writeData(const char* data, qint64 maxSize) { return 0; } + + void setIsLooping(bool isLooping) { _isLooping = isLooping; } + +private: + QByteArray _rawAudioArray; + bool _isLooping; + bool _isStopped; +}; + +#endif // hifi_AudioInjectorLocalBuffer_h \ No newline at end of file From cb5d5dd3a8ba3b879811361406b0d1422478c6cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:57:25 -0800 Subject: [PATCH 19/24] handle looping via AudioInjectorLocalBuffer --- examples/lobby.js | 2 +- libraries/audio/src/AudioInjector.cpp | 4 +- .../audio/src/AudioInjectorLocalBuffer.cpp | 45 ++++++++++++++++--- .../audio/src/AudioInjectorLocalBuffer.h | 9 +++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index eb2611fd29..682e8dbd80 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -92,7 +92,7 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - currentDrone = Audio.playSound(droneSound, { stereo: true, localOnly: true }); + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true }); } } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index ddd4f05630..6716d525da 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -83,9 +83,7 @@ void AudioInjector::injectLocally() { _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); _localBuffer->open(QIODevice::ReadOnly); - _localBuffer->setIsLooping(_options.loop); - - qDebug() << "Passing off AudioInjectorLocatBuffer to localAudioInterface"; + _localBuffer->setShouldLoop(_options.loop); QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", Qt::BlockingQueuedConnection, diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp index 19c92276f9..bdf084091d 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.cpp +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -14,8 +14,9 @@ AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) : QIODevice(parent), _rawAudioArray(rawAudioArray), - _isLooping(false), - _isStopped(false) + _shouldLoop(false), + _isStopped(false), + _currentOffset(0) { } @@ -27,17 +28,47 @@ void AudioInjectorLocalBuffer::stop() { qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { if (!_isStopped) { - int bytesToEnd = _rawAudioArray.size() - pos(); - int bytesToRead = maxSize; + // first copy to the end of the raw audio + int bytesToEnd = _rawAudioArray.size() - _currentOffset; + + int bytesRead = maxSize; if (maxSize > bytesToEnd) { - bytesToRead = bytesToEnd; + bytesRead = bytesToEnd; } - memcpy(data, _rawAudioArray.data() + pos(), bytesToRead); - return bytesToRead; + memcpy(data, _rawAudioArray.data() + _currentOffset, bytesRead); + + // now check if we are supposed to loop and if we can copy more from the beginning + if (_shouldLoop && maxSize != bytesRead) { + bytesRead += recursiveReadFromFront(data + bytesRead, maxSize - bytesRead); + } else { + _currentOffset += bytesRead; + } + + return bytesRead; } else { return 0; } +} + +qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSize) { + // see how much we can get in this pass + int bytesRead = maxSize; + + if (bytesRead > _rawAudioArray.size()) { + bytesRead = _rawAudioArray.size(); + } + + // copy that amount + memcpy(data, _rawAudioArray.data(), bytesRead); + + // check if we need to call ourselves again and pull from the front again + if (bytesRead < maxSize) { + return bytesRead + recursiveReadFromFront(data, maxSize); + } else { + _currentOffset = bytesRead; + return bytesRead; + } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h index 6d234066ef..8b32c6fbc7 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.h +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -24,12 +24,17 @@ public: qint64 readData(char* data, qint64 maxSize); qint64 writeData(const char* data, qint64 maxSize) { return 0; } - void setIsLooping(bool isLooping) { _isLooping = isLooping; } + void setShouldLoop(bool shouldLoop) { _shouldLoop = shouldLoop; } private: + + qint64 recursiveReadFromFront(char* data, qint64 maxSize); + QByteArray _rawAudioArray; - bool _isLooping; + bool _shouldLoop; bool _isStopped; + + int _currentOffset; }; #endif // hifi_AudioInjectorLocalBuffer_h \ No newline at end of file From 04335862938ce81cd270ff2a344394307746fa8d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:59:15 -0800 Subject: [PATCH 20/24] switch lobby noise back to drone --- examples/lobby.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lobby.js b/examples/lobby.js index 682e8dbd80..89a6b69776 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,7 +39,7 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" -var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") var currentDrone; function reticlePosition() { From 7f79f0946d57df39975911011966c6af2605de3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 17:10:25 -0800 Subject: [PATCH 21/24] play a random musak song in lobby when it is shown --- examples/lobby.js | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 89a6b69776..02d74a0cd7 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -40,7 +40,11 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") -var currentDrone; +var currentDrone = null; + +var latinSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") +var elevatorSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.raw") +var currentMusak = null; function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -93,6 +97,9 @@ function drawLobby() { // start the drone sound currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true }); + + // start one of our musak sounds + playRandomMusak(); } } @@ -118,13 +125,38 @@ function changeLobbyTextures() { Overlays.editOverlay(panelWall, textureProp); } +function playRandomMusak() { + chosenSound = null; + + if (latinSound.downloaded && elevatorSound.downloaded) { + chosenSound = Math.random < 0.5 ? latinSound : elevatorSound; + } else if (latinSound.downloaded) { + chosenSound = latinSound; + } else if (elevator.downloaded) { + chosenSound = elevatorSound; + } + + if (chosenSound) { + currentMusak = Audio.playSound(chosenSound, { stereo: true, localOnly: true }) + } else { + currentMusak = null; + } +} + function cleanupLobby() { Overlays.deleteOverlay(panelWall); Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); - currentDrone.stop(); - currentDrone = null; + if (currentDrone) { + currentDrone.stop(); + currentDrone = null; + } + + if (currentMusak) { + currentMusak.stop(); + currentMusak = null; + } panelWall = false; orbShell = false; From 9aa950e65740f6aecbe0008f2dd5a9ea12f1b5f8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 17:34:03 -0800 Subject: [PATCH 22/24] fix audio injector cleanup for local only injectors --- examples/lobby.js | 14 +++++--------- libraries/audio/src/AudioInjector.cpp | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 02d74a0cd7..1b6596efa7 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -132,7 +132,7 @@ function playRandomMusak() { chosenSound = Math.random < 0.5 ? latinSound : elevatorSound; } else if (latinSound.downloaded) { chosenSound = latinSound; - } else if (elevator.downloaded) { + } else if (elevatorSound.downloaded) { chosenSound = elevatorSound; } @@ -148,15 +148,11 @@ function cleanupLobby() { Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); - if (currentDrone) { - currentDrone.stop(); - currentDrone = null; - } + Audio.stopInjector(currentDrone); + currentDrone = null; - if (currentMusak) { - currentMusak.stop(); - currentMusak = null; - } + Audio.stopInjector(currentMusak); + currentMusak = null; panelWall = false; orbShell = false; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 6716d525da..fcd2127d4f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -75,26 +75,25 @@ void AudioInjector::injectAudio() { } void AudioInjector::injectLocally() { + bool success = false; if (_localAudioInterface) { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { - bool successfulOutput = false; - _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); _localBuffer->open(QIODevice::ReadOnly); _localBuffer->setShouldLoop(_options.loop); QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, successfulOutput), + Q_RETURN_ARG(bool, success), Q_ARG(bool, _options.stereo), Q_ARG(qreal, _options.volume), Q_ARG(AudioInjector*, this)); - if (!successfulOutput) { + if (!success) { qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; } } else { @@ -104,6 +103,12 @@ void AudioInjector::injectLocally() { } else { qDebug() << "AudioInjector::injectLocally cannot inject locally with no local audio interface present."; } + + if (!success) { + // we never started so we are finished, call our stop method + stop(); + } + } const uchar MAX_INJECTOR_VOLUME = 0xFF; @@ -235,11 +240,8 @@ void AudioInjector::injectToMixer() { void AudioInjector::stop() { _shouldStop = true; - if (_localBuffer) { + if (_options.localOnly) { // we're only a local injector, so we can say we are finished right away too - - _localBuffer->stop(); - _isFinished = true; emit finished(); } From 9a45a707649d81140adf21af2b14a5f3467739c0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 20:47:40 -0800 Subject: [PATCH 23/24] repairs to Sound script conversion typos --- libraries/audio/src/Sound.cpp | 4 ++-- libraries/audio/src/Sound.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index bb134ad198..4c520f27ce 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -30,11 +30,11 @@ #include "Sound.h" -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in) { +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in) { return engine->newQObject(in); } -void soundFromScriptValue(const QScriptValue &object, Sound* &out) { +void soundFromScriptValue(const QScriptValue& object, Sound*& out) { out = qobject_cast(object.toQObject()); } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index ade3ad324f..f7b51891f0 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -47,7 +47,7 @@ private slots: Q_DECLARE_METATYPE(Sound*) -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in); -void soundFromScriptValue(const QScriptValue &object, Sound* &out); +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in); +void soundFromScriptValue(const QScriptValue& object, Sound*& out); #endif // hifi_Sound_h From ed9a2bf676010e7d374b5973ac0a16f68a51c7d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 20:48:34 -0800 Subject: [PATCH 24/24] fix for AudioInjector QScriptValue conversion typos --- libraries/audio/src/AudioInjector.cpp | 4 ++-- libraries/audio/src/AudioInjector.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fcd2127d4f..1743504883 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,11 +21,11 @@ #include "AudioInjector.h" -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) { return engine->newQObject(in); } -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { +void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) { out = qobject_cast(object.toQObject()); } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 607aeb500e..13188c5977 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -63,7 +63,7 @@ private: Q_DECLARE_METATYPE(AudioInjector*) -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in); -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out); +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in); +void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out); #endif // hifi_AudioInjector_h