move audio zones to zone entity properties

This commit is contained in:
HifiExperiments 2024-03-02 11:27:04 -08:00
parent d928cb4ccd
commit b8d2d71e07
18 changed files with 610 additions and 91 deletions

View file

@ -31,6 +31,7 @@
#include <StDev.h>
#include <UUID.h>
#include <CPUDetect.h>
#include <ZoneEntityItem.h>
#include "AudioLogging.h"
#include "AudioHelpers.h"
@ -39,6 +40,7 @@
#include "AvatarAudioStream.h"
#include "InjectedAudioStream.h"
#include "crash-handler/CrashHandler.h"
#include "../entities/AssignmentParentFinder.h"
using namespace std;
@ -56,9 +58,7 @@ float AudioMixer::_noiseMutingThreshold{ DEFAULT_NOISE_MUTING_THRESHOLD };
float AudioMixer::_attenuationPerDoublingInDistance{ DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE };
map<QString, shared_ptr<CodecPlugin>> AudioMixer::_availableCodecs{ };
QStringList AudioMixer::_codecPreferenceOrder{};
vector<AudioMixer::ZoneDescription> AudioMixer::_audioZones;
vector<AudioMixer::ZoneSettings> AudioMixer::_zoneSettings;
vector<AudioMixer::ReverbSettings> AudioMixer::_zoneReverbSettings;
unordered_map<QString, AudioMixer::ZoneSettings> AudioMixer::_audioZones;
AudioMixer::AudioMixer(ReceivedMessage& message) :
ThreadedAssignment(message)
@ -112,6 +112,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
PacketReceiver::makeSourcedListenerReference<AudioMixer>(this, &AudioMixer::handleNodeMuteRequestPacket));
packetReceiver.registerListener(PacketType::KillAvatar,
PacketReceiver::makeSourcedListenerReference<AudioMixer>(this, &AudioMixer::handleKillAvatarPacket));
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
PacketReceiver::makeSourcedListenerReference<AudioMixer>(this, &AudioMixer::handleOctreePacket));
packetReceiver.registerListenerForTypes({
PacketType::ReplicatedMicrophoneAudioNoEcho,
@ -405,7 +407,7 @@ void AudioMixer::start() {
// prepare the NodeList
nodeList->addSetOfNodeTypesToNodeInterestSet({
NodeType::Agent, NodeType::EntityScriptServer,
NodeType::Agent, NodeType::EntityScriptServer, NodeType::EntityServer,
NodeType::UpstreamAudioMixer, NodeType::DownstreamAudioMixer
});
nodeList->linkedDataCreateCallback = [&](Node* node) { getOrCreateClientData(node); };
@ -417,12 +419,19 @@ void AudioMixer::start() {
parseSettingsObject(settingsObject);
}
setupEntityQuery();
// mix state
unsigned int frame = 1;
while (!_isFinished) {
auto ticTimer = _ticTiming.timer();
// Set our query each frame
{
_entityViewer.queryOctree();
}
if (_startFrameTimestamp.time_since_epoch().count() == 0) {
_startFrameTimestamp = _idealFrameTimestamp = p_high_resolution_clock::now();
} else {
@ -555,8 +564,6 @@ void AudioMixer::clearDomainSettings() {
_noiseMutingThreshold = DEFAULT_NOISE_MUTING_THRESHOLD;
_codecPreferenceOrder.clear();
_audioZones.clear();
_zoneSettings.clear();
_zoneReverbSettings.clear();
}
void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
@ -727,8 +734,13 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
if (allOk) {
glm::vec3 corner(xMin, yMin, zMin);
glm::vec3 dimensions(xMax - xMin, yMax - yMin, zMax - zMin);
AABox zoneAABox(corner, dimensions);
_audioZones.push_back({ zoneName, zoneAABox });
Transform t;
t.setTranslation(corner + 0.5f * dimensions);
t.setScale(dimensions);
_audioZones[zoneName].inverseTransform = t.getInverseMatrix();
_audioZones[zoneName].volume = dimensions.x * dimensions.y * dimensions.z;
qCDebug(audio) << "Added zone:" << zoneName << "(corner:" << corner << ", dimensions:" << dimensions << ")";
}
}
@ -749,28 +761,17 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
coefficientObject.contains(LISTENER) &&
coefficientObject.contains(COEFFICIENT)) {
auto itSource = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) {
return description.name == coefficientObject.value(SOURCE).toString();
});
auto itListener = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) {
return description.name == coefficientObject.value(LISTENER).toString();
});
auto itSource = _audioZones.find(coefficientObject.value(SOURCE).toString());
bool ok;
float coefficient = coefficientObject.value(COEFFICIENT).toString().toFloat(&ok);
if (ok && coefficient <= 1.0f && itSource != _audioZones.end()) {
auto listener = coefficientObject.value(LISTENER).toString();
itSource->second.listeners.emplace_back(listener);
itSource->second.coefficients.emplace_back(coefficient);
if (ok && coefficient <= 1.0f &&
itSource != end(_audioZones) &&
itListener != end(_audioZones)) {
ZoneSettings settings;
settings.source = itSource - begin(_audioZones);
settings.listener = itListener - begin(_audioZones);
settings.coefficient = coefficient;
_zoneSettings.push_back(settings);
qCDebug(audio) << "Added Coefficient:" << itSource->name << itListener->name << settings.coefficient;
qCDebug(audio) << "Added Coefficient:" << itSource->first << listener << coefficient;
}
}
}
@ -791,21 +792,16 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
reverbObject.contains(WET_LEVEL)) {
bool okReverbTime, okWetLevel;
auto itZone = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) {
return description.name == reverbObject.value(ZONE).toString();
});
auto itZone = _audioZones.find(reverbObject.value(ZONE).toString());
float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime);
float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel);
if (okReverbTime && okWetLevel && itZone != end(_audioZones)) {
ReverbSettings settings;
settings.zone = itZone - begin(_audioZones);
settings.reverbTime = reverbTime;
settings.wetLevel = wetLevel;
if (okReverbTime && okWetLevel && itZone != _audioZones.end()) {
itZone->second.reverbEnabled = true;
itZone->second.reverbTime = reverbTime;
itZone->second.wetLevel = wetLevel;
_zoneReverbSettings.push_back(settings);
qCDebug(audio) << "Added Reverb:" << itZone->name << reverbTime << wetLevel;
qCDebug(audio) << "Added Reverb:" << itZone->first << reverbTime << wetLevel;
}
}
}
@ -813,6 +809,107 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
}
}
void AudioMixer::setupEntityQuery() {
_entityViewer.init();
EntityTreePointer entityTree = _entityViewer.getTree();
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
DependencyManager::set<AssignmentParentFinder>(entityTree);
connect(entityTree.get(), &EntityTree::addingEntityPointer, this, &AudioMixer::entityAdded);
connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AudioMixer::entityRemoved);
// ES query: {"type": "Zone"}
QJsonObject zoneQuery;
zoneQuery["type"] = "Zone";
QJsonObject queryFlags;
queryFlags["includeAncestors"] = true;
queryFlags["includeDescendants"] = true;
zoneQuery["flags"] = queryFlags;
zoneQuery["name"] = true; // Handy for debugging.
_entityViewer.getOctreeQuery().setJSONParameters(zoneQuery);
}
void AudioMixer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
PacketType packetType = message->getType();
switch (packetType) {
case PacketType::OctreeStats:
{ // Ignore stats, but may have a different Entity packet appended.
OctreeHeadlessViewer::parseOctreeStats(message, senderNode);
const auto piggyBackedSizeWithHeader = message->getBytesLeftToRead();
if (piggyBackedSizeWithHeader > 0) {
// pull out the piggybacked packet and create a new QSharedPointer<NLPacket> for it
auto buffer = std::unique_ptr<char[]>(new char[piggyBackedSizeWithHeader]);
memcpy(buffer.get(), message->getRawMessage() + message->getPosition(), piggyBackedSizeWithHeader);
auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr());
auto newMessage = QSharedPointer<ReceivedMessage>::create(*newPacket);
handleOctreePacket(newMessage, senderNode);
}
break;
}
case PacketType::EntityData:
_entityViewer.processDatagram(*message, senderNode);
break;
case PacketType::EntityErase:
_entityViewer.processEraseMessage(*message, senderNode);
break;
default:
qCDebug(audio) << "Unexpected packet type:" << packetType;
break;
}
}
void updateAudioZone(EntityItem* entity, std::unordered_map<QString, AudioMixer::ZoneSettings>& audioZones) {
auto zoneEntity = (ZoneEntityItem*)entity;
auto& audioZone = audioZones[entity->getID().toString()];
auto& audioSettings = zoneEntity->getAudioProperties();
vec3 dimensions = entity->getScaledDimensions();
Transform t;
t.setTranslation(entity->getWorldPosition());
t.setScale(dimensions);
t.setRotation(entity->getWorldOrientation());
audioZone.inverseTransform = t.getInverseMatrix();
audioZone.volume = dimensions.x * dimensions.y * dimensions.z;
audioZone.reverbEnabled = audioSettings.getReverbEnabled();
audioZone.reverbTime = audioSettings.getReverbTime();
audioZone.wetLevel = audioSettings.getReverbWetLevel();
audioZone.listeners.clear();
auto listenerZones = audioSettings.getListenerZones();
audioZone.listeners.reserve(listenerZones.length());
for (auto& listener : listenerZones) {
audioZone.listeners.push_back(listener.toString());
}
audioZone.coefficients = audioSettings.getListenerAttenuationCoefficients().toStdVector();
/*qCDebug(audio) << "Updated audio zone:" << entity->getID().toString() << "(position:" << t.getTranslation()
<< ", dimensions:" << t.getScale() << ")";*/
}
void AudioMixer::entityAdded(EntityItem* entity) {
if (entity->getType() == EntityTypes::Zone) {
updateAudioZone(entity, _audioZones);
entity->registerChangeHandler([entity](const EntityItemID& entityItemID) {
updateAudioZone(entity, _audioZones);
});
}
}
void AudioMixer::entityRemoved(EntityItem* entity) {
if (entity->getType() == EntityTypes::Zone) {
_audioZones.erase(entity->getID().toString());
}
}
AudioMixer::Timer::Timing::Timing(uint64_t& sum) : _sum(sum) {
_timing = p_high_resolution_clock::now();
}

View file

@ -14,7 +14,7 @@
#include <QtCore/QSharedPointer>
#include <AABox.h>
#include <Transform.h>
#include <AudioHRTF.h>
#include <AudioRingBuffer.h>
#include <ThreadedAssignment.h>
@ -25,6 +25,8 @@
#include "AudioMixerStats.h"
#include "AudioMixerSlavePool.h"
#include "../entities/EntityTreeHeadlessViewer.h"
class PositionalAudioStream;
class AvatarAudioStream;
class AudioHRTF;
@ -36,28 +38,22 @@ class AudioMixer : public ThreadedAssignment {
public:
AudioMixer(ReceivedMessage& message);
struct ZoneDescription {
QString name;
AABox area;
};
struct ZoneSettings {
int source;
int listener;
float coefficient;
};
struct ReverbSettings {
int zone;
float reverbTime;
float wetLevel;
glm::mat4 inverseTransform;
float volume { FLT_MAX };
bool reverbEnabled { false };
float reverbTime { 0.0f };
float wetLevel { 0.0f };
std::vector<QString> listeners;
std::vector<float> coefficients;
};
static int getStaticJitterFrames() { return _numStaticJitterFrames; }
static bool shouldMute(float quietestFrame) { return quietestFrame > _noiseMutingThreshold; }
static float getAttenuationPerDoublingInDistance() { return _attenuationPerDoublingInDistance; }
static const std::vector<ZoneDescription>& getAudioZones() { return _audioZones; }
static const std::vector<ZoneSettings>& getZoneSettings() { return _zoneSettings; }
static const std::vector<ReverbSettings>& getReverbSettings() { return _zoneReverbSettings; }
static const std::unordered_map<QString, ZoneSettings>& getAudioZones() { return _audioZones; }
static const std::pair<QString, CodecPluginPointer> negotiateCodec(std::vector<QString> codecs);
static bool shouldReplicateTo(const Node& from, const Node& to) {
@ -72,12 +68,17 @@ public slots:
void run() override;
void sendStatsPacket() override;
// Audio zone possibly changed
void entityAdded(EntityItem* entity);
void entityRemoved(EntityItem* entity);
private slots:
// packet handlers
void handleMuteEnvironmentPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleNodeMuteRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleNodeKilled(SharedNodePointer killedNode);
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void queueAudioPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> packet);
@ -146,14 +147,17 @@ private:
static std::map<QString, CodecPluginPointer> _availableCodecs;
static QStringList _codecPreferenceOrder;
static std::vector<ZoneDescription> _audioZones;
static std::vector<ZoneSettings> _zoneSettings;
static std::vector<ReverbSettings> _zoneReverbSettings;
static std::unordered_map<QString, ZoneSettings> _audioZones;
float _throttleStartTarget = 0.9f;
float _throttleBackoffTarget = 0.44f;
AudioMixerSlave::SharedData _workerSharedData;
void setupEntityQuery();
// Attach to entity tree for audio zone info.
EntityTreeHeadlessViewer _entityViewer;
};
#endif // hifi_AudioMixer_h

View file

@ -646,27 +646,36 @@ void sendMutePacket(const SharedNodePointer& node, AudioMixerClientData& data) {
data.setShouldMuteClient(false);
}
const AABox UNIT_BOX(vec3(-0.5f), vec3(1.0f));
void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& data) {
bool hasReverb = false;
float reverbTime, wetLevel;
auto& reverbSettings = AudioMixer::getReverbSettings();
auto& audioZones = AudioMixer::getAudioZones();
AvatarAudioStream* stream = data.getAvatarAudioStream();
glm::vec3 streamPosition = stream->getPosition();
vec4 streamPosition = vec4(stream->getPosition(), 1.0f);
// find reverb properties
for (const auto& settings : reverbSettings) {
AABox box = audioZones[settings.zone].area;
if (box.contains(streamPosition)) {
hasReverb = true;
reverbTime = settings.reverbTime;
wetLevel = settings.wetLevel;
break;
QString bestZone;
float bestZoneVolume = FLT_MAX;
for (const auto& zone : audioZones) {
if (zone.second.reverbEnabled) {
vec4 localPosition = zone.second.inverseTransform * streamPosition;
if (UNIT_BOX.contains(localPosition) && zone.second.volume < bestZoneVolume) {
bestZone = zone.first;
bestZoneVolume = zone.second.volume;
}
}
}
if (bestZoneVolume < FLT_MAX) {
const auto& zone = audioZones.at(bestZone);
hasReverb = zone.reverbEnabled;
reverbTime = zone.reverbTime;
wetLevel = zone.wetLevel;
}
// check if data changed
bool dataChanged = (stream->hasReverb() != hasReverb) ||
(stream->hasReverb() && (stream->getRevebTime() != reverbTime || stream->getWetLevel() != wetLevel));
@ -759,18 +768,40 @@ float computeGain(float masterAvatarGain,
}
auto& audioZones = AudioMixer::getAudioZones();
auto& zoneSettings = AudioMixer::getZoneSettings();
// find distance attenuation coefficient
float attenuationPerDoublingInDistance = AudioMixer::getAttenuationPerDoublingInDistance();
for (const auto& settings : zoneSettings) {
if (audioZones[settings.source].area.contains(streamToAdd.getPosition()) &&
audioZones[settings.listener].area.contains(listeningNodeStream.getPosition())) {
attenuationPerDoublingInDistance = settings.coefficient;
break;
float bestZonesVolume = FLT_MAX;
float bestZonesCoefficient;
for (const auto& sourceZone : audioZones) {
if (sourceZone.second.listeners.size() > 0 && sourceZone.second.listeners.size() == sourceZone.second.coefficients.size()) {
vec4 localSourcePosition = sourceZone.second.inverseTransform * vec4(streamToAdd.getPosition(), 1.0f);
if (UNIT_BOX.contains(localSourcePosition)) {
size_t listenerIndex = 0;
for (const auto& listener : sourceZone.second.listeners) {
const auto& listenerZone = audioZones.find(listener);
if (listenerZone != audioZones.end()) {
vec4 localListenerPosition = listenerZone->second.inverseTransform * vec4(listeningNodeStream.getPosition(), 1.0f);
if (UNIT_BOX.contains(localListenerPosition)) {
// This isn't an exact solution, but we target the smallest sum of volumes of the source and listener zones
const float zonesVolume = sourceZone.second.volume + listenerZone->second.volume;
if (zonesVolume < bestZonesVolume) {
bestZonesVolume = zonesVolume;
bestZonesCoefficient = sourceZone.second.coefficients[listenerIndex];
}
}
}
listenerIndex++;
}
}
}
}
if (bestZonesVolume < FLT_MAX) {
attenuationPerDoublingInDistance = bestZonesCoefficient;
}
if (attenuationPerDoublingInDistance < 0.0f) {
// translate a negative zone setting to distance limit
const float MIN_DISTANCE_LIMIT = ATTN_DISTANCE_REF + 1.0f; // silent after 1m

View file

@ -1085,7 +1085,7 @@ void AvatarMixer::setupEntityQuery() {
DependencyManager::set<AssignmentParentFinder>(entityTree);
connect(entityTree.get(), &EntityTree::addingEntityPointer, this, &AvatarMixer::entityAdded);
connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AvatarMixer::entityChange);
connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AvatarMixer::entityRemoved);
// ES query: {"avatarPriority": true, "type": "Zone"}
QJsonObject priorityZoneQuery;
@ -1140,7 +1140,7 @@ void AvatarMixer::entityAdded(EntityItem* entity) {
if (entity->getType() == EntityTypes::Zone) {
_dirtyHeroStatus = true;
entity->registerChangeHandler([this](const EntityItemID& entityItemID) {
entityChange();
_dirtyHeroStatus = true;
});
}
}
@ -1151,10 +1151,6 @@ void AvatarMixer::entityRemoved(EntityItem * entity) {
}
}
void AvatarMixer::entityChange() {
_dirtyHeroStatus = true;
}
void AvatarMixer::aboutToFinish() {
DependencyManager::destroy<ResourceManager>();
DependencyManager::destroy<ResourceCacheSharedItems>();

View file

@ -52,7 +52,6 @@ public slots:
// Avatar zone possibly changed
void entityAdded(EntityItem* entity);
void entityRemoved(EntityItem* entity);
void entityChange();
private slots:
void queueIncomingPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node);

View file

@ -1239,7 +1239,7 @@ void OctreeServer::beginRunning() {
// we need to ask the DS about agents so we can ping/reply with them
nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer,
NodeType::AvatarMixer });
NodeType::AvatarMixer, NodeType::AudioMixer });
beforeRun(); // after payload has been processed

View file

@ -1235,7 +1235,7 @@
{
"name": "zones",
"type": "table",
"label": "Zones",
"label": "Zones (deprecated, use Zone Entities)",
"help": "In this table you can define a set of zones in which you can specify various audio properties.",
"numbered": false,
"content_setting": true,
@ -1287,7 +1287,7 @@
{
"name": "attenuation_coefficients",
"type": "table",
"label": "Attenuation Coefficients",
"label": "Attenuation Coefficients (deprecated, use Zone Entities)",
"help": "In this table you can set custom attenuation coefficients between audio zones",
"content_setting": true,
"numbered": true,
@ -1317,7 +1317,7 @@
{
"name": "reverb",
"type": "table",
"label": "Reverb Settings",
"label": "Reverb Settings (deprecated, use Zone Entities)",
"help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet/dry mix of 25%. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet/dry mix of 50%.",
"numbered": true,
"content_setting": true,

View file

@ -44,6 +44,7 @@ AnimationPropertyGroup EntityItemProperties::_staticAnimation;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
HazePropertyGroup EntityItemProperties::_staticHaze;
BloomPropertyGroup EntityItemProperties::_staticBloom;
ZoneAudioPropertyGroup EntityItemProperties::_staticAudio;
KeyLightPropertyGroup EntityItemProperties::_staticKeyLight;
AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight;
GrabPropertyGroup EntityItemProperties::_staticGrab;
@ -87,6 +88,7 @@ void EntityItemProperties::debugDump() const {
getKeyLight().debugDump();
getAmbientLight().debugDump();
getBloom().debugDump();
getAudio().debugDump();
getGrab().debugDump();
qCDebug(entities) << " changed properties...";
@ -613,6 +615,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
changedProperties += _skybox.getChangedProperties();
changedProperties += _haze.getChangedProperties();
changedProperties += _bloom.getChangedProperties();
changedProperties += _audio.getChangedProperties();
CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed);
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
CHECK_PROPERTY_CHANGE(PROP_FILTER_URL, filterURL);
@ -853,7 +856,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* avatar entities, <code>false</code> if they won't be.
* @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from.
*
* @property {Uuid[]} renderWithZones=[]] - A list of entity IDs representing with which zones this entity should render.
* @property {Uuid[]} renderWithZones=[] - A list of entity IDs representing with which zones this entity should render.
* If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within
* one of the zones in this list.
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation
@ -1481,6 +1484,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Entities.ComponentMode} bloomMode="inherit" - Configures the bloom in the zone.
* @property {Entities.Bloom} bloom - The bloom properties of the zone.
*
* @property {Entities.ZoneAudio} audio - The audio properties of the zone.
*
* @property {boolean} flyingAllowed=true - <code>true</code> if visitors can fly in the zone; <code>false</code> if they
* cannot. Only works for domain entities.
* @property {boolean} ghostingAllowed=true - <code>true</code> if visitors with avatar collisions turned off will not
@ -1834,6 +1839,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
_skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_audio.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
}
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
@ -2211,6 +2217,7 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h
_skybox.copyFromScriptValue(object, namesSet, _defaultSettings);
_haze.copyFromScriptValue(object, namesSet, _defaultSettings);
_bloom.copyFromScriptValue(object, namesSet, _defaultSettings);
_audio.copyFromScriptValue(object, namesSet, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(flyingAllowed, bool, setFlyingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(filterURL, QString, setFilterURL);
@ -2496,6 +2503,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
_skybox.merge(other._skybox);
_haze.merge(other._haze);
_bloom.merge(other._bloom);
_audio.merge(other._audio);
COPY_PROPERTY_IF_CHANGED(flyingAllowed);
COPY_PROPERTY_IF_CHANGED(ghostingAllowed);
COPY_PROPERTY_IF_CHANGED(filterURL);
@ -2892,6 +2900,13 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold);
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize);
}
{ // Audio
ADD_GROUP_PROPERTY_TO_MAP(PROP_REVERB_ENABLED, Audio, audio, ReverbEnabled, reverbEnabled);
ADD_GROUP_PROPERTY_TO_MAP(PROP_REVERB_TIME, Audio, audio, ReverbTime, reverbTime);
ADD_GROUP_PROPERTY_TO_MAP(PROP_REVERB_WET_LEVEL, Audio, audio, ReverbWetLevel, reverbWetLevel);
ADD_GROUP_PROPERTY_TO_MAP(PROP_LISTENER_ZONES, Audio, audio, ListenerZones, listenerZones);
ADD_GROUP_PROPERTY_TO_MAP(PROP_LISTENER_ATTENUATION_COEFFICIENTS, Audio, audio, ListenerAttenuationCoefficients, listenerAttenuationCoefficients);
}
ADD_PROPERTY_TO_MAP(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool);
ADD_PROPERTY_TO_MAP(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool);
ADD_PROPERTY_TO_MAP(PROP_FILTER_URL, FilterURL, filterURL, QString);
@ -3307,6 +3322,9 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticBloom.setProperties(properties);
_staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
_staticAudio.setProperties(properties);
_staticAudio.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed());
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL());
@ -3775,6 +3793,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getAudio().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
@ -4147,6 +4166,7 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_haze.markAllChanged();
_bloom.markAllChanged();
_audio.markAllChanged();
_flyingAllowedChanged = true;
_ghostingAllowedChanged = true;
_filterURLChanged = true;
@ -4738,6 +4758,7 @@ QList<QString> EntityItemProperties::listChangedProperties() {
getSkybox().listChangedProperties(out);
getHaze().listChangedProperties(out);
getBloom().listChangedProperties(out);
getAudio().listChangedProperties(out);
if (flyingAllowedChanged()) {
out += "flyingAllowed";
}

View file

@ -61,6 +61,7 @@
#include "BloomPropertyGroup.h"
#include "PulsePropertyGroup.h"
#include "RingGizmoPropertyGroup.h"
#include "ZoneAudioPropertyGroup.h"
#include "MaterialMappingMode.h"
#include "BillboardMode.h"
@ -331,6 +332,7 @@ public:
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup);
DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup);
DEFINE_PROPERTY_GROUP(Audio, audio, ZoneAudioPropertyGroup);
DEFINE_PROPERTY(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool, ZoneEntityItem::DEFAULT_FLYING_ALLOWED);
DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED);
DEFINE_PROPERTY(PROP_FILTER_URL, FilterURL, filterURL, QString, ZoneEntityItem::DEFAULT_FILTER_URL);

View file

@ -167,6 +167,11 @@ enum EntityPropertyList {
PROP_DERIVED_32,
PROP_DERIVED_33,
PROP_DERIVED_34,
PROP_DERIVED_35,
PROP_DERIVED_36,
PROP_DERIVED_37,
PROP_DERIVED_38,
PROP_DERIVED_39,
PROP_AFTER_LAST_ITEM,
@ -301,6 +306,12 @@ enum EntityPropertyList {
PROP_AVATAR_PRIORITY = PROP_DERIVED_33,
// Screen-sharing
PROP_SCREENSHARE = PROP_DERIVED_34,
// Audio
PROP_REVERB_ENABLED = PROP_DERIVED_35,
PROP_REVERB_TIME = PROP_DERIVED_36,
PROP_REVERB_WET_LEVEL = PROP_DERIVED_37,
PROP_LISTENER_ZONES = PROP_DERIVED_38,
PROP_LISTENER_ATTENUATION_COEFFICIENTS = PROP_DERIVED_39,
// Polyvox
PROP_VOXEL_VOLUME_SIZE = PROP_DERIVED_0,

View file

@ -0,0 +1,194 @@
//
// ZoneAudioPropertyGroup.cpp
// libraries/entities/src
//
// Created by HifiExperiments on 11/28/23
// Copyright 2023 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#include "ZoneAudioPropertyGroup.h"
#include <OctreePacketData.h>
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
void ZoneAudioPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_REVERB_ENABLED, Audio, audio, ReverbEnabled, reverbEnabled);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_REVERB_TIME, Audio, audio, ReverbTime, reverbTime);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_REVERB_WET_LEVEL, Audio, audio, ReverbWetLevel, reverbWetLevel);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_LISTENER_ZONES, Audio, audio, ListenerZones, listenerZones);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_LISTENER_ATTENUATION_COEFFICIENTS, Audio, audio, ListenerAttenuationCoefficients, listenerAttenuationCoefficients);
}
void ZoneAudioPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(audio, reverbEnabled, bool, setReverbEnabled);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(audio, reverbTime, float, setReverbTime);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(audio, reverbWetLevel, float, setReverbWetLevel);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(audio, listenerZones, qVectorQUuid, setListenerZones);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(audio, listenerAttenuationCoefficients, qVectorFloat, setListenerAttenuationCoefficients);
}
void ZoneAudioPropertyGroup::merge(const ZoneAudioPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(reverbEnabled);
COPY_PROPERTY_IF_CHANGED(reverbTime);
COPY_PROPERTY_IF_CHANGED(reverbWetLevel);
COPY_PROPERTY_IF_CHANGED(listenerZones);
COPY_PROPERTY_IF_CHANGED(listenerAttenuationCoefficients);
}
void ZoneAudioPropertyGroup::debugDump() const {
qCDebug(entities) << " ZoneAudioPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " _reverbEnabled:" << _reverbEnabled;
qCDebug(entities) << " _reverbTime:" << _reverbTime;
qCDebug(entities) << " _reverbWetLevel:" << _reverbWetLevel;
qCDebug(entities) << " _listenerZones:" << _listenerZones;
qCDebug(entities) << " _listenerAttenuationCoefficients:" << _listenerAttenuationCoefficients;
}
void ZoneAudioPropertyGroup::listChangedProperties(QList<QString>& out) {
if (reverbEnabledChanged()) {
out << "reverbEnabled";
}
if (reverbTimeChanged()) {
out << "reverbTime";
}
if (reverbWetLevelChanged()) {
out << "reverbWetLevel";
}
if (listenerZonesChanged()) {
out << "listenerZones";
}
if (listenerAttenuationCoefficientsChanged()) {
out << "listenerAttenuationCoefficients";
}
}
bool ZoneAudioPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_REVERB_ENABLED, getReverbEnabled());
APPEND_ENTITY_PROPERTY(PROP_REVERB_TIME, getReverbTime());
APPEND_ENTITY_PROPERTY(PROP_REVERB_WET_LEVEL, getReverbWetLevel());
APPEND_ENTITY_PROPERTY(PROP_LISTENER_ZONES, getListenerZones());
APPEND_ENTITY_PROPERTY(PROP_LISTENER_ATTENUATION_COEFFICIENTS, getListenerAttenuationCoefficients());
return true;
}
bool ZoneAudioPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_REVERB_ENABLED, bool, setReverbEnabled);
READ_ENTITY_PROPERTY(PROP_REVERB_TIME, float, setReverbTime);
READ_ENTITY_PROPERTY(PROP_REVERB_WET_LEVEL, float, setReverbWetLevel);
READ_ENTITY_PROPERTY(PROP_LISTENER_ZONES, QVector<QUuid>, setListenerZones);
READ_ENTITY_PROPERTY(PROP_LISTENER_ATTENUATION_COEFFICIENTS, QVector<float>, setListenerAttenuationCoefficients);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_REVERB_ENABLED, ReverbEnabled);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_REVERB_TIME, ReverbTime);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_REVERB_WET_LEVEL, ReverbWetLevel);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_LISTENER_ZONES, ListenerZones);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_LISTENER_ATTENUATION_COEFFICIENTS, ListenerAttenuationCoefficients);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void ZoneAudioPropertyGroup::markAllChanged() {
_reverbEnabledChanged = true;
_reverbTimeChanged = true;
_reverbWetLevelChanged = true;
_listenerZonesChanged = true;
_listenerAttenuationCoefficientsChanged = true;
}
EntityPropertyFlags ZoneAudioPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_REVERB_ENABLED, reverbEnabled);
CHECK_PROPERTY_CHANGE(PROP_REVERB_TIME, reverbTime);
CHECK_PROPERTY_CHANGE(PROP_REVERB_WET_LEVEL, reverbWetLevel);
CHECK_PROPERTY_CHANGE(PROP_LISTENER_ZONES, listenerZones);
CHECK_PROPERTY_CHANGE(PROP_LISTENER_ATTENUATION_COEFFICIENTS, listenerAttenuationCoefficients);
return changedProperties;
}
void ZoneAudioPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Audio, ReverbEnabled, getReverbEnabled);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Audio, ReverbTime, getReverbTime);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Audio, ReverbWetLevel, getReverbWetLevel);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Audio, ListenerZones, getListenerZones);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Audio, ListenerAttenuationCoefficients, getListenerAttenuationCoefficients);
}
bool ZoneAudioPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Audio, ReverbEnabled, reverbEnabled, setReverbEnabled);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Audio, ReverbTime, reverbTime, setReverbTime);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Audio, ReverbWetLevel, reverbWetLevel, setReverbWetLevel);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Audio, ListenerZones, listenerZones, setListenerZones);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Audio, ListenerAttenuationCoefficients, listenerAttenuationCoefficients, setListenerAttenuationCoefficients);
return somethingChanged;
}
EntityPropertyFlags ZoneAudioPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_REVERB_ENABLED;
requestedProperties += PROP_REVERB_TIME;
requestedProperties += PROP_REVERB_WET_LEVEL;
requestedProperties += PROP_LISTENER_ZONES;
requestedProperties += PROP_LISTENER_ATTENUATION_COEFFICIENTS;
return requestedProperties;
}
void ZoneAudioPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_REVERB_ENABLED, getReverbEnabled());
APPEND_ENTITY_PROPERTY(PROP_REVERB_TIME, getReverbTime());
APPEND_ENTITY_PROPERTY(PROP_REVERB_WET_LEVEL, getReverbWetLevel());
APPEND_ENTITY_PROPERTY(PROP_LISTENER_ZONES, getListenerZones());
APPEND_ENTITY_PROPERTY(PROP_LISTENER_ATTENUATION_COEFFICIENTS, getListenerAttenuationCoefficients());
}
int ZoneAudioPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_REVERB_ENABLED, bool, setReverbEnabled);
READ_ENTITY_PROPERTY(PROP_REVERB_TIME, float, setReverbTime);
READ_ENTITY_PROPERTY(PROP_REVERB_WET_LEVEL, float, setReverbWetLevel);
READ_ENTITY_PROPERTY(PROP_LISTENER_ZONES, QVector<QUuid>, setListenerZones);
READ_ENTITY_PROPERTY(PROP_LISTENER_ATTENUATION_COEFFICIENTS, QVector<float>, setListenerAttenuationCoefficients);
return bytesRead;
}

View file

@ -0,0 +1,97 @@
//
// ZoneAudioPropertyGroup.h
// libraries/entities/src
//
// Created by HifiExperiments on 11/28/23
// Copyright 2023 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#ifndef hifi_ZoneAudioPropertyGroup_h
#define hifi_ZoneAudioPropertyGroup_h
#include <stdint.h>
#include <glm/glm.hpp>
#include "PropertyGroup.h"
#include "EntityItemPropertiesMacros.h"
class EntityItemProperties;
class EncodeBitstreamParams;
class OctreePacketData;
class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams;
class ScriptEngine;
class ScriptValue;
/*@jsdoc
* Zone audio is defined by the following properties:
* @typedef {object} Entities.ZoneAudio
* @property {boolean} reverbEnabled=false - If reverb should be enabled for listeners in this zone.
* @property {number} reverbTime=1.0 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
* @property {number} reverbWetLevel=50 - Adjusts the wet/dry percentage, from completely dry (0%) to completely wet (100%).
* @property {Uuid[]} listenerZones=[] - A list of entity IDs representing listener zones with this zone as a source.
* Sounds from this zone being heard by a listener in a listener zone will be attenuated by the corresponding
* <code>listenerAttenuationCoefficient</code>.
* @property {number[]} listenerAttenuationCoefficients=[] - A list of attenuation coefficients. Each coefficient will be
* applied to sounds coming from this zone and being heard by a listener in the corresponding <code>listenerZone</code>.
*/
class ZoneAudioPropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties,
ScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties) const override;
virtual void copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) override;
void merge(const ZoneAudioPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
DEFINE_PROPERTY(PROP_REVERB_ENABLED, ReverbEnabled, reverbEnabled, bool, false);
DEFINE_PROPERTY(PROP_REVERB_TIME, ReverbTime, reverbTime, float, 1.0f);
DEFINE_PROPERTY(PROP_REVERB_WET_LEVEL, ReverbWetLevel, reverbWetLevel, float, 50.0f);
DEFINE_PROPERTY(PROP_LISTENER_ZONES, ListenerZones, listenerZones, QVector<QUuid>, QVector<QUuid>());
DEFINE_PROPERTY(PROP_LISTENER_ATTENUATION_COEFFICIENTS, ListenerAttenuationCoefficients, listenerAttenuationCoefficients, QVector<float>, QVector<float>());
};
#endif // hifi_ZoneAudioPropertyGroup_h

View file

@ -60,6 +60,7 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de
});
_hazeProperties.getProperties(properties);
_bloomProperties.getProperties(properties);
_audioProperties.getProperties(properties);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
@ -90,6 +91,7 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
});
_hazePropertiesChanged |= _hazeProperties.setProperties(properties);
_bloomPropertiesChanged |= _bloomProperties.setProperties(properties);
bool audioPropertiesChanged = _audioProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
@ -103,8 +105,8 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(screenshare, setScreenshare);
somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged ||
_skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged;
somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _skyboxPropertiesChanged ||
_hazePropertiesChanged || _bloomPropertiesChanged || audioPropertiesChanged;
return somethingChanged;
}
@ -168,6 +170,13 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
dataAt += bytesFromBloom;
}
{
int bytesFromAudio = _audioProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged);
bytesRead += bytesFromAudio;
dataAt += bytesFromAudio;
}
READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL);
@ -194,6 +203,7 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
requestedProperties += _skyboxProperties.getEntityProperties(params);
requestedProperties += _hazeProperties.getEntityProperties(params);
requestedProperties += _bloomProperties.getEntityProperties(params);
requestedProperties += _audioProperties.getEntityProperties(params);
requestedProperties += PROP_FLYING_ALLOWED;
requestedProperties += PROP_GHOSTING_ALLOWED;
@ -235,6 +245,8 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_audioProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
@ -267,6 +279,7 @@ void ZoneEntityItem::debugDump() const {
_skyboxProperties.debugDump();
_hazeProperties.debugDump();
_bloomProperties.debugDump();
_audioProperties.debugDump();
}
void ZoneEntityItem::setShapeType(ShapeType type) {

View file

@ -22,6 +22,7 @@
#include "SkyboxPropertyGroup.h"
#include "HazePropertyGroup.h"
#include "BloomPropertyGroup.h"
#include "ZoneAudioPropertyGroup.h"
class ZoneEntityItem : public EntityItem {
public:
@ -46,10 +47,9 @@ public:
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
static bool getZonesArePickable() { return _zonesArePickable; }
@ -90,6 +90,7 @@ public:
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; }
const ZoneAudioPropertyGroup& getAudioProperties() const { return _audioProperties; }
bool getFlyingAllowed() const { return _flyingAllowed; }
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
@ -152,6 +153,7 @@ protected:
SkyboxPropertyGroup _skyboxProperties;
HazePropertyGroup _hazeProperties;
BloomPropertyGroup _bloomProperties;
ZoneAudioPropertyGroup _audioProperties;
bool _flyingAllowed { DEFAULT_FLYING_ALLOWED };
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
@ -167,7 +169,7 @@ protected:
bool _keyLightPropertiesChanged { false };
bool _ambientLightPropertiesChanged { false };
bool _skyboxPropertiesChanged { false };
bool _hazePropertiesChanged{ false };
bool _hazePropertiesChanged { false };
bool _bloomPropertiesChanged { false };
static bool _drawZoneBoundaries;

View file

@ -293,6 +293,7 @@ enum class EntityVersion : PacketVersion {
Mirror,
EntityTags,
WantsKeyboardFocus,
AudioZones,
// Add new versions above here
NUM_PACKET_TYPE,

View file

@ -158,6 +158,21 @@
"bloom.bloomSize": {
"tooltip": "The radius of bloom. The higher the value, the larger the bloom."
},
"audio.reverbEnabled": {
"tooltip": "If reverb should be enabled for listeners in this zone."
},
"audio.reverbTime": {
"tooltip": "The time (seconds) for the reverb tail to decay by 60dB."
},
"audio.reverbWetLevel": {
"tooltip": "Adjusts the wet/dry percentage, from completely dry (0%) to completely wet (100%)."
},
"audio.listenerZones": {
"tooltip": "A list of entity IDs representing listener zones with this zone as a source."
},
"audio.listenerAttenuationCoefficients": {
"tooltip": "A list of attenuation coefficients."
},
"avatarPriority": {
"tooltip": "Alter Avatars' update priorities."
},

View file

@ -620,6 +620,42 @@ const GROUPS = [
}
]
},
{
id: "zone_audio",
label: "ZONE AUDIO",
properties: [
{
label: "Enable Reverb",
type: "bool",
propertyID: "audio.enableReverb"
},
{
label: "Reverb Time",
type: "number-draggable",
min: 0,
max: 10,
step: 0.1,
decimals: 2,
propertyID: "audio.reverbTime",
showPropertyRule: { "audio.enableReverb": "true" },
},
{
label: "Reverb Wet Level",
type: "number-draggable",
min: 0,
max: 100,
step: 1,
decimals: 1,
propertyID: "audio.reverbWetLevel",
showPropertyRule: { "audio.enableReverb": "true" },
},
{
label: "Listener Zones",
type: "multipleZonesSelection",
propertyID: "audio.listenerZones",
}
]
},
{
id: "model",
label: "MODEL",
@ -1764,7 +1800,7 @@ const GROUPS_PER_TYPE = {
Shape: [ 'base', 'shape', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Text: [ 'base', 'text', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Zone: [ 'base', 'zone', 'zone_key_light', 'zone_skybox', 'zone_ambient_light', 'zone_haze',
'zone_bloom', 'zone_avatar_priority', 'spatial', 'behavior', 'scripts', 'physics' ],
'zone_bloom', 'zone_avatar_priority', 'zone_audio', 'spatial', 'behavior', 'scripts', 'physics' ],
Model: [ 'base', 'model', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Image: [ 'base', 'image', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Web: [ 'base', 'web', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B