From 70942925bc200da48196b5955d86156f12513d29 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 19 Dec 2016 10:32:17 -0800 Subject: [PATCH 1/4] Entity script for ambisonic sound emitter --- .../tutorials/entity_scripts/ambientSound.js | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 scripts/tutorials/entity_scripts/ambientSound.js diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js new file mode 100644 index 0000000000..a387f00c10 --- /dev/null +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -0,0 +1,101 @@ +// ambientSound.js +// +// This entity script will allow you to create an ambient sound that loops when a person is within a given +// range of this entity. Great way to add one or more ambisonic soundfields to your environment. +// +// In the userData section for the entity, add two values: +// userData.SoundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. +// userData.range should be an integer for the max distance away from the entity where the sound will be audible. +// userData.volume is the max volume at which the clip should play. +// +// Note: When you update the above values, you need to reload the entity script for it to see the changes. Also, +// remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is +// large enough to be loaded at the range you set, particularly for large ranges. +// +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function(){ + // This sample clip and range will be used if you don't add userData to the entity (see above) + var DEFAULT_RANGE = 100; + var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; + var DEFAULT_VOLUME = 1.0; + + var soundURL = DEFAULT_URL; + var range = DEFAULT_RANGE; + var maxVolume = DEFAULT_VOLUME; + var UPDATE_INTERVAL_MSECS = 100; + + var entity; + var ambientSound; + var center; + var soundPlaying = false; + var updateTimer = false; + + var WANT_DEBUG = false; + + function debugPrint(string) { + if (WANT_DEBUG) { + print(string); + } + } + + this.preload = function(entityID) { + // Load the sound and range from the entity userData fields, and note the position of the entity. + debugPrint("Ambient sound preload"); + entity = entityID; + var props = Entities.getEntityProperties(entityID, [ "userData" ]); + var data = JSON.parse(props.userData); + if (data.soundURL) { + soundURL = data.soundURL; + debugPrint("Read ambient sound URL: " + soundURL); + } + ambientSound = SoundCache.getSound(soundURL); + if (data.range) { + range = data.range; + debugPrint("Read ambient sound range: " + range); + } + if (data.volume) { + maxVolume = data.volume; + debugPrint("Read ambient sound volume: " + maxVolume); + } + updateTimer = Script.setInterval(this.update, UPDATE_INTERVAL_MSECS); + }; + + this.update = function() { + // Every UPDATE_INTERVAL_MSECS, update the volume of the ambient sound based on distance from my avatar + var HYSTERESIS_FRACTION = 0.1; + var props = Entities.getEntityProperties(entity, [ "position" ]); + center = props.position; + var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center)); + if (distance <= range) { + var volume = (1.0 - distance / range) * maxVolume; + if (!soundPlaying && ambientSound.downloaded) { + soundPlaying = Audio.playSound(ambientSound, { loop: true, volume: volume }); + debugPrint("Starting ambient sound, volume: " + volume); + Entities.editEntity(entity, { color: { red: 255, green: 0, blue: 0 }}); + } else if (soundPlaying && soundPlaying.playing) { + soundPlaying.setOptions( { volume: volume } ); + } + } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { + soundPlaying.stop(); + soundPlaying = false; + Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }}); + debugPrint("Out of range, stopping ambient sound"); + } + } + + this.unload = function(entityID) { + debugPrint("Ambient sound unload"); + if (updateTimer) { + Script.clearInterval(updateTimer); + } + if (soundPlaying && soundPlaying.playing) { + soundPlaying.stop(); + } + }; + +}) From e2dfbf1b023aaa0f568d9fc9fbf6f0c1f82439c1 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 20 Dec 2016 12:02:13 -0800 Subject: [PATCH 2/4] Addressed PR feedback - now dynamically reads userdata --- .../tutorials/entity_scripts/ambientSound.js | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index a387f00c10..19b082e157 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -3,13 +3,12 @@ // This entity script will allow you to create an ambient sound that loops when a person is within a given // range of this entity. Great way to add one or more ambisonic soundfields to your environment. // -// In the userData section for the entity, add two values: +// In the userData section for the entity, add/edit three values: // userData.SoundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. // userData.range should be an integer for the max distance away from the entity where the sound will be audible. -// userData.volume is the max volume at which the clip should play. +// userData.volume is the max volume at which the clip should play. Defaults to 1.0 full volume) // -// Note: When you update the above values, you need to reload the entity script for it to see the changes. Also, -// remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is +// Remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is // large enough to be loaded at the range you set, particularly for large ranges. // // Copyright 2016 High Fidelity, Inc. @@ -24,7 +23,7 @@ var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; - var soundURL = DEFAULT_URL; + var soundURL = ""; var range = DEFAULT_RANGE; var maxVolume = DEFAULT_VOLUME; var UPDATE_INTERVAL_MSECS = 100; @@ -33,40 +32,61 @@ var ambientSound; var center; var soundPlaying = false; - var updateTimer = false; - - var WANT_DEBUG = false; + var checkTimer = false; + var _this; + var WANT_DEBUG = true; function debugPrint(string) { if (WANT_DEBUG) { print(string); } } + this.updateSettings = function() { + // Check user data on the entity for any changes + var oldSoundURL = soundURL; + var props = Entities.getEntityProperties(entity, [ "userData" ]); + if (props.userData) { + var data = JSON.parse(props.userData); + if (data.soundURL && !(soundURL === data.soundURL)) { + soundURL = data.soundURL; + debugPrint("Read ambient sound URL: " + soundURL); + } else if (!data.soundURL) { + soundURL = DEFAULT_URL; + } + if (data.range && !(range === data.range)) { + range = data.range; + debugPrint("Read ambient sound range: " + range); + } + if (data.volume && !(maxVolume === data.volume)) { + maxVolume = data.volume; + debugPrint("Read ambient sound volume: " + maxVolume); + } + } + if (!(soundURL === oldSoundURL) || (soundURL === "")) { + debugPrint("Loading ambient sound into cache"); + ambientSound = SoundCache.getSound(soundURL); + if (soundPlaying && soundPlaying.playing) { + soundPlaying.stop(); + soundPlaying = false; + Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }}); + debugPrint("Restarting ambient sound"); + } + } + } + this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. debugPrint("Ambient sound preload"); entity = entityID; - var props = Entities.getEntityProperties(entityID, [ "userData" ]); - var data = JSON.parse(props.userData); - if (data.soundURL) { - soundURL = data.soundURL; - debugPrint("Read ambient sound URL: " + soundURL); - } - ambientSound = SoundCache.getSound(soundURL); - if (data.range) { - range = data.range; - debugPrint("Read ambient sound range: " + range); - } - if (data.volume) { - maxVolume = data.volume; - debugPrint("Read ambient sound volume: " + maxVolume); - } - updateTimer = Script.setInterval(this.update, UPDATE_INTERVAL_MSECS); + _this = this; + checkTimer = Script.setInterval(this.maybeUpdate, UPDATE_INTERVAL_MSECS); }; - this.update = function() { + this.maybeUpdate = function() { // Every UPDATE_INTERVAL_MSECS, update the volume of the ambient sound based on distance from my avatar + _this.updateSettings(); + var props = Entities.getEntityProperties(entity); var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position" ]); center = props.position; @@ -74,7 +94,7 @@ if (distance <= range) { var volume = (1.0 - distance / range) * maxVolume; if (!soundPlaying && ambientSound.downloaded) { - soundPlaying = Audio.playSound(ambientSound, { loop: true, volume: volume }); + soundPlaying = Audio.playSound(ambientSound, { loop: true, localOnly: true, volume: volume }); debugPrint("Starting ambient sound, volume: " + volume); Entities.editEntity(entity, { color: { red: 255, green: 0, blue: 0 }}); } else if (soundPlaying && soundPlaying.playing) { @@ -90,12 +110,12 @@ this.unload = function(entityID) { debugPrint("Ambient sound unload"); - if (updateTimer) { - Script.clearInterval(updateTimer); + if (checkTimer) { + Script.clearInterval(checkTimer); } if (soundPlaying && soundPlaying.playing) { soundPlaying.stop(); } }; -}) +}) From 632af18c1d601662fb1d96184e71b379c8662644 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 20 Dec 2016 12:09:42 -0800 Subject: [PATCH 3/4] PR feedback - flag for setting color --- scripts/tutorials/entity_scripts/ambientSound.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 19b082e157..b3ec919078 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -35,6 +35,10 @@ var checkTimer = false; var _this; + var WANT_COLOR_CHANGE = true; + var COLOR_OFF = { red: 128, green: 128, blue: 128 }; + var COLOR_ON = { red: 255, green: 0, blue: 0 }; + var WANT_DEBUG = true; function debugPrint(string) { if (WANT_DEBUG) { @@ -69,7 +73,9 @@ if (soundPlaying && soundPlaying.playing) { soundPlaying.stop(); soundPlaying = false; - Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }}); + if (WANT_COLOR_CHANGE) { + Entities.editEntity(entity, { color: COLOR_OFF }); + } debugPrint("Restarting ambient sound"); } } @@ -96,7 +102,10 @@ if (!soundPlaying && ambientSound.downloaded) { soundPlaying = Audio.playSound(ambientSound, { loop: true, localOnly: true, volume: volume }); debugPrint("Starting ambient sound, volume: " + volume); - Entities.editEntity(entity, { color: { red: 255, green: 0, blue: 0 }}); + if (WANT_COLOR_CHANGE) { + Entities.editEntity(entity, { color: COLOR_ON }); + } + } else if (soundPlaying && soundPlaying.playing) { soundPlaying.setOptions( { volume: volume } ); } From 4bade4400f8f1ff45b3c12f54285400b01cf8b89 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 20 Dec 2016 16:02:26 -0800 Subject: [PATCH 4/4] fixed typo per review --- scripts/tutorials/entity_scripts/ambientSound.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index b3ec919078..6a892ed139 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -4,7 +4,7 @@ // range of this entity. Great way to add one or more ambisonic soundfields to your environment. // // In the userData section for the entity, add/edit three values: -// userData.SoundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. +// userData.soundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. // userData.range should be an integer for the max distance away from the entity where the sound will be audible. // userData.volume is the max volume at which the clip should play. Defaults to 1.0 full volume) //