1 /*
  2  *Copyright (c) 2009, TellurianRing.com
  3  *All rights reserved.
  4  *
  5  *Redistribution and use in source and binary forms, with or without modification,
  6  *are permitted provided that the following conditions are met:
  7  *
  8  *   Redistributions of source code must retain the above copyright notice, this
  9  *   list of conditions and the following disclaimer.
 10  *   Redistributions in binary form must reproduce the above copyright notice,
 11  *   this list of conditions and the following disclaimer in the documentation
 12  *   and/or other materials provided with the distribution.
 13  *   Neither the name of the Organization (TellurianRing.com) nor the names of
 14  *   its contributors may be used to endorse or promote products derived from
 15  *   this software without specific prior written permission.
 16  *
 17  *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 18  *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 19  *WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 20  *DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 21  *ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22  *(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 23  *LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 24  *ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25  *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 26  *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27  */
 28 /**
 29  * @class Loads some audio or sound into the Scene. This implementation uses the
 30  * HTML 5 audio tag and therefore requires a compatible browser.
 31  * @example
 32  * var sound1 = Audio({
 33  *    url: "http://www.tellurianring.com/sounds/laugh.ogg"
 34  * });
 35  * sound1.play();
 36  * <div id="sound_example_1"></div>
 37  * <script type="text/javascript">
 38  *    var sound1 = Sound({
 39  *       url: "http://www.tellurianring.com/sounds/laugh.ogg"
 40  *    });
 41  *    Stage({
 42  *      container_id: "sound_example_1",
 43  *      width: 100, height: 100,
 44  *      update_time: 500,
 45  *      scene: Scene({
 46  *         content: [ sound1 ]
 47  *      })
 48  *    });
 49  *    function audio_1() {
 50  *       sound1.play();
 51  *    }
 52  * </script>
 53  * <button onclick="audio_1()">Play It!</button>
 54  * @example
 55  * Relative URL's work as well:
 56  * var sound2 = Audio({ url: "./sounds/ohhh.ogg" });
 57  * sound2.play();
 58  * <div id="sound_example_2"></div>
 59  * <script type="text/javascript">
 60  *    var sound2 = Sound({ url: "./sounds/ohhh.ogg" });
 61  *    Stage({
 62  *       container_id: "sound_example_2",
 63  *       width: 100, height: 100,
 64  *       update_time: 500,
 65  *       scene: Scene({
 66  *          content: [ sound2 ]
 67  *       })
 68  *    });
 69  *    function audio_2() {
 70  *       sound2.play();
 71  *    }
 72  * </script>
 73  * <button onclick="audio_2()">Play It!</button>
 74  * @extends SceneContent
 75  * @param {Object} _details A JSON object with the following properties:
 76  * <table cellpadding="0" cellspacing="1" border="0" class="constructor_details">
 77  *    <tr><th>Property</th> <th>Required</th> <th>Default</th></tr>
 78  *    <tr><td>loop</td>     <td>no</td>       <td>false</td></tr>
 79  *    <tr><td>start</td>    <td>no</td>       <td>false</td></tr>
 80  *    <tr><td>url</td>      <td>yes</td>      <td></td></tr>
 81  *    <tr><td>volume</td>   <td>no</td>       <td>1</td></tr>
 82  * </table>
 83  */
 84 function Sound(_details) { // {{{
 85    /** @constructs */
 86    function _Sound(_details) { // {{{
 87       // Private Members {{{
 88       var audio = document.createElement("audio");
 89       var loaded = false;
 90       var loop = check(_details.loop, false);
 91       var start = check(_details.start, false);
 92       var url = _details.url;
 93       var volume = check(_details.volume, 1);
 94 
 95       // tries to preload the image at initialization.
 96       audio.autoplay = start;
 97       audio.loader = this;
 98       audio.loop = loop;
 99       audio.onload = function() {
100          this.loader.doLoad();
101       };
102       audio.volume = volume;
103       // }}} Private Members
104 
105       // Public Members {{{
106       /**
107        * Executed when the audio is actually loaded.
108        */
109       this.doLoad = function() {
110          loaded = true;
111          if(exists(_details.onLoad)) {
112             _details.onLoad();
113          }
114       }
115       // Overridden to load audio at load time instead of creation time.
116       this.load = function(_scene, _parent) {
117          this.loadBase(_scene, _parent);
118          audio.src = url;
119          audio.load()
120       }
121       /**
122        * Sets the volume to the initial volume, and starts the sound.
123        * @function
124        */
125       this.play = function() {
126          audio.play();
127       }
128       /**
129        * Pauses the sound.
130        * @function
131        */
132       this.pause = function() {
133          audio.pause();
134       }
135       /**
136        * Sets the looping of this Sound.
137        * @function
138        * @param {Boolean} _loop Turns looping on for this sound - true or false.
139        */
140       this.setLoop = function(_loop) {
141          loop = _loop;
142          audo.loop = _loop;
143       }
144       /**
145        * Sets the volume on this Sound.
146        * @function
147        * @param {Decimal} _volume Volume of sound between 0.0 and 1.0
148        */
149       this.setVolume = function(_volume) {
150          volume = _volume;
151          audo.volume = _volume;
152       }
153       /**
154        * Stops the sound. This implementation pauses the sound and resets it.
155        */
156       this.stop = function() {
157          this.pause();
158          audio.currentTime = 0;
159       }
160       // Overridden to react to stage unloads - which cause the sound to stop.
161       this.update = function(_runtime) {
162          if(this.getStage().isRunning() == false) {
163             this.pause();
164          }
165       }
166       // }}} Public Members
167    }// }}} _Sound
168    SceneContent(_details).extend(_Sound);
169    var theSound = new _Sound(_details);
170    return theSound;
171 } // }}} Sound
172 // These properties are for jEdit - Programmer's Text Editor.
173 // Load this file in jEdit to see what they do.
174 // ::folding=explicit:mode=javascript:noTabs=true:collapseFolds=4::
175