1 /**
  2  * The Render Engine
  3  * Sound
  4  *
  5  * @fileoverview A sound object.
  6  *
  7  * @author: Brett Fattori (brettf@renderengine.com)
  8  * @author: $Author: bfattori $
  9  * @version: $Revision: 1555 $
 10  *
 11  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 12  *
 13  * Permission is hereby granted, free of charge, to any person obtaining a copy
 14  * of this software and associated documentation files (the "Software"), to deal
 15  * in the Software without restriction, including without limitation the rights
 16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 17  * copies of the Software, and to permit persons to whom the Software is
 18  * furnished to do so, subject to the following conditions:
 19  *
 20  * The above copyright notice and this permission notice shall be included in
 21  * all copies or substantial portions of the Software.
 22  *
 23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 29  * THE SOFTWARE.
 30  *
 31  */
 32 
 33 // The class this file defines and its required classes
 34 R.Engine.define({
 35     "class":"R.resources.types.Sound",
 36     "requires":[
 37         "R.engine.PooledObject"
 38     ]
 39 });
 40 
 41 /**
 42  * @class Represents a sound object that is abstracted from the sound system.
 43  *        If the sound system does not initialize, for whatever reason, you can
 44  *             still call a sound's methods.
 45  *
 46  * @constructor
 47  * @param name {String} The name of the sound
 48  * @extends R.engine.PooledObject
 49  */
 50 R.resources.types.Sound = function () {
 51     return R.engine.PooledObject.extend(/** @scope R.resources.types.Sound.prototype */{
 52 
 53         volume:-1,
 54         paused:false,
 55         pan:-1,
 56         muted:false,
 57         soundObj:null,
 58         soundSystem:null,
 59         supportedType:false,
 60 
 61         /** @private */
 62         constructor:function (soundSystem, soundObj) {
 63             this.volume = 50;
 64             this.paused = false;
 65             this.pan = 0;
 66             this.muted = false;
 67             this.soundObj = soundObj;
 68             this.soundSystem = soundSystem;
 69             this.supportedType = true;
 70             this.loop = false;
 71             return this.base(name);
 72         },
 73 
 74         /**
 75          * Destroy the sound object
 76          */
 77         destroy:function () {
 78             this.soundSystem.destroySound(this.sound);
 79             this.base();
 80         },
 81 
 82         /**
 83          * Release the sound back into the pool for reuse
 84          */
 85         release:function () {
 86             this.base();
 87             this.volume = -1;
 88             this.pan = -1;
 89             this.paused = false;
 90             this.muted = false;
 91             this.soundObj = null;
 92             this.soundSystem = null;
 93         },
 94 
 95         /**
 96          * Set a boolean flag indicating if the sound type is supported by the browser
 97          * @param state {Boolean} <code>true</code> indicates the sound type is supported
 98          */
 99         setSupportedTypeFlag:function (state) {
100             this.supportedType = state;
101         },
102 
103         /**
104          * Returns a boolean indicating if the sound type is supported by the browser
105          * @return {Boolean}
106          */
107         getSupportedTypeFlag:function () {
108             return this.supportedType;
109         },
110 
111         /**
112          * Get the native sound object which was created by the subclassed sound system.
113          * @return {Object}
114          */
115         getSoundObject:function () {
116             return this.soundObj;
117         },
118 
119         /**
120          * Set the sound object which the subclassed sound system created.
121          * @param soundObj {Object} The sound's native object
122          */
123         setSoundObject:function (soundObj) {
124             this.soundObj = soundObj;
125         },
126 
127         /**
128          * Play the sound.  If the volume is specified, it will set volume of the
129          * sound before playing.  If the sound was paused, it will be resumed.
130          *
131          * @param volume {Number} <i>[optional]</i> An integer between 0 (muted) and 100 (full volume)
132          */
133         play:function (volume) {
134             if (this.paused) {
135                 this.resume();
136                 return;
137             }
138 
139             if (volume && volume != this.getVolume()) {
140                 this.setVolume(volume);
141             }
142 
143             this.soundSystem.playSound(this.soundObj);
144         },
145 
146         /**
147          * If the sound is playing, stop the sound and reset it to the beginning.
148          */
149         stop:function () {
150             this.paused = false;
151             this.soundSystem.stopSound(this.soundObj);
152         },
153 
154         /**
155          * If the sound is playing, pause the sound.
156          */
157         pause:function () {
158             this.soundSystem.pauseSound(this.soundObj);
159             this.paused = true;
160         },
161 
162         /**
163          * Returns <tt>true</tt> if the sound is currently paused.
164          * @return {Boolean} <tt>true</tt> if the sound is paused
165          */
166         isPaused:function () {
167             return this.paused;
168         },
169 
170         /**
171          * If the sound is paused, it will resume playing the sound.
172          */
173         resume:function () {
174             this.paused = false;
175             this.soundSystem.resumeSound(this.soundObj);
176         },
177 
178         /**
179          * Mute the sound (set its volume to zero).
180          */
181         mute:function () {
182             this.soundSystem.muteSound(this.soundObj);
183             this.muted = true;
184         },
185 
186         /**
187          * Unmute the sound (reset its volume to what it was before muting).
188          */
189         unmute:function () {
190             if (!this.muted) {
191                 return;
192             }
193             this.soundSystem.unmuteSound(this.soundObj);
194             this.muted = false;
195         },
196 
197         /**
198          * Set the volume of the sound to an integer between 0 (muted) and 100 (full volume).
199          *
200          * @param volume {Number} The volume of the sound
201          */
202         setVolume:function (volume) {
203             if (isNaN(volume)) {
204                 return;
205             }
206 
207             // clamp it
208             volume = (volume < 0 ? 0 : volume > 100 ? 100 : volume);
209             this.volume = volume;
210             this.soundSystem.setSoundVolume(this.soundObj, volume);
211         },
212 
213         /**
214          * Get the volume the sound is playing at.
215          * @return {Number} An integer between 0 and 100
216          */
217         getVolume:function () {
218             return this.volume;
219         },
220 
221         /**
222          * Set the pan of the sound, with -100 being full left and 100 being full right.
223          *
224          * @param pan {Number} An integer between -100 and 100, with 0 being center.
225          */
226         setPan:function (pan) {
227             this.pan = pan;
228             this.soundSystem.setSoundPan(this.soundObj, pan);
229         },
230 
231         /**
232          * Get the pan of the sound, with -100 being full left and 100 being full right.
233          * @return {Number} An integer between -100 and 100
234          */
235         getPan:function () {
236             return this.pan;
237         },
238 
239         /**
240          * Set the sound offset in milliseconds.
241          *
242          * @param millisecondOffset {Number} The offset into the sound to play from
243          */
244         setPosition:function (millisecondOffset) {
245             this.position = millisecondOffset;
246             this.soundSystem.setSoundPosition(this.soundObj, millisecondOffset);
247         },
248 
249         /**
250          * Get the position of the sound, in milliseconds, from the start of the sound.
251          * @return {Number} The millisecond offset into the sound
252          */
253         getLastPosition:function () {
254             return this.soundSystem.getSoundPosition(this.soundObj);
255         },
256 
257         /**
258          * Get the total size, in bytes, of the sound.  If the sound engine is not
259          * initialized, returns 0.
260          * @return {Number} The size of the sound, in bytes
261          */
262         getSizeBytes:function () {
263             return this.soundSystem.getSoundSize(this.soundObj);
264         },
265 
266         /**
267          * Get the length of the sound, in milliseconds.  If the sound hasn't fully loaded,
268          * it will be the number of milliseconds currently loaded.  Due to the nature of
269          * Variable Bitrate (VBR) sounds, this number may be inaccurate.
270          * @return {Number} The length of the sound, in milliseconds
271          */
272         getDuration:function () {
273             return this.soundSystem.getSoundDuration(this.soundObj);
274         },
275 
276         /**
277          * Flag to indicate if the sound ready to use.
278          * @return {Boolean}
279          */
280         getReadyState:function () {
281             return this.soundSystem.getSoundReadyState(this.soundObj);
282         }
283 
284     }, /** @scope R.resources.types.Sound.prototype */ {
285         /**
286          * Gets the class name of this object.
287          * @return {String} The string "R.resources.types.Sound"
288          */
289         getClassName:function () {
290             return "R.resources.types.Sound";
291         }
292     });
293 
294 }