From 2794a134c17d48f85044d2ebd8d7dee8c9127544 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 10:44:59 -0700 Subject: [PATCH 01/26] Add master injector gain to audio-mixer --- .../src/audio/AudioMixerClientData.h | 3 + .../src/audio/AudioMixerSlave.cpp | 56 ++++++++++++------- assignment-client/src/audio/AudioMixerSlave.h | 7 ++- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 653749f619..f9d113c53d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -84,6 +84,8 @@ public: float getMasterAvatarGain() const { return _masterAvatarGain; } void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; } + float getMasterInjectorGain() const { return _masterInjectorGain; } + void setMasterInjectorGain(float gain) { _masterInjectorGain = gain; } AudioLimiter audioLimiter; @@ -189,6 +191,7 @@ private: int _frameToSendStats { 0 }; float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars + float _masterInjectorGain { 1.0f }; // per-listener mixing gain, applied only to injectors CodecPluginPointer _codec; QString _selectedCodecName; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index a920b45161..f7f8e8a9c1 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -50,7 +50,7 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& // mix helpers inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd); -inline float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, +inline float computeGain(float masterAvatarGain, float masterInjectorGain, const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, float distance, bool isEcho); inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); @@ -338,8 +338,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { } if (!isThrottling) { - updateHRTFParameters(stream, *listenerAudioStream, - listenerData->getMasterAvatarGain()); + updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + listenerData->getMasterInjectorGain()); } return false; }); @@ -363,8 +363,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { } if (!isThrottling) { - updateHRTFParameters(stream, *listenerAudioStream, - listenerData->getMasterAvatarGain()); + updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + listenerData->getMasterInjectorGain()); } return false; }); @@ -381,13 +381,13 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { stream.approximateVolume = approximateVolume(stream, listenerAudioStream); } else { if (shouldBeSkipped(stream, *listener, *listenerAudioStream, *listenerData)) { - addStream(stream, *listenerAudioStream, 0.0f, isSoloing); + addStream(stream, *listenerAudioStream, 0.0f, 0.0f, isSoloing); streams.skipped.push_back(move(stream)); ++stats.activeToSkipped; return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(), isSoloing); if (shouldBeInactive(stream)) { @@ -423,7 +423,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(), isSoloing); if (shouldBeInactive(stream)) { @@ -491,7 +491,9 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain, bool isSoloing) { + float masterAvatarGain, + float masterInjectorGain, + bool isSoloing) { ++stats.totalMixes; auto streamToAdd = mixableStream.positionalStream; @@ -504,9 +506,10 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre float distance = glm::max(glm::length(relativePosition), EPSILON); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); - float gain = masterListenerGain; + float gain = masterAvatarGain; if (!isSoloing) { - gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + gain = computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd, relativePosition, + distance, isEcho); } const int HRTF_DATASET_INDEX = 1; @@ -585,8 +588,9 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre } void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, - AvatarAudioStream& listeningNodeStream, - float masterListenerGain) { + AvatarAudioStream& listeningNodeStream, + float masterAvatarGain, + float masterInjectorGain) { auto streamToAdd = mixableStream.positionalStream; // check if this is a server echo of a source back to itself @@ -595,7 +599,8 @@ void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream& glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + float gain = computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd, relativePosition, + distance, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); mixableStream.hrtf->setParameterHistory(azimuth, distance, gain); @@ -720,6 +725,7 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio(); + // injector: skip master gain } // avatar: skip attenuation - it is too costly to approximate @@ -729,16 +735,23 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi float distance = glm::length(relativePosition); return gain / distance; - // avatar: skip master gain - it is constant for all streams + // avatar: skip master gain } -float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, - const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, float distance, bool isEcho) { +float computeGain(float masterAvatarGain, + float masterInjectorGain, + const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition, + float distance, + bool isEcho) { float gain = 1.0f; // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio(); + // apply master gain + gain *= masterInjectorGain; // avatar: apply fixed off-axis attenuation to make them quieter as they turn away } else if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) { @@ -754,8 +767,8 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo gain *= offAxisCoefficient; - // apply master gain, only to avatars - gain *= masterListenerGain; + // apply master gain + gain *= masterAvatarGain; } auto& audioZones = AudioMixer::getAudioZones(); @@ -797,8 +810,9 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo return gain; } -float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition) { +float computeAzimuth(const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition) { glm::quat inverseOrientation = glm::inverse(listeningNodeStream.getOrientation()); glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 3d979da1fc..9765ea8639 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -57,10 +57,13 @@ private: bool prepareMix(const SharedNodePointer& listener); void addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain, bool isSoloing); + float masterAvatarGain, + float masterInjectorGain, + bool isSoloing); void updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain); + float masterAvatarGain, + float masterInjectorGain); void resetHRTFState(AudioMixerClientData::MixableStream& mixableStream); void addStreams(Node& listener, AudioMixerClientData& listenerData); From a5a305f1816cb56c9a0434d41c446d74ccca38d2 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 12:05:51 -0700 Subject: [PATCH 02/26] Handle InjectorGainSet packet at the audio-mixer --- assignment-client/src/audio/AudioMixer.cpp | 1 + .../src/audio/AudioMixerClientData.cpp | 14 ++++++++++++++ assignment-client/src/audio/AudioMixerClientData.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f67c54239e..201e24d4b9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -97,6 +97,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::RadiusIgnoreRequest, PacketType::RequestsDomainListData, PacketType::PerAvatarGainSet, + PacketType::InjectorGainSet, PacketType::AudioSoloRequest }, this, "queueAudioPacket"); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 90698bfac8..b8d3ec62a6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -92,6 +92,9 @@ int AudioMixerClientData::processPackets(ConcurrentAddedStreams& addedStreams) { case PacketType::PerAvatarGainSet: parsePerAvatarGainSet(*packet, node); break; + case PacketType::InjectorGainSet: + parseInjectorGainSet(*packet, node); + break; case PacketType::NodeIgnoreRequest: parseNodeIgnoreRequest(packet, node); break; @@ -205,6 +208,17 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const } } +void AudioMixerClientData::parseInjectorGainSet(ReceivedMessage& message, const SharedNodePointer& node) { + QUuid uuid = node->getUUID(); + + uint8_t packedGain; + message.readPrimitive(&packedGain); + float gain = unpackFloatGainFromByte(packedGain); + + setMasterInjectorGain(gain); + qCDebug(audio) << "Setting MASTER injector gain for " << uuid << " to " << gain; +} + void AudioMixerClientData::setGainForAvatar(QUuid nodeID, float gain) { auto it = std::find_if(_streams.active.cbegin(), _streams.active.cend(), [nodeID](const MixableStream& mixableStream){ return mixableStream.nodeStreamID.nodeID == nodeID && mixableStream.nodeStreamID.streamID.isNull(); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index f9d113c53d..4a1ca7f9b5 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -63,6 +63,7 @@ public: void negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node); void parseRequestsDomainListData(ReceivedMessage& message); void parsePerAvatarGainSet(ReceivedMessage& message, const SharedNodePointer& node); + void parseInjectorGainSet(ReceivedMessage& message, const SharedNodePointer& node); void parseNodeIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); void parseRadiusIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); void parseSoloRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0ec7c40ca4..413ff14b17 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -57,7 +57,7 @@ public: ICEServerQuery, OctreeStats, SetAvatarTraits, - UNUSED_PACKET_TYPE, + InjectorGainSet, AssignmentClientStatus, NoisyMute, AvatarIdentity, From ca0379f6de206502722aa27f31137870fc762677 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 17:24:50 -0700 Subject: [PATCH 03/26] Send InjectorGainSet packet to the audio-mixer --- libraries/networking/src/NodeList.cpp | 25 +++++++++++++++++++++++++ libraries/networking/src/NodeList.h | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index e6eb6087b0..eec710322e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -265,6 +265,8 @@ void NodeList::reset(bool skipDomainHandlerReset) { _avatarGainMap.clear(); _avatarGainMapLock.unlock(); + _injectorGain = 0.0f; + if (!skipDomainHandlerReset) { // clear the domain connection information, unless they're the ones that asked us to reset _domainHandler.softReset(); @@ -1087,6 +1089,29 @@ float NodeList::getAvatarGain(const QUuid& nodeID) { return 0.0f; } +void NodeList::setInjectorGain(float gain) { + auto audioMixer = soloNodeOfType(NodeType::AudioMixer); + if (audioMixer) { + // setup the packet + auto setInjectorGainPacket = NLPacket::create(PacketType::InjectorGainSet, sizeof(float), true); + + // We need to convert the gain in dB (from the script) to an amplitude before packing it. + setInjectorGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.02059991f))); + + qCDebug(networking) << "Sending Set Injector Gain packet with Gain:" << gain; + + sendPacket(std::move(setInjectorGainPacket), *audioMixer); + _injectorGain = gain; + + } else { + qWarning() << "Couldn't find audio mixer to send set gain request"; + } +} + +float NodeList::getInjectorGain() { + return _injectorGain; +} + void NodeList::kickNodeBySessionID(const QUuid& nodeID) { // send a request to domain-server to kick the node with the given session ID // the domain-server will handle the persistence of the kick (via username or IP) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index e135bc937d..d2a1212d64 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -83,6 +83,8 @@ public: bool isPersonalMutingNode(const QUuid& nodeID) const; void setAvatarGain(const QUuid& nodeID, float gain); float getAvatarGain(const QUuid& nodeID); + void setInjectorGain(float gain); + float getInjectorGain(); void kickNodeBySessionID(const QUuid& nodeID); void muteNodeBySessionID(const QUuid& nodeID); @@ -181,6 +183,8 @@ private: mutable QReadWriteLock _avatarGainMapLock; tbb::concurrent_unordered_map<QUuid, float, UUIDHasher> _avatarGainMap; + std::atomic<float> _injectorGain { 0.0f }; + void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); #if defined(Q_OS_ANDROID) Setting::Handle<bool> _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false }; From 3186a9468231daff21687c76999469c012910824 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Wed, 20 Mar 2019 15:48:05 -0700 Subject: [PATCH 04/26] Add Users.setInjectorGain() and Users.getInjectorGain() to the scripting interface --- .../script-engine/src/UsersScriptingInterface.cpp | 9 +++++++++ .../script-engine/src/UsersScriptingInterface.h | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index fef11c12e9..a0593d3ff8 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -51,6 +51,15 @@ float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) { return DependencyManager::get<NodeList>()->getAvatarGain(nodeID); } +void UsersScriptingInterface::setInjectorGain(float gain) { + // ask the NodeList to set the audio injector gain + DependencyManager::get<NodeList>()->setInjectorGain(gain); +} + +float UsersScriptingInterface::getInjectorGain() { + return DependencyManager::get<NodeList>()->getInjectorGain(); +} + void UsersScriptingInterface::kick(const QUuid& nodeID) { // ask the NodeList to kick the user with the given session ID DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 57de205066..17a84248a1 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -90,6 +90,21 @@ public slots: */ float getAvatarGain(const QUuid& nodeID); + /**jsdoc + * Sets the audio injector gain at the server. + * Units are Decibels (dB) + * @function Users.setInjectorGain + * @param {number} gain (in dB) + */ + void setInjectorGain(float gain); + + /**jsdoc + * Gets the audio injector gain at the server. + * @function Users.getInjectorGain + * @returns {number} gain (in dB) + */ + float getInjectorGain(); + /**jsdoc * Kick/ban another user. Removes them from the server and prevents them from returning. Bans by either user name (if * available) or machine fingerprint otherwise. This will only do anything if you're an admin of the domain you're in. From 7311c3ac06aa3e1425c169afc22f0d0c2842900e Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Thu, 21 Mar 2019 11:51:49 -0700 Subject: [PATCH 05/26] Move the new audio volume API from Users scripting interface to Audio scripting interface --- interface/src/scripting/Audio.cpp | 36 ++++++++++++++++--- interface/src/scripting/Audio.h | 30 ++++++++++++++++ .../src/UsersScriptingInterface.cpp | 9 ----- .../src/UsersScriptingInterface.h | 15 -------- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index bf43db3044..e0474b7bba 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -374,6 +374,18 @@ void Audio::handlePushedToTalk(bool enabled) { } } +void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { + withWriteLock([&] { + _devices.chooseInputDevice(device, isHMD); + }); +} + +void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { + withWriteLock([&] { + _devices.chooseOutputDevice(device, isHMD); + }); +} + void Audio::setReverb(bool enable) { withWriteLock([&] { DependencyManager::get<AudioClient>()->setReverb(enable); @@ -386,14 +398,28 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { }); } -void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { +void Audio::setAvatarGain(float gain) { withWriteLock([&] { - _devices.chooseInputDevice(device, isHMD); + // ask the NodeList to set the master avatar gain + DependencyManager::get<NodeList>()->setAvatarGain("", gain); }); } -void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { - withWriteLock([&] { - _devices.chooseOutputDevice(device, isHMD); +float Audio::getAvatarGain() { + return resultWithReadLock<float>([&] { + return DependencyManager::get<NodeList>()->getAvatarGain(""); + }); +} + +void Audio::setInjectorGain(float gain) { + withWriteLock([&] { + // ask the NodeList to set the audio injector gain + DependencyManager::get<NodeList>()->setInjectorGain(gain); + }); +} + +float Audio::getInjectorGain() { + return resultWithReadLock<float>([&] { + return DependencyManager::get<NodeList>()->getInjectorGain(); }); } diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 9ee230fc29..14a75d5ffe 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -170,6 +170,36 @@ public: */ Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options); + /**jsdoc + * Sets the master avatar gain at the server. + * Units are Decibels (dB) + * @function Audio.setAvatarGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setAvatarGain(float gain); + + /**jsdoc + * Gets the master avatar gain at the server. + * @function Audio.getAvatarGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getAvatarGain(); + + /**jsdoc + * Sets the audio injector gain at the server. + * Units are Decibels (dB) + * @function Audio.setInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setInjectorGain(float gain); + + /**jsdoc + * Gets the audio injector gain at the server. + * @function Audio.getInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getInjectorGain(); + /**jsdoc * Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format. * @function Audio.startRecording diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index a0593d3ff8..fef11c12e9 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -51,15 +51,6 @@ float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) { return DependencyManager::get<NodeList>()->getAvatarGain(nodeID); } -void UsersScriptingInterface::setInjectorGain(float gain) { - // ask the NodeList to set the audio injector gain - DependencyManager::get<NodeList>()->setInjectorGain(gain); -} - -float UsersScriptingInterface::getInjectorGain() { - return DependencyManager::get<NodeList>()->getInjectorGain(); -} - void UsersScriptingInterface::kick(const QUuid& nodeID) { // ask the NodeList to kick the user with the given session ID DependencyManager::get<NodeList>()->kickNodeBySessionID(nodeID); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 17a84248a1..57de205066 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -90,21 +90,6 @@ public slots: */ float getAvatarGain(const QUuid& nodeID); - /**jsdoc - * Sets the audio injector gain at the server. - * Units are Decibels (dB) - * @function Users.setInjectorGain - * @param {number} gain (in dB) - */ - void setInjectorGain(float gain); - - /**jsdoc - * Gets the audio injector gain at the server. - * @function Users.getInjectorGain - * @returns {number} gain (in dB) - */ - float getInjectorGain(); - /**jsdoc * Kick/ban another user. Removes them from the server and prevents them from returning. Bans by either user name (if * available) or machine fingerprint otherwise. This will only do anything if you're an admin of the domain you're in. From e6c720f793f79217fe11f99381b6caf878efdf3b Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:12:31 -0700 Subject: [PATCH 06/26] Add AudioClient mixing gains for local injectors and system sounds --- libraries/audio-client/src/AudioClient.cpp | 4 +++- libraries/audio-client/src/AudioClient.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 1c10d24f23..79811ac98f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1366,7 +1366,9 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { memset(_localScratchBuffer, 0, bytesToRead); if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) { - float gain = injector->getVolume(); + bool isSystemSound = !injector->isPositionSet() && !injector->isAmbisonic(); + + float gain = injector->getVolume() * (isSystemSound ? _systemInjectorGain : _localInjectorGain); if (injector->isAmbisonic()) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index b9648219a5..6e1f48d5f4 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -239,6 +239,8 @@ public slots: void setInputVolume(float volume, bool emitSignal = true); void setReverb(bool reverb); void setReverbOptions(const AudioEffectOptions* options); + void setLocalInjectorGain(float gain) { _localInjectorGain = gain; }; + void setSystemInjectorGain(float gain) { _systemInjectorGain = gain; }; void outputNotify(); @@ -393,6 +395,8 @@ private: int16_t* _outputScratchBuffer { NULL }; // for local audio (used by audio injectors thread) + std::atomic<float> _localInjectorGain { 1.0f }; + std::atomic<float> _systemInjectorGain { 1.0f }; float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC]; float* _localOutputMixBuffer { NULL }; From 23a6a66528ac68792594cd0cf7547737c7ddba94 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:21:54 -0700 Subject: [PATCH 07/26] Add local injector gains to the Audio scripting interface --- interface/src/scripting/Audio.cpp | 34 ++++++++++++++++++++++++++ interface/src/scripting/Audio.h | 40 +++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index e0474b7bba..7e1a35762a 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -423,3 +423,37 @@ float Audio::getInjectorGain() { return DependencyManager::get<NodeList>()->getInjectorGain(); }); } + +void Audio::setLocalInjectorGain(float gain) { + withWriteLock([&] { + if (_localInjectorGain != gain) { + _localInjectorGain = gain; + // convert dB to amplitude + gain = fastExp2f(gain / 6.02059991f); + DependencyManager::get<AudioClient>()->setLocalInjectorGain(gain); + } + }); +} + +float Audio::getLocalInjectorGain() { + return resultWithReadLock<float>([&] { + return _localInjectorGain; + }); +} + +void Audio::setSystemInjectorGain(float gain) { + withWriteLock([&] { + if (_systemInjectorGain != gain) { + _systemInjectorGain = gain; + // convert dB to amplitude + gain = fastExp2f(gain / 6.02059991f); + DependencyManager::get<AudioClient>()->setSystemInjectorGain(gain); + } + }); +} + +float Audio::getSystemInjectorGain() { + return resultWithReadLock<float>([&] { + return _systemInjectorGain; + }); +} diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 14a75d5ffe..d6823ea452 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -171,7 +171,7 @@ public: Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options); /**jsdoc - * Sets the master avatar gain at the server. + * Sets the avatar gain at the server. * Units are Decibels (dB) * @function Audio.setAvatarGain * @param {number} gain (in dB) @@ -179,14 +179,14 @@ public: Q_INVOKABLE void setAvatarGain(float gain); /**jsdoc - * Gets the master avatar gain at the server. + * Gets the avatar gain at the server. * @function Audio.getAvatarGain * @returns {number} gain (in dB) */ Q_INVOKABLE float getAvatarGain(); /**jsdoc - * Sets the audio injector gain at the server. + * Sets the injector gain at the server. * Units are Decibels (dB) * @function Audio.setInjectorGain * @param {number} gain (in dB) @@ -194,12 +194,42 @@ public: Q_INVOKABLE void setInjectorGain(float gain); /**jsdoc - * Gets the audio injector gain at the server. + * Gets the injector gain at the server. * @function Audio.getInjectorGain * @returns {number} gain (in dB) */ Q_INVOKABLE float getInjectorGain(); + /**jsdoc + * Sets the local injector gain in the client. + * Units are Decibels (dB) + * @function Audio.setLocalInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setLocalInjectorGain(float gain); + + /**jsdoc + * Gets the local injector gain in the client. + * @function Audio.getLocalInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getLocalInjectorGain(); + + /**jsdoc + * Sets the injector gain for system sounds. + * Units are Decibels (dB) + * @function Audio.setSystemInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setSystemInjectorGain(float gain); + + /**jsdoc + * Gets the injector gain for system sounds. + * @function Audio.getSystemInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getSystemInjectorGain(); + /**jsdoc * Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format. * @function Audio.startRecording @@ -380,6 +410,8 @@ private: float _inputVolume { 1.0f }; float _inputLevel { 0.0f }; + float _localInjectorGain { 0.0f }; // in dB + float _systemInjectorGain { 0.0f }; // in dB bool _isClipping { false }; bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled. bool _enableWarnWhenMuted { true }; From e8ddee280d6e8c11f897791c7d7041a1edd1a7c7 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:24:30 -0700 Subject: [PATCH 08/26] Quantize and limit the local injector gains to match the network protocol --- interface/src/scripting/Audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 7e1a35762a..6dd1c40ef5 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -430,6 +430,8 @@ void Audio::setLocalInjectorGain(float gain) { _localInjectorGain = gain; // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); + // quantize and limit to match NodeList::setInjectorGain() + gain = unpackFloatGainFromByte(packFloatGainToByte(gain)); DependencyManager::get<AudioClient>()->setLocalInjectorGain(gain); } }); @@ -447,6 +449,8 @@ void Audio::setSystemInjectorGain(float gain) { _systemInjectorGain = gain; // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); + // quantize and limit to match NodeList::setInjectorGain() + gain = unpackFloatGainFromByte(packFloatGainToByte(gain)); DependencyManager::get<AudioClient>()->setSystemInjectorGain(gain); } }); From e671a124c3c5d6a14510111417f6346c81d8efe4 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 17:58:17 -0700 Subject: [PATCH 09/26] Cleanup --- assignment-client/src/audio/AudioMixerClientData.cpp | 6 +++--- interface/src/scripting/Audio.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b8d3ec62a6..41b72c04d2 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -200,11 +200,11 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const if (avatarUUID.isNull()) { // set the MASTER avatar gain setMasterAvatarGain(gain); - qCDebug(audio) << "Setting MASTER avatar gain for " << uuid << " to " << gain; + qCDebug(audio) << "Setting MASTER avatar gain for" << uuid << "to" << gain; } else { // set the per-source avatar gain setGainForAvatar(avatarUUID, gain); - qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUUID << "] to " << gain; + qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUUID << "] to" << gain; } } @@ -216,7 +216,7 @@ void AudioMixerClientData::parseInjectorGainSet(ReceivedMessage& message, const float gain = unpackFloatGainFromByte(packedGain); setMasterInjectorGain(gain); - qCDebug(audio) << "Setting MASTER injector gain for " << uuid << " to " << gain; + qCDebug(audio) << "Setting MASTER injector gain for" << uuid << "to" << gain; } void AudioMixerClientData::setGainForAvatar(QUuid nodeID, float gain) { diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 6dd1c40ef5..ac5ddd6a6a 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -401,13 +401,13 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { void Audio::setAvatarGain(float gain) { withWriteLock([&] { // ask the NodeList to set the master avatar gain - DependencyManager::get<NodeList>()->setAvatarGain("", gain); + DependencyManager::get<NodeList>()->setAvatarGain(QUuid(), gain); }); } float Audio::getAvatarGain() { return resultWithReadLock<float>([&] { - return DependencyManager::get<NodeList>()->getAvatarGain(""); + return DependencyManager::get<NodeList>()->getAvatarGain(QUuid()); }); } From cbeb4b0b208fc40bc00d32e31bcce3b6903cc7e0 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Sat, 23 Mar 2019 06:48:37 -0700 Subject: [PATCH 10/26] Persist the audio-mixer settings across domain changes and server resets --- libraries/networking/src/NodeList.cpp | 38 ++++++++++++++++++--------- libraries/networking/src/NodeList.h | 3 ++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index eec710322e..0021a594bc 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -265,8 +265,6 @@ void NodeList::reset(bool skipDomainHandlerReset) { _avatarGainMap.clear(); _avatarGainMapLock.unlock(); - _injectorGain = 0.0f; - if (!skipDomainHandlerReset) { // clear the domain connection information, unless they're the ones that asked us to reset _domainHandler.softReset(); @@ -1018,6 +1016,14 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { // also send them the current ignore radius state. sendIgnoreRadiusStateToNode(newNode); + + // also send the current avatar and injector gains + if (_avatarGain != 0.0f) { + setAvatarGain(QUuid(), _avatarGain); + } + if (_injectorGain != 0.0f) { + setInjectorGain(_injectorGain); + } } if (newNode->getType() == NodeType::AvatarMixer) { // this is a mixer that we just added - it's unlikely it knows who we were previously ignoring in this session, @@ -1064,13 +1070,17 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { if (nodeID.isNull()) { qCDebug(networking) << "Sending Set MASTER Avatar Gain packet with Gain:" << gain; - } else { - qCDebug(networking) << "Sending Set Avatar Gain packet with UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; - } - sendPacket(std::move(setAvatarGainPacket), *audioMixer); - QWriteLocker lock{ &_avatarGainMapLock }; - _avatarGainMap[nodeID] = gain; + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + _avatarGain = gain; + + } else { + qCDebug(networking) << "Sending Set Avatar Gain packet with UUID:" << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + QWriteLocker lock{ &_avatarGainMapLock }; + _avatarGainMap[nodeID] = gain; + } } else { qWarning() << "Couldn't find audio mixer to send set gain request"; @@ -1081,10 +1091,14 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { } float NodeList::getAvatarGain(const QUuid& nodeID) { - QReadLocker lock{ &_avatarGainMapLock }; - auto it = _avatarGainMap.find(nodeID); - if (it != _avatarGainMap.cend()) { - return it->second; + if (nodeID.isNull()) { + return _avatarGain; + } else { + QReadLocker lock{ &_avatarGainMapLock }; + auto it = _avatarGainMap.find(nodeID); + if (it != _avatarGainMap.cend()) { + return it->second; + } } return 0.0f; } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index d2a1212d64..f871560fba 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -183,7 +183,8 @@ private: mutable QReadWriteLock _avatarGainMapLock; tbb::concurrent_unordered_map<QUuid, float, UUIDHasher> _avatarGainMap; - std::atomic<float> _injectorGain { 0.0f }; + std::atomic<float> _avatarGain { 0.0f }; // in dB + std::atomic<float> _injectorGain { 0.0f }; // in dB void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); #if defined(Q_OS_ANDROID) From 649bb92e6c8d628ce4825e2dc946cdf624b981e0 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Sat, 23 Mar 2019 16:00:02 -0700 Subject: [PATCH 11/26] Prototype an updated Audio tab with 3 independent volume controls --- interface/resources/qml/hifi/audio/Audio.qml | 176 +++++++++++++++--- .../qml/hifi/audio/LoopbackAudio.qml | 16 +- .../qml/hifi/audio/PlaySampleSound.qml | 16 +- 3 files changed, 169 insertions(+), 39 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index da306f911b..92dfcb4117 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -85,8 +85,19 @@ Rectangle { } function updateMyAvatarGainFromQML(sliderValue, isReleased) { - if (Users.getAvatarGain(myAvatarUuid) != sliderValue) { - Users.setAvatarGain(myAvatarUuid, sliderValue); + if (AudioScriptingInterface.getAvatarGain() != sliderValue) { + AudioScriptingInterface.setAvatarGain(sliderValue); + } + } + function updateInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getInjectorGain() != sliderValue) { + AudioScriptingInterface.setInjectorGain(sliderValue); // server side + AudioScriptingInterface.setLocalInjectorGain(sliderValue); // client side + } + } + function updateSystemInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getSystemInjectorGain() != sliderValue) { + AudioScriptingInterface.setSystemInjectorGain(sliderValue); } } @@ -254,6 +265,14 @@ Rectangle { color: hifi.colors.white; text: qsTr("Choose input device"); } + + AudioControls.LoopbackAudio { + x: margins.paddings + + visible: (bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR); + anchors { right: parent.right } + } } ListView { @@ -301,13 +320,6 @@ Rectangle { } } } - AudioControls.LoopbackAudio { - x: margins.paddings - - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } - } Separator {} @@ -335,6 +347,14 @@ Rectangle { color: hifi.colors.white; text: qsTr("Choose output device"); } + + AudioControls.PlaySampleSound { + x: margins.paddings + + visible: (bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR); + anchors { right: parent.right } + } } ListView { @@ -370,20 +390,20 @@ Rectangle { } Item { - id: gainContainer + id: avatarGainContainer x: margins.paddings; width: parent.width - margins.paddings*2 - height: gainSliderTextMetrics.height + height: avatarGainSliderTextMetrics.height HifiControlsUit.Slider { - id: gainSlider + id: avatarGainSlider anchors.right: parent.right height: parent.height width: 200 minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 - value: Users.getAvatarGain(myAvatarUuid) + value: AudioScriptingInterface.getAvatarGain() onValueChanged: { updateMyAvatarGainFromQML(value, false); } @@ -399,7 +419,7 @@ Rectangle { // Do nothing. } onDoubleClicked: { - gainSlider.value = 0.0 + avatarGainSlider.value = 0.0 } onPressed: { // Pass through to Slider @@ -413,13 +433,13 @@ Rectangle { } } TextMetrics { - id: gainSliderTextMetrics - text: gainSliderText.text - font: gainSliderText.font + id: avatarGainSliderTextMetrics + text: avatarGainSliderText.text + font: avatarGainSliderText.font } RalewayRegular { // The slider for my card is special, it controls the master gain - id: gainSliderText; + id: avatarGainSliderText; text: "Avatar volume"; size: 16; anchors.left: parent.left; @@ -429,12 +449,122 @@ Rectangle { } } - AudioControls.PlaySampleSound { - x: margins.paddings + Item { + id: injectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: injectorGainSliderTextMetrics.height - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } + HifiControlsUit.Slider { + id: injectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getInjectorGain() + onValueChanged: { + updateInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + injectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: injectorGainSliderTextMetrics + text: injectorGainSliderText.text + font: injectorGainSliderText.font + } + RalewayRegular { + id: injectorGainSliderText; + text: "Environment volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } + + Item { + id: systemInjectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: systemInjectorGainSliderTextMetrics.height + + HifiControlsUit.Slider { + id: systemInjectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getSystemInjectorGain() + onValueChanged: { + updateSystemInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateSystemInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + systemInjectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: systemInjectorGainSliderTextMetrics + text: systemInjectorGainSliderText.text + font: systemInjectorGainSliderText.font + } + RalewayRegular { + id: systemInjectorGainSliderText; + text: "System Sound volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } } } } diff --git a/interface/resources/qml/hifi/audio/LoopbackAudio.qml b/interface/resources/qml/hifi/audio/LoopbackAudio.qml index 8ec0ffc496..74bc0f67dc 100644 --- a/interface/resources/qml/hifi/audio/LoopbackAudio.qml +++ b/interface/resources/qml/hifi/audio/LoopbackAudio.qml @@ -44,7 +44,7 @@ RowLayout { } HifiControlsUit.Button { - text: audioLoopedBack ? qsTr("STOP TESTING YOUR VOICE") : qsTr("TEST YOUR VOICE"); + text: audioLoopedBack ? qsTr("STOP TESTING") : qsTr("TEST YOUR VOICE"); color: audioLoopedBack ? hifi.buttons.red : hifi.buttons.blue; onClicked: { if (audioLoopedBack) { @@ -57,11 +57,11 @@ RowLayout { } } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: audioLoopedBack ? qsTr("Speak in your input") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: audioLoopedBack ? qsTr("Speak in your input") : ""; +// } } diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index b9d9727dab..0eb78f3efe 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -56,16 +56,16 @@ RowLayout { HifiConstants { id: hifi; } HifiControlsUit.Button { - text: isPlaying ? qsTr("STOP TESTING YOUR SOUND") : qsTr("TEST YOUR SOUND"); + text: isPlaying ? qsTr("STOP TESTING") : qsTr("TEST YOUR SOUND"); color: isPlaying ? hifi.buttons.red : hifi.buttons.blue; onClicked: isPlaying ? stopSound() : playSound(); } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: isPlaying ? qsTr("Listen to your output") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: isPlaying ? qsTr("Listen to your output") : ""; +// } } From 4658e34b4be6bd1340e56d320f775fb1d2ee3d7b Mon Sep 17 00:00:00 2001 From: Wayne Chen <wayne@highfidelity.io> Date: Mon, 25 Mar 2019 11:29:27 -0700 Subject: [PATCH 12/26] update indent spacing --- interface/resources/qml/hifi/audio/Audio.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index ded28506b8..46ea64a323 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -669,10 +669,10 @@ Rectangle { } } AudioControls.PlaySampleSound { - id: playSampleSound - x: margins.paddings - anchors.top: systemInjectorGainContainer.bottom; - anchors.topMargin: 10; + id: playSampleSound + x: margins.paddings + anchors.top: systemInjectorGainContainer.bottom; + anchors.topMargin: 10; } } } From afe46cd78bfcaf759bf3099c8a37d7d7bb4406fb Mon Sep 17 00:00:00 2001 From: Wayne Chen <wayne@highfidelity.io> Date: Mon, 25 Mar 2019 11:29:34 -0700 Subject: [PATCH 13/26] update indent spacing From 1057166418e4c0526c2caa6e7a02c6b06b4fd63c Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 10:44:59 -0700 Subject: [PATCH 14/26] Add master injector gain to audio-mixer --- .../src/audio/AudioMixerClientData.h | 3 + .../src/audio/AudioMixerSlave.cpp | 56 ++++++++++++------- assignment-client/src/audio/AudioMixerSlave.h | 7 ++- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 653749f619..f9d113c53d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -84,6 +84,8 @@ public: float getMasterAvatarGain() const { return _masterAvatarGain; } void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; } + float getMasterInjectorGain() const { return _masterInjectorGain; } + void setMasterInjectorGain(float gain) { _masterInjectorGain = gain; } AudioLimiter audioLimiter; @@ -189,6 +191,7 @@ private: int _frameToSendStats { 0 }; float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars + float _masterInjectorGain { 1.0f }; // per-listener mixing gain, applied only to injectors CodecPluginPointer _codec; QString _selectedCodecName; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index a920b45161..f7f8e8a9c1 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -50,7 +50,7 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& // mix helpers inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd); -inline float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, +inline float computeGain(float masterAvatarGain, float masterInjectorGain, const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, float distance, bool isEcho); inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); @@ -338,8 +338,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { } if (!isThrottling) { - updateHRTFParameters(stream, *listenerAudioStream, - listenerData->getMasterAvatarGain()); + updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + listenerData->getMasterInjectorGain()); } return false; }); @@ -363,8 +363,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { } if (!isThrottling) { - updateHRTFParameters(stream, *listenerAudioStream, - listenerData->getMasterAvatarGain()); + updateHRTFParameters(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + listenerData->getMasterInjectorGain()); } return false; }); @@ -381,13 +381,13 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { stream.approximateVolume = approximateVolume(stream, listenerAudioStream); } else { if (shouldBeSkipped(stream, *listener, *listenerAudioStream, *listenerData)) { - addStream(stream, *listenerAudioStream, 0.0f, isSoloing); + addStream(stream, *listenerAudioStream, 0.0f, 0.0f, isSoloing); streams.skipped.push_back(move(stream)); ++stats.activeToSkipped; return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(), isSoloing); if (shouldBeInactive(stream)) { @@ -423,7 +423,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), listenerData->getMasterInjectorGain(), isSoloing); if (shouldBeInactive(stream)) { @@ -491,7 +491,9 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain, bool isSoloing) { + float masterAvatarGain, + float masterInjectorGain, + bool isSoloing) { ++stats.totalMixes; auto streamToAdd = mixableStream.positionalStream; @@ -504,9 +506,10 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre float distance = glm::max(glm::length(relativePosition), EPSILON); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); - float gain = masterListenerGain; + float gain = masterAvatarGain; if (!isSoloing) { - gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + gain = computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd, relativePosition, + distance, isEcho); } const int HRTF_DATASET_INDEX = 1; @@ -585,8 +588,9 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre } void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, - AvatarAudioStream& listeningNodeStream, - float masterListenerGain) { + AvatarAudioStream& listeningNodeStream, + float masterAvatarGain, + float masterInjectorGain) { auto streamToAdd = mixableStream.positionalStream; // check if this is a server echo of a source back to itself @@ -595,7 +599,8 @@ void AudioMixerSlave::updateHRTFParameters(AudioMixerClientData::MixableStream& glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + float gain = computeGain(masterAvatarGain, masterInjectorGain, listeningNodeStream, *streamToAdd, relativePosition, + distance, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); mixableStream.hrtf->setParameterHistory(azimuth, distance, gain); @@ -720,6 +725,7 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio(); + // injector: skip master gain } // avatar: skip attenuation - it is too costly to approximate @@ -729,16 +735,23 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi float distance = glm::length(relativePosition); return gain / distance; - // avatar: skip master gain - it is constant for all streams + // avatar: skip master gain } -float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, - const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, float distance, bool isEcho) { +float computeGain(float masterAvatarGain, + float masterInjectorGain, + const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition, + float distance, + bool isEcho) { float gain = 1.0f; // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast<const InjectedAudioStream*>(&streamToAdd)->getAttenuationRatio(); + // apply master gain + gain *= masterInjectorGain; // avatar: apply fixed off-axis attenuation to make them quieter as they turn away } else if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) { @@ -754,8 +767,8 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo gain *= offAxisCoefficient; - // apply master gain, only to avatars - gain *= masterListenerGain; + // apply master gain + gain *= masterAvatarGain; } auto& audioZones = AudioMixer::getAudioZones(); @@ -797,8 +810,9 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo return gain; } -float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition) { +float computeAzimuth(const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition) { glm::quat inverseOrientation = glm::inverse(listeningNodeStream.getOrientation()); glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 3d979da1fc..9765ea8639 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -57,10 +57,13 @@ private: bool prepareMix(const SharedNodePointer& listener); void addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain, bool isSoloing); + float masterAvatarGain, + float masterInjectorGain, + bool isSoloing); void updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain); + float masterAvatarGain, + float masterInjectorGain); void resetHRTFState(AudioMixerClientData::MixableStream& mixableStream); void addStreams(Node& listener, AudioMixerClientData& listenerData); From b15651f1ebcf161fb50253bc9333e906cd27454b Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 12:05:51 -0700 Subject: [PATCH 15/26] Handle InjectorGainSet packet at the audio-mixer --- assignment-client/src/audio/AudioMixer.cpp | 1 + .../src/audio/AudioMixerClientData.cpp | 14 ++++++++++++++ assignment-client/src/audio/AudioMixerClientData.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f67c54239e..201e24d4b9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -97,6 +97,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::RadiusIgnoreRequest, PacketType::RequestsDomainListData, PacketType::PerAvatarGainSet, + PacketType::InjectorGainSet, PacketType::AudioSoloRequest }, this, "queueAudioPacket"); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 90698bfac8..b8d3ec62a6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -92,6 +92,9 @@ int AudioMixerClientData::processPackets(ConcurrentAddedStreams& addedStreams) { case PacketType::PerAvatarGainSet: parsePerAvatarGainSet(*packet, node); break; + case PacketType::InjectorGainSet: + parseInjectorGainSet(*packet, node); + break; case PacketType::NodeIgnoreRequest: parseNodeIgnoreRequest(packet, node); break; @@ -205,6 +208,17 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const } } +void AudioMixerClientData::parseInjectorGainSet(ReceivedMessage& message, const SharedNodePointer& node) { + QUuid uuid = node->getUUID(); + + uint8_t packedGain; + message.readPrimitive(&packedGain); + float gain = unpackFloatGainFromByte(packedGain); + + setMasterInjectorGain(gain); + qCDebug(audio) << "Setting MASTER injector gain for " << uuid << " to " << gain; +} + void AudioMixerClientData::setGainForAvatar(QUuid nodeID, float gain) { auto it = std::find_if(_streams.active.cbegin(), _streams.active.cend(), [nodeID](const MixableStream& mixableStream){ return mixableStream.nodeStreamID.nodeID == nodeID && mixableStream.nodeStreamID.streamID.isNull(); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index f9d113c53d..4a1ca7f9b5 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -63,6 +63,7 @@ public: void negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node); void parseRequestsDomainListData(ReceivedMessage& message); void parsePerAvatarGainSet(ReceivedMessage& message, const SharedNodePointer& node); + void parseInjectorGainSet(ReceivedMessage& message, const SharedNodePointer& node); void parseNodeIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); void parseRadiusIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); void parseSoloRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0ec7c40ca4..413ff14b17 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -57,7 +57,7 @@ public: ICEServerQuery, OctreeStats, SetAvatarTraits, - UNUSED_PACKET_TYPE, + InjectorGainSet, AssignmentClientStatus, NoisyMute, AvatarIdentity, From 755762e8ecf7a7a1d70f21ba6a6c15557f5f2914 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 15 Mar 2019 17:24:50 -0700 Subject: [PATCH 16/26] Send InjectorGainSet packet to the audio-mixer --- libraries/networking/src/NodeList.cpp | 25 +++++++++++++++++++++++++ libraries/networking/src/NodeList.h | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index e6eb6087b0..eec710322e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -265,6 +265,8 @@ void NodeList::reset(bool skipDomainHandlerReset) { _avatarGainMap.clear(); _avatarGainMapLock.unlock(); + _injectorGain = 0.0f; + if (!skipDomainHandlerReset) { // clear the domain connection information, unless they're the ones that asked us to reset _domainHandler.softReset(); @@ -1087,6 +1089,29 @@ float NodeList::getAvatarGain(const QUuid& nodeID) { return 0.0f; } +void NodeList::setInjectorGain(float gain) { + auto audioMixer = soloNodeOfType(NodeType::AudioMixer); + if (audioMixer) { + // setup the packet + auto setInjectorGainPacket = NLPacket::create(PacketType::InjectorGainSet, sizeof(float), true); + + // We need to convert the gain in dB (from the script) to an amplitude before packing it. + setInjectorGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.02059991f))); + + qCDebug(networking) << "Sending Set Injector Gain packet with Gain:" << gain; + + sendPacket(std::move(setInjectorGainPacket), *audioMixer); + _injectorGain = gain; + + } else { + qWarning() << "Couldn't find audio mixer to send set gain request"; + } +} + +float NodeList::getInjectorGain() { + return _injectorGain; +} + void NodeList::kickNodeBySessionID(const QUuid& nodeID) { // send a request to domain-server to kick the node with the given session ID // the domain-server will handle the persistence of the kick (via username or IP) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index e135bc937d..d2a1212d64 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -83,6 +83,8 @@ public: bool isPersonalMutingNode(const QUuid& nodeID) const; void setAvatarGain(const QUuid& nodeID, float gain); float getAvatarGain(const QUuid& nodeID); + void setInjectorGain(float gain); + float getInjectorGain(); void kickNodeBySessionID(const QUuid& nodeID); void muteNodeBySessionID(const QUuid& nodeID); @@ -181,6 +183,8 @@ private: mutable QReadWriteLock _avatarGainMapLock; tbb::concurrent_unordered_map<QUuid, float, UUIDHasher> _avatarGainMap; + std::atomic<float> _injectorGain { 0.0f }; + void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); #if defined(Q_OS_ANDROID) Setting::Handle<bool> _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false }; From 4a6e495f5fa96eaa4772aaeb615035a050ec3a0f Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Wed, 20 Mar 2019 15:48:05 -0700 Subject: [PATCH 17/26] Add Users.setInjectorGain() and Users.getInjectorGain() to the scripting interface --- .../script-engine/src/UsersScriptingInterface.cpp | 9 +++++++++ .../script-engine/src/UsersScriptingInterface.h | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index 9beb52f20a..7b30e087e5 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -51,6 +51,15 @@ float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) { return DependencyManager::get<NodeList>()->getAvatarGain(nodeID); } +void UsersScriptingInterface::setInjectorGain(float gain) { + // ask the NodeList to set the audio injector gain + DependencyManager::get<NodeList>()->setInjectorGain(gain); +} + +float UsersScriptingInterface::getInjectorGain() { + return DependencyManager::get<NodeList>()->getInjectorGain(); +} + void UsersScriptingInterface::kick(const QUuid& nodeID) { if (_kickConfirmationOperator) { diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index f8ca974b8b..d6750b263d 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -97,6 +97,21 @@ public slots: */ float getAvatarGain(const QUuid& nodeID); + /**jsdoc + * Sets the audio injector gain at the server. + * Units are Decibels (dB) + * @function Users.setInjectorGain + * @param {number} gain (in dB) + */ + void setInjectorGain(float gain); + + /**jsdoc + * Gets the audio injector gain at the server. + * @function Users.getInjectorGain + * @returns {number} gain (in dB) + */ + float getInjectorGain(); + /**jsdoc * Kick/ban another user. Removes them from the server and prevents them from returning. Bans by either user name (if * available) or machine fingerprint otherwise. This will only do anything if you're an admin of the domain you're in. From a2d261d20ca1273b99ab90952945569baa43a153 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Thu, 21 Mar 2019 11:51:49 -0700 Subject: [PATCH 18/26] Move the new audio volume API from Users scripting interface to Audio scripting interface --- interface/src/scripting/Audio.cpp | 36 ++++++++++++++++--- interface/src/scripting/Audio.h | 30 ++++++++++++++++ .../src/UsersScriptingInterface.cpp | 9 ----- .../src/UsersScriptingInterface.h | 15 -------- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index b1b5077e60..f9560c84f7 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -377,6 +377,18 @@ void Audio::handlePushedToTalk(bool enabled) { } } +void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { + withWriteLock([&] { + _devices.chooseInputDevice(device, isHMD); + }); +} + +void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { + withWriteLock([&] { + _devices.chooseOutputDevice(device, isHMD); + }); +} + void Audio::setReverb(bool enable) { withWriteLock([&] { DependencyManager::get<AudioClient>()->setReverb(enable); @@ -389,14 +401,28 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { }); } -void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { +void Audio::setAvatarGain(float gain) { withWriteLock([&] { - _devices.chooseInputDevice(device, isHMD); + // ask the NodeList to set the master avatar gain + DependencyManager::get<NodeList>()->setAvatarGain("", gain); }); } -void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { - withWriteLock([&] { - _devices.chooseOutputDevice(device, isHMD); +float Audio::getAvatarGain() { + return resultWithReadLock<float>([&] { + return DependencyManager::get<NodeList>()->getAvatarGain(""); + }); +} + +void Audio::setInjectorGain(float gain) { + withWriteLock([&] { + // ask the NodeList to set the audio injector gain + DependencyManager::get<NodeList>()->setInjectorGain(gain); + }); +} + +float Audio::getInjectorGain() { + return resultWithReadLock<float>([&] { + return DependencyManager::get<NodeList>()->getInjectorGain(); }); } diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 9ee230fc29..14a75d5ffe 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -170,6 +170,36 @@ public: */ Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options); + /**jsdoc + * Sets the master avatar gain at the server. + * Units are Decibels (dB) + * @function Audio.setAvatarGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setAvatarGain(float gain); + + /**jsdoc + * Gets the master avatar gain at the server. + * @function Audio.getAvatarGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getAvatarGain(); + + /**jsdoc + * Sets the audio injector gain at the server. + * Units are Decibels (dB) + * @function Audio.setInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setInjectorGain(float gain); + + /**jsdoc + * Gets the audio injector gain at the server. + * @function Audio.getInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getInjectorGain(); + /**jsdoc * Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format. * @function Audio.startRecording diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index 7b30e087e5..9beb52f20a 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -51,15 +51,6 @@ float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) { return DependencyManager::get<NodeList>()->getAvatarGain(nodeID); } -void UsersScriptingInterface::setInjectorGain(float gain) { - // ask the NodeList to set the audio injector gain - DependencyManager::get<NodeList>()->setInjectorGain(gain); -} - -float UsersScriptingInterface::getInjectorGain() { - return DependencyManager::get<NodeList>()->getInjectorGain(); -} - void UsersScriptingInterface::kick(const QUuid& nodeID) { if (_kickConfirmationOperator) { diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index d6750b263d..f8ca974b8b 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -97,21 +97,6 @@ public slots: */ float getAvatarGain(const QUuid& nodeID); - /**jsdoc - * Sets the audio injector gain at the server. - * Units are Decibels (dB) - * @function Users.setInjectorGain - * @param {number} gain (in dB) - */ - void setInjectorGain(float gain); - - /**jsdoc - * Gets the audio injector gain at the server. - * @function Users.getInjectorGain - * @returns {number} gain (in dB) - */ - float getInjectorGain(); - /**jsdoc * Kick/ban another user. Removes them from the server and prevents them from returning. Bans by either user name (if * available) or machine fingerprint otherwise. This will only do anything if you're an admin of the domain you're in. From 95b4f954a6a1ed2912a6c47ac2c5c6d86a29d8ea Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:12:31 -0700 Subject: [PATCH 19/26] Add AudioClient mixing gains for local injectors and system sounds --- libraries/audio-client/src/AudioClient.cpp | 4 +++- libraries/audio-client/src/AudioClient.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9d645a1dbf..9fa9a0bc18 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1368,7 +1368,9 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { memset(_localScratchBuffer, 0, bytesToRead); if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) { - float gain = options.volume; + bool isSystemSound = !injector->isPositionSet() && !injector->isAmbisonic(); + + float gain = injector->getVolume() * (isSystemSound ? _systemInjectorGain : _localInjectorGain); if (options.ambisonic) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index a153f22bf3..7608bf5cdb 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -241,6 +241,8 @@ public slots: void setInputVolume(float volume, bool emitSignal = true); void setReverb(bool reverb); void setReverbOptions(const AudioEffectOptions* options); + void setLocalInjectorGain(float gain) { _localInjectorGain = gain; }; + void setSystemInjectorGain(float gain) { _systemInjectorGain = gain; }; void outputNotify(); @@ -395,6 +397,8 @@ private: int16_t* _outputScratchBuffer { NULL }; // for local audio (used by audio injectors thread) + std::atomic<float> _localInjectorGain { 1.0f }; + std::atomic<float> _systemInjectorGain { 1.0f }; float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC]; float* _localOutputMixBuffer { NULL }; From 37429a07b8a7a2262582f4b77779d46db3debdc3 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:21:54 -0700 Subject: [PATCH 20/26] Add local injector gains to the Audio scripting interface --- interface/src/scripting/Audio.cpp | 34 ++++++++++++++++++++++++++ interface/src/scripting/Audio.h | 40 +++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index f9560c84f7..b3c7b25745 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -426,3 +426,37 @@ float Audio::getInjectorGain() { return DependencyManager::get<NodeList>()->getInjectorGain(); }); } + +void Audio::setLocalInjectorGain(float gain) { + withWriteLock([&] { + if (_localInjectorGain != gain) { + _localInjectorGain = gain; + // convert dB to amplitude + gain = fastExp2f(gain / 6.02059991f); + DependencyManager::get<AudioClient>()->setLocalInjectorGain(gain); + } + }); +} + +float Audio::getLocalInjectorGain() { + return resultWithReadLock<float>([&] { + return _localInjectorGain; + }); +} + +void Audio::setSystemInjectorGain(float gain) { + withWriteLock([&] { + if (_systemInjectorGain != gain) { + _systemInjectorGain = gain; + // convert dB to amplitude + gain = fastExp2f(gain / 6.02059991f); + DependencyManager::get<AudioClient>()->setSystemInjectorGain(gain); + } + }); +} + +float Audio::getSystemInjectorGain() { + return resultWithReadLock<float>([&] { + return _systemInjectorGain; + }); +} diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 14a75d5ffe..d6823ea452 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -171,7 +171,7 @@ public: Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options); /**jsdoc - * Sets the master avatar gain at the server. + * Sets the avatar gain at the server. * Units are Decibels (dB) * @function Audio.setAvatarGain * @param {number} gain (in dB) @@ -179,14 +179,14 @@ public: Q_INVOKABLE void setAvatarGain(float gain); /**jsdoc - * Gets the master avatar gain at the server. + * Gets the avatar gain at the server. * @function Audio.getAvatarGain * @returns {number} gain (in dB) */ Q_INVOKABLE float getAvatarGain(); /**jsdoc - * Sets the audio injector gain at the server. + * Sets the injector gain at the server. * Units are Decibels (dB) * @function Audio.setInjectorGain * @param {number} gain (in dB) @@ -194,12 +194,42 @@ public: Q_INVOKABLE void setInjectorGain(float gain); /**jsdoc - * Gets the audio injector gain at the server. + * Gets the injector gain at the server. * @function Audio.getInjectorGain * @returns {number} gain (in dB) */ Q_INVOKABLE float getInjectorGain(); + /**jsdoc + * Sets the local injector gain in the client. + * Units are Decibels (dB) + * @function Audio.setLocalInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setLocalInjectorGain(float gain); + + /**jsdoc + * Gets the local injector gain in the client. + * @function Audio.getLocalInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getLocalInjectorGain(); + + /**jsdoc + * Sets the injector gain for system sounds. + * Units are Decibels (dB) + * @function Audio.setSystemInjectorGain + * @param {number} gain (in dB) + */ + Q_INVOKABLE void setSystemInjectorGain(float gain); + + /**jsdoc + * Gets the injector gain for system sounds. + * @function Audio.getSystemInjectorGain + * @returns {number} gain (in dB) + */ + Q_INVOKABLE float getSystemInjectorGain(); + /**jsdoc * Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format. * @function Audio.startRecording @@ -380,6 +410,8 @@ private: float _inputVolume { 1.0f }; float _inputLevel { 0.0f }; + float _localInjectorGain { 0.0f }; // in dB + float _systemInjectorGain { 0.0f }; // in dB bool _isClipping { false }; bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled. bool _enableWarnWhenMuted { true }; From 155bd39da6339410682a3c2bfd8b1c2bcb16947f Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 10:24:30 -0700 Subject: [PATCH 21/26] Quantize and limit the local injector gains to match the network protocol --- interface/src/scripting/Audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index b3c7b25745..330ed7abfe 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -433,6 +433,8 @@ void Audio::setLocalInjectorGain(float gain) { _localInjectorGain = gain; // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); + // quantize and limit to match NodeList::setInjectorGain() + gain = unpackFloatGainFromByte(packFloatGainToByte(gain)); DependencyManager::get<AudioClient>()->setLocalInjectorGain(gain); } }); @@ -450,6 +452,8 @@ void Audio::setSystemInjectorGain(float gain) { _systemInjectorGain = gain; // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); + // quantize and limit to match NodeList::setInjectorGain() + gain = unpackFloatGainFromByte(packFloatGainToByte(gain)); DependencyManager::get<AudioClient>()->setSystemInjectorGain(gain); } }); From c15813b44225235a96fd507d031c6e6650d0eedb Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Fri, 22 Mar 2019 17:58:17 -0700 Subject: [PATCH 22/26] Cleanup --- assignment-client/src/audio/AudioMixerClientData.cpp | 6 +++--- interface/src/scripting/Audio.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b8d3ec62a6..41b72c04d2 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -200,11 +200,11 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const if (avatarUUID.isNull()) { // set the MASTER avatar gain setMasterAvatarGain(gain); - qCDebug(audio) << "Setting MASTER avatar gain for " << uuid << " to " << gain; + qCDebug(audio) << "Setting MASTER avatar gain for" << uuid << "to" << gain; } else { // set the per-source avatar gain setGainForAvatar(avatarUUID, gain); - qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUUID << "] to " << gain; + qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUUID << "] to" << gain; } } @@ -216,7 +216,7 @@ void AudioMixerClientData::parseInjectorGainSet(ReceivedMessage& message, const float gain = unpackFloatGainFromByte(packedGain); setMasterInjectorGain(gain); - qCDebug(audio) << "Setting MASTER injector gain for " << uuid << " to " << gain; + qCDebug(audio) << "Setting MASTER injector gain for" << uuid << "to" << gain; } void AudioMixerClientData::setGainForAvatar(QUuid nodeID, float gain) { diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 330ed7abfe..4f2171d451 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -404,13 +404,13 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { void Audio::setAvatarGain(float gain) { withWriteLock([&] { // ask the NodeList to set the master avatar gain - DependencyManager::get<NodeList>()->setAvatarGain("", gain); + DependencyManager::get<NodeList>()->setAvatarGain(QUuid(), gain); }); } float Audio::getAvatarGain() { return resultWithReadLock<float>([&] { - return DependencyManager::get<NodeList>()->getAvatarGain(""); + return DependencyManager::get<NodeList>()->getAvatarGain(QUuid()); }); } From 3d7c3e7b6f6fe3d737cc86e038966617397258f5 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Sat, 23 Mar 2019 06:48:37 -0700 Subject: [PATCH 23/26] Persist the audio-mixer settings across domain changes and server resets --- libraries/networking/src/NodeList.cpp | 38 ++++++++++++++++++--------- libraries/networking/src/NodeList.h | 3 ++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index eec710322e..0021a594bc 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -265,8 +265,6 @@ void NodeList::reset(bool skipDomainHandlerReset) { _avatarGainMap.clear(); _avatarGainMapLock.unlock(); - _injectorGain = 0.0f; - if (!skipDomainHandlerReset) { // clear the domain connection information, unless they're the ones that asked us to reset _domainHandler.softReset(); @@ -1018,6 +1016,14 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { // also send them the current ignore radius state. sendIgnoreRadiusStateToNode(newNode); + + // also send the current avatar and injector gains + if (_avatarGain != 0.0f) { + setAvatarGain(QUuid(), _avatarGain); + } + if (_injectorGain != 0.0f) { + setInjectorGain(_injectorGain); + } } if (newNode->getType() == NodeType::AvatarMixer) { // this is a mixer that we just added - it's unlikely it knows who we were previously ignoring in this session, @@ -1064,13 +1070,17 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { if (nodeID.isNull()) { qCDebug(networking) << "Sending Set MASTER Avatar Gain packet with Gain:" << gain; - } else { - qCDebug(networking) << "Sending Set Avatar Gain packet with UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; - } - sendPacket(std::move(setAvatarGainPacket), *audioMixer); - QWriteLocker lock{ &_avatarGainMapLock }; - _avatarGainMap[nodeID] = gain; + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + _avatarGain = gain; + + } else { + qCDebug(networking) << "Sending Set Avatar Gain packet with UUID:" << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + QWriteLocker lock{ &_avatarGainMapLock }; + _avatarGainMap[nodeID] = gain; + } } else { qWarning() << "Couldn't find audio mixer to send set gain request"; @@ -1081,10 +1091,14 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { } float NodeList::getAvatarGain(const QUuid& nodeID) { - QReadLocker lock{ &_avatarGainMapLock }; - auto it = _avatarGainMap.find(nodeID); - if (it != _avatarGainMap.cend()) { - return it->second; + if (nodeID.isNull()) { + return _avatarGain; + } else { + QReadLocker lock{ &_avatarGainMapLock }; + auto it = _avatarGainMap.find(nodeID); + if (it != _avatarGainMap.cend()) { + return it->second; + } } return 0.0f; } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index d2a1212d64..f871560fba 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -183,7 +183,8 @@ private: mutable QReadWriteLock _avatarGainMapLock; tbb::concurrent_unordered_map<QUuid, float, UUIDHasher> _avatarGainMap; - std::atomic<float> _injectorGain { 0.0f }; + std::atomic<float> _avatarGain { 0.0f }; // in dB + std::atomic<float> _injectorGain { 0.0f }; // in dB void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); #if defined(Q_OS_ANDROID) From 7b56bef83815b230cda13711165f60e15c7bfd58 Mon Sep 17 00:00:00 2001 From: Ken Cooke <ken@highfidelity.io> Date: Sat, 23 Mar 2019 16:00:02 -0700 Subject: [PATCH 24/26] Prototype an updated Audio tab with 3 independent volume controls --- interface/resources/qml/hifi/audio/Audio.qml | 158 ++++++++++++++++-- .../qml/hifi/audio/LoopbackAudio.qml | 16 +- .../qml/hifi/audio/PlaySampleSound.qml | 16 +- 3 files changed, 158 insertions(+), 32 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index cd0f290da4..8fdd0368e2 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -87,8 +87,19 @@ Rectangle { } function updateMyAvatarGainFromQML(sliderValue, isReleased) { - if (Users.getAvatarGain(myAvatarUuid) != sliderValue) { - Users.setAvatarGain(myAvatarUuid, sliderValue); + if (AudioScriptingInterface.getAvatarGain() != sliderValue) { + AudioScriptingInterface.setAvatarGain(sliderValue); + } + } + function updateInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getInjectorGain() != sliderValue) { + AudioScriptingInterface.setInjectorGain(sliderValue); // server side + AudioScriptingInterface.setLocalInjectorGain(sliderValue); // client side + } + } + function updateSystemInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getSystemInjectorGain() != sliderValue) { + AudioScriptingInterface.setSystemInjectorGain(sliderValue); } } @@ -334,6 +345,7 @@ Rectangle { color: hifi.colors.white; text: qsTr("Choose input device"); } + } ListView { @@ -462,22 +474,22 @@ Rectangle { } Item { - id: gainContainer + id: avatarGainContainer x: margins.paddings; anchors.top: outputView.bottom; anchors.topMargin: 10; width: parent.width - margins.paddings*2 - height: gainSliderTextMetrics.height + height: avatarGainSliderTextMetrics.height HifiControlsUit.Slider { - id: gainSlider + id: avatarGainSlider anchors.right: parent.right height: parent.height width: 200 minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 - value: Users.getAvatarGain(myAvatarUuid) + value: AudioScriptingInterface.getAvatarGain() onValueChanged: { updateMyAvatarGainFromQML(value, false); } @@ -493,7 +505,7 @@ Rectangle { // Do nothing. } onDoubleClicked: { - gainSlider.value = 0.0 + avatarGainSlider.value = 0.0 } onPressed: { // Pass through to Slider @@ -507,13 +519,13 @@ Rectangle { } } TextMetrics { - id: gainSliderTextMetrics - text: gainSliderText.text - font: gainSliderText.font + id: avatarGainSliderTextMetrics + text: avatarGainSliderText.text + font: avatarGainSliderText.font } RalewayRegular { // The slider for my card is special, it controls the master gain - id: gainSliderText; + id: avatarGainSliderText; text: "Avatar volume"; size: 16; anchors.left: parent.left; @@ -523,15 +535,129 @@ Rectangle { } } + Item { + id: injectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: injectorGainSliderTextMetrics.height + + HifiControlsUit.Slider { + id: injectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getInjectorGain() + onValueChanged: { + updateInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + injectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: injectorGainSliderTextMetrics + text: injectorGainSliderText.text + font: injectorGainSliderText.font + } + RalewayRegular { + id: injectorGainSliderText; + text: "Environment volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } + + Item { + id: systemInjectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: systemInjectorGainSliderTextMetrics.height + + HifiControlsUit.Slider { + id: systemInjectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getSystemInjectorGain() + onValueChanged: { + updateSystemInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateSystemInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + systemInjectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: systemInjectorGainSliderTextMetrics + text: systemInjectorGainSliderText.text + font: systemInjectorGainSliderText.font + } + RalewayRegular { + id: systemInjectorGainSliderText; + text: "System Sound volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } + AudioControls.PlaySampleSound { id: playSampleSound x: margins.paddings - anchors.top: gainContainer.bottom; + anchors.top: systemInjectorGainContainer.bottom; anchors.topMargin: 10; - - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } } } } diff --git a/interface/resources/qml/hifi/audio/LoopbackAudio.qml b/interface/resources/qml/hifi/audio/LoopbackAudio.qml index 8ec0ffc496..74bc0f67dc 100644 --- a/interface/resources/qml/hifi/audio/LoopbackAudio.qml +++ b/interface/resources/qml/hifi/audio/LoopbackAudio.qml @@ -44,7 +44,7 @@ RowLayout { } HifiControlsUit.Button { - text: audioLoopedBack ? qsTr("STOP TESTING YOUR VOICE") : qsTr("TEST YOUR VOICE"); + text: audioLoopedBack ? qsTr("STOP TESTING") : qsTr("TEST YOUR VOICE"); color: audioLoopedBack ? hifi.buttons.red : hifi.buttons.blue; onClicked: { if (audioLoopedBack) { @@ -57,11 +57,11 @@ RowLayout { } } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: audioLoopedBack ? qsTr("Speak in your input") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: audioLoopedBack ? qsTr("Speak in your input") : ""; +// } } diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index b9d9727dab..0eb78f3efe 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -56,16 +56,16 @@ RowLayout { HifiConstants { id: hifi; } HifiControlsUit.Button { - text: isPlaying ? qsTr("STOP TESTING YOUR SOUND") : qsTr("TEST YOUR SOUND"); + text: isPlaying ? qsTr("STOP TESTING") : qsTr("TEST YOUR SOUND"); color: isPlaying ? hifi.buttons.red : hifi.buttons.blue; onClicked: isPlaying ? stopSound() : playSound(); } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: isPlaying ? qsTr("Listen to your output") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: isPlaying ? qsTr("Listen to your output") : ""; +// } } From a2d754cebd786741ec7d714576d4462ee3618177 Mon Sep 17 00:00:00 2001 From: Wayne Chen <chen.wayne@outlook.com> Date: Tue, 26 Mar 2019 10:26:29 -0700 Subject: [PATCH 25/26] fixing audio screen with master --- interface/resources/qml/hifi/audio/Audio.qml | 4 ++++ .../qml/hifi/audio/LoopbackAudio.qml | 19 +++++++++++-------- .../qml/hifi/audio/PlaySampleSound.qml | 17 ++++++++++------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 8fdd0368e2..fe86d7d930 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -540,6 +540,8 @@ Rectangle { x: margins.paddings; width: parent.width - margins.paddings*2 height: injectorGainSliderTextMetrics.height + anchors.top: avatarGainContainer.bottom; + anchors.topMargin: 10; HifiControlsUit.Slider { id: injectorGainSlider @@ -599,6 +601,8 @@ Rectangle { x: margins.paddings; width: parent.width - margins.paddings*2 height: systemInjectorGainSliderTextMetrics.height + anchors.top: injectorGainContainer.bottom; + anchors.topMargin: 10; HifiControlsUit.Slider { id: systemInjectorGainSlider diff --git a/interface/resources/qml/hifi/audio/LoopbackAudio.qml b/interface/resources/qml/hifi/audio/LoopbackAudio.qml index 74bc0f67dc..8d1099d38c 100644 --- a/interface/resources/qml/hifi/audio/LoopbackAudio.qml +++ b/interface/resources/qml/hifi/audio/LoopbackAudio.qml @@ -44,8 +44,11 @@ RowLayout { } HifiControlsUit.Button { - text: audioLoopedBack ? qsTr("STOP TESTING") : qsTr("TEST YOUR VOICE"); + text: audioLoopedBack ? qsTr("STOP TESTING VOICE") : qsTr("TEST YOUR VOICE"); color: audioLoopedBack ? hifi.buttons.red : hifi.buttons.blue; + fontSize: 15; + width: 200; + height: 32; onClicked: { if (audioLoopedBack) { loopbackTimer.stop(); @@ -57,11 +60,11 @@ RowLayout { } } -// RalewayRegular { -// Layout.leftMargin: 2; -// size: 14; -// color: "white"; -// font.italic: true -// text: audioLoopedBack ? qsTr("Speak in your input") : ""; -// } + RalewayRegular { + Layout.leftMargin: 2; + size: 14; + color: "white"; + font.italic: true + text: audioLoopedBack ? qsTr("Speak in your input") : ""; + } } diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index 0eb78f3efe..4675f6087a 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -59,13 +59,16 @@ RowLayout { text: isPlaying ? qsTr("STOP TESTING") : qsTr("TEST YOUR SOUND"); color: isPlaying ? hifi.buttons.red : hifi.buttons.blue; onClicked: isPlaying ? stopSound() : playSound(); + fontSize: 15; + width: 200; + height: 32; } -// RalewayRegular { -// Layout.leftMargin: 2; -// size: 14; -// color: "white"; -// font.italic: true -// text: isPlaying ? qsTr("Listen to your output") : ""; -// } + RalewayRegular { + Layout.leftMargin: 2; + size: 14; + color: "white"; + font.italic: true + text: isPlaying ? qsTr("Listen to your output") : ""; + } } From c0b71150eafa60947b5a1390ac8c18795cb25dd8 Mon Sep 17 00:00:00 2001 From: Wayne Chen <chen.wayne@outlook.com> Date: Tue, 26 Mar 2019 10:58:04 -0700 Subject: [PATCH 26/26] removing an extra button --- interface/resources/qml/hifi/audio/Audio.qml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 69cbad458b..195dd78a0e 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -438,14 +438,6 @@ Rectangle { color: hifi.colors.white; text: qsTr("Choose output device"); } - - AudioControls.PlaySampleSound { - x: margins.paddings - - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { right: parent.right } - } } ListView {