PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/DiegoRay/actionscripts/org/asapframework/management/sound/SoundManager.as

https://github.com/joemaffia/flash-junk
ActionScript | 483 lines | 192 code | 41 blank | 250 comment | 51 complexity | 02c7bffdb10c6f5f5c32a3c328e1cbbb MD5 | raw file
  1. /*
  2. Copyright 2005-2006 by the authors of asapframework, http://asapframework.org
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // ASAP classes
  14. import org.asapframework.management.sound.EventSound;
  15. import org.asapframework.management.sound.SoundClip;
  16. import org.asapframework.management.sound.SoundClipEvent;
  17. import org.asapframework.management.sound.SoundMovie;
  18. import org.asapframework.util.debug.Log;
  19. /**
  20. SoundManager provides a single access point to all sounds in a Flash project.
  21. Sounds may be compiled into a SWF movie (<em>internal</em>) or loaded as MP3 files (<em>external</em>).
  22. SoundManager allows access to these sounds from any part in the Flash project.
  23. @use
  24. <code>
  25. import org.asapframework.management.sound.SoundManager;
  26. var theSoundManager:SoundManager = SoundManager.getInstance();
  27. // played sounds need a MovieClip
  28. var mc:MovieClip = createEmptyMovieClip("soundmanager", 0);
  29. theSoundManager.addMovie("main", mc);
  30. theSoundManager.addSound("test10", "main");
  31. theSoundManager.addSound("test11", "main");
  32. theSoundManager.playSound("test10");
  33. theSoundManager.playSound("test11");
  34. onUnload = function () {
  35. theSoundManager.removeMovie("main");
  36. }
  37. </code>
  38. */
  39. class org.asapframework.management.sound.SoundManager {
  40. private var mSounds:Array;
  41. private var mMovies:Array;
  42. private var mCurrentLevel:Number = 1;
  43. private static var sInstance:SoundManager = null;
  44. /**
  45. Private constructor, use {@link #getInstance} to refer to singleton instance.
  46. */
  47. private function SoundManager () {
  48. mSounds = new Array();
  49. mMovies = new Array();
  50. }
  51. /**
  52. Returns reference to singleton instance of SoundManager
  53. */
  54. public static function getInstance () : SoundManager {
  55. if (sInstance == null) {
  56. sInstance = new SoundManager();
  57. }
  58. return sInstance;
  59. }
  60. /**
  61. Add a named movieclip to function as container for sounds
  62. Make sure the movieclip resides in the same swf as the sounds that will be added to it.
  63. @param inName: (unique) name of movie to be used as identifier
  64. @param inClip: the movieclip itself
  65. @return True if the movie was successfully added, otherwise false (due to non-unique name).
  66. */
  67. public function addMovie (inName:String, inClip:MovieClip) : Boolean {
  68. if (getMovie(inName)){
  69. Log.error("addMovie: Movie with name '" + inName + "' already exists, not added", toString());
  70. return false;
  71. }
  72. var movie:SoundMovie = new SoundMovie(inName, inClip);
  73. mMovies.push(movie);
  74. }
  75. /**
  76. Remove a previously added movie with specified name. Also removes all associated sounds.
  77. @param inName: (unique) name of a movie
  78. */
  79. public function removeMovie (inName:String) : Void {
  80. var index:Number = getMovieIndex(inName);
  81. if (index == -1){
  82. Log.error("removeMovie: movie with name '" + inName + "' not found, not removed", toString());
  83. return;
  84. }
  85. // remove sounds associated with this movie
  86. removeSoundsInMovie(inName);
  87. // remove soundmovie itself
  88. mMovies.splice(index, 1);
  89. }
  90. /**
  91. Add a sound from the library, associated with the specified movie name
  92. @param inLinkageName: linkage id of the sound in the library
  93. @param inMovieName: name of previously added movieclip in which the sound will be created
  94. @return True if the sound was successfully added, or false if not. False indicates either that a sound with the specified linkage id has already been added, that the movie with the specified moviename was not found, or that a sound with the specified linkage id does not exist in the library.
  95. */
  96. public function addSound (inLinkageName:String, inMovieName:String) : Boolean {
  97. // create SoundClip
  98. var clip:SoundClip = createSoundClip(inLinkageName, inMovieName);
  99. if (clip == null) return false;
  100. // attach library sound
  101. clip.sound.attachSound(inLinkageName);
  102. // check if sound has duration; if not, it's most likely not in the library
  103. if (clip.sound.duration == undefined) {
  104. Log.error("addSound: Could not attach sound with linkage id '" + inLinkageName + "'; check the library!", toString());
  105. return false;
  106. }
  107. // store in list
  108. mSounds.push(clip);
  109. return true;
  110. }
  111. /**
  112. Add an external sound. If <code>inIsStreaming</code> is set to false, loading of the external sound starts immediately.
  113. @param inLinkageName: unique identifier for the sound
  114. @param inMovieName: name of previously added movie to associate sound with
  115. @param inUrl: url of sound
  116. @param inIsStreaming: specify if sound should be loaded entirely before playing (false) or be played streaming (true)
  117. @param inListener: Object to be added as listener to {@link SoundClipEvent#ON_LOADED} and {@link SoundClipEvent#ON_ERROR} events from the SoundClip
  118. @return True if the sound was successfully added. This indicates either that a sound with the specified linkage id has already been added, or that the movie with the specified moviename was not found.
  119. Note that adding an event listener after adding the sound may result in ON_LOADED or ON_ERROR events going missing. If the sound is loaded from the local system, the event can be fired during the addExternalSound call. It is therefore recommended to use the "inListener" property.
  120. @example
  121. On the timeline, add this code:
  122. <code>
  123. com.lostboys.AppController.main(this);
  124. </code>
  125. Create a new class com.lostboys.AppController, and add the following code:
  126. <code>
  127. import org.asapframework.management.sound.SoundClip;
  128. import org.asapframework.management.sound.SoundClipEvent;
  129. import org.asapframework.management.sound.SoundManager;
  130. import org.asapframework.util.debug.Log;
  131. import org.asapframework.management.movie.LocalController;
  132. class com.lostboys.AppController extends LocalController {
  133. private static var TEST_SOUND_NAME:String = "test";
  134. private static var TEST_SOUND_URL:String = "test.mp3";
  135. private static var TEST2_SOUND_NAME:String = "test2";
  136. private static var TEST2_SOUND_URL:String = "test2.mp3";
  137. private static var SOUND_CONTAINER:String = "main";
  138. public function AppController (inMC:MovieClip) {
  139. super(inMC);
  140. // get sound manager
  141. var sm:SoundManager = SoundManager.getInstance();
  142. // create sound container clip
  143. var mc:MovieClip = timeline.createEmptyMovieClip("soundContainer", 0);
  144. // add container clip to sound manager
  145. sm.addMovie(SOUND_CONTAINER, mc);
  146. // try to add the external sounds, non-streaming so it starts loading immediately
  147. // For the test, make sure one of these sounds exists, and the other doesn't
  148. sm.addExternalSound(TEST_SOUND_NAME, SOUND_CONTAINER, TEST_SOUND_URL, false, this);
  149. sm.addExternalSound(TEST2_SOUND_NAME, SOUND_CONTAINER, TEST2_SOUND_URL, false, this);
  150. }
  151. // Event handler for SoundClipEvent.ON_LOADED event from external sounds
  152. private function onSoundClipLoaded (e:SoundClipEvent) : Void {
  153. SoundManager.getInstance().playSound(e.name);
  154. }
  155. // Event handler for SoundClipEvent.ON_ERROR event from external sounds
  156. private function onSoundClipLoadError (e:SoundClipEvent) : Void {
  157. Log.error("Could not load sound with url '" + SoundClip(e.target).url + "'", toString());
  158. }
  159. // The main entry point from the timeline
  160. public static function main (inMC:MovieClip) : Void {
  161. var controller:AppController = new AppController(inMC);
  162. }
  163. public function toString() : String {
  164. return ";com.lostboys.AppController";
  165. }
  166. }
  167. </code>
  168. This will play the sound that exists, and output an error message to the trace window with the url of the non-existent sound file.
  169. */
  170. public function addExternalSound (inLinkageName:String, inMovieName:String, inUrl:String, inIsStreaming:Boolean, inListener:Object) : Boolean {
  171. // create SoundClip
  172. var clip:SoundClip = createSoundClip(inLinkageName, inMovieName);
  173. if (clip == null) return false;
  174. // add listener
  175. if (inListener != undefined) {
  176. clip.addEventListener(SoundClipEvent.ON_LOADED, inListener);
  177. clip.addEventListener(SoundClipEvent.ON_ERROR, inListener);
  178. }
  179. if (inIsStreaming) {
  180. clip.setStreaming(inUrl);
  181. } else {
  182. clip.loadExternalSound(inUrl);
  183. }
  184. // store SoundClip
  185. mSounds.push(clip);
  186. return true;
  187. }
  188. /**
  189. Remove a previously added sound
  190. @param inName: (unique) name
  191. */
  192. public function removeSound (inName:String) : Void {
  193. var index:Number = getSoundIndex(inName);
  194. if (index == -1){
  195. Log.error("removeSound: sound with name '" + inName + "' not found, not removed", toString());
  196. return;
  197. }
  198. mSounds.splice(index, 1);
  199. }
  200. /**
  201. Remove all sounds in a previously added sound container movie
  202. @param inMovieName: name of movie
  203. */
  204. public function removeSoundsInMovie (inMovieName:String) : Void {
  205. var clipNames:Array = new Array();
  206. var movieNames:Array = new Array();
  207. var i:Number;
  208. var sLen:Number = mSounds.length;
  209. for (i=0; i<sLen; ++i){
  210. var clip:SoundClip = SoundClip(mSounds[i]);
  211. clipNames.push(clip.name);
  212. movieNames.push(clip.movieName);
  213. }
  214. var j:Number;
  215. var mLen:Number = movieNames.length;
  216. for (j=0; j<mLen; ++j) {
  217. if (String(movieNames[j]) == inMovieName){
  218. removeSound(clipNames[j]);
  219. }
  220. }
  221. }
  222. /**
  223. Play a sound with the specified name and play count. If the sound was playing, it is stopped.
  224. @param name Sound identifier.
  225. @param playCount Number of times to play the sound. 0: play in a loop; nothing: play once.
  226. @return True if successfully started. False indicates that a sound with the specified name has not been added, or that an external sound has not loaded (yet).
  227. @use
  228. To play a sound once:
  229. <code>
  230. SoundManager.getInstance().playSound("test");
  231. </code>
  232. To play a sound 10 times:
  233. <code>
  234. SoundManager.getInstance().playSound("test", 10);
  235. </code>
  236. To loop a sound:
  237. <code>
  238. SoundManager.getInstance().playSound("test", 0);
  239. </code>
  240. Note: looping is <b>only</b> devoid of glitches with sounds in the library. External sounds are always with a glitch.
  241. Note: in certain cases, when used with an <b>external sound</b> (an mp3 file), you can pass playSound only after a frame has passed. For example from a controller class:
  242. <code>
  243. private function onSoundClipLoaded (inName:String) : Void
  244. { // passed from SoundClip
  245. mc.onEnterFrame = function() {
  246. delete mc.onEnterFrame;
  247. var theSoundManager:SoundManager = SoundManager.getInstance();
  248. theSoundManager.playSound("mainsound", 0);
  249. theSoundManager.setSoundVolume("mainsound", 70);
  250. }
  251. }
  252. </code>
  253. or you can use the class org.asapframework.util.FrameDelay for this: (example untested!)
  254. <code>
  255. private function onSoundClipLoaded (inName:String) : Void
  256. { // passed from SoundClip
  257. new FrameDelay(SoundManager.getInstance(), playSound, ["mainsound", 0]);
  258. }
  259. </code>
  260. */
  261. public function playSound (inName:String, inPlayCount:Number) : Boolean {
  262. var clip:SoundClip = getSound(inName);
  263. if (clip == null) {
  264. Log.error("playSound: Sound with name '" + inName + "' not found", toString());
  265. return false;
  266. }
  267. if (clip.isExternal && !clip.isLoaded){
  268. Log.error("playSound: Sound with name '" + inName + "' not loaded", toString());
  269. return false;
  270. }
  271. clip.stop();
  272. clip.startSound(inPlayCount == undefined ? 1 : inPlayCount);
  273. return true;
  274. }
  275. /**
  276. Stop the sound with the specified name
  277. @param inName: identifying name of the sound to be stopped
  278. @return True if the sound was stopped. False indicates that a sound with the specified name was not added, or that an external sound has not loaded (yet).
  279. */
  280. public function stopSound (inName:String) : Boolean {
  281. var clip:SoundClip = getSound(inName);
  282. if (clip == null) return false;
  283. if (clip.isExternal && !clip.isLoaded){
  284. Log.error("stopSound: Sound with name '" + inName + "' not loaded", toString());
  285. return false;
  286. }
  287. clip.stop();
  288. }
  289. /**
  290. @param name : Sound identifier.
  291. @param volume : A number from 0 to 100.
  292. @return True if successfully applied to sound. False indicates that a sound with the specified name was not added.
  293. */
  294. public function setSoundVolume (inName:String, inVolume:Number) : Boolean {
  295. var clip:SoundClip = getSound(inName);
  296. if (clip == null) return false;
  297. clip.volume = inVolume;
  298. return true;
  299. }
  300. /**
  301. Stop all sounds.
  302. Note that this function affects only sounds played with the SoundManager.
  303. */
  304. public function stopAllSounds () : Void {
  305. for (var i:Number = 0; i < mSounds.length; i++){
  306. var clip:SoundClip = SoundClip(mSounds[i]);
  307. clip.stop();
  308. }
  309. }
  310. /**
  311. Set the volume of all sounds to 0. The original volume is retained, and can be reset with {@link #unmuteAllSounds}.
  312. Note that this function affects only sounds played with the SoundManager.
  313. */
  314. public function muteAllSounds () : Void {
  315. for (var i:Number = 0; i < mSounds.length; i++){
  316. var clip:SoundClip = SoundClip(mSounds[i]);
  317. clip.mute();
  318. }
  319. }
  320. /**
  321. Reset the original volume of all sounds.
  322. Note that this function affects only sounds played with the SoundManager.
  323. */
  324. public function unmuteAllSounds () : Void {
  325. for (var i:Number = 0; i < mSounds.length; i++){
  326. var clip:SoundClip = SoundClip(mSounds[i]);
  327. clip.unmute();
  328. }
  329. }
  330. /**
  331. Get the SoundClip object for more direct manipulation.
  332. @param inName: name of the sound for which the SoundClip object is requested
  333. @return The SoundClip object if found, or null if none was found.
  334. */
  335. public function getSound (inName:String) : SoundClip {
  336. for (var i:Number = 0; i < mSounds.length; i++){
  337. var clip:SoundClip = SoundClip(mSounds[i]);
  338. if (clip.name == inName){
  339. return clip;
  340. }
  341. }
  342. return null;
  343. }
  344. /**
  345. Return the index of the SoundClip object with the specified name.
  346. @param inName: name of the object to be found
  347. @return The index of the sound, or -1 if none was found.
  348. */
  349. private function getSoundIndex (inName:String) : Number {
  350. for (var i:Number = 0; i < mSounds.length; i++){
  351. var clip:SoundClip = SoundClip(mSounds[i]);
  352. if (clip.name == inName){
  353. return i;
  354. }
  355. }
  356. return -1;
  357. }
  358. /**
  359. Return the movie with the specified name.
  360. @param inName: name of the movie to be found
  361. @return The movie, or null if none was found.
  362. */
  363. private function getMovie (inName:String) : SoundMovie {
  364. for (var i:Number = 0; i < mMovies.length; i++){
  365. var movie:SoundMovie = SoundMovie(mMovies[i]);
  366. if (movie.name == inName){
  367. return movie;
  368. }
  369. }
  370. return null;
  371. }
  372. /**
  373. Return the index of the movie with the specified name
  374. @param inName: name of the movie to be found
  375. @return The index, or -1 if none was found.
  376. */
  377. private function getMovieIndex (inName:String) : Number {
  378. for (var i:Number = 0; i < mMovies.length; i++){
  379. var movie:SoundMovie = SoundMovie(mMovies[i]);
  380. if (movie.name == inName){
  381. return i;
  382. }
  383. }
  384. return -1;
  385. }
  386. /**
  387. Create a new SoundClip object with the specified name in the specified movie
  388. @param inLinkageName: unique identifier for the sound clip
  389. @param inMovieName: name of the movie in which the sound clip will be created
  390. @return The created SoundClip, or null if an error occurred. This indicates that a sound with the specified name has been added already, or that the movie with the specified movie name has not been added.
  391. */
  392. private function createSoundClip (inLinkageName:String, inMovieName:String) : SoundClip {
  393. var clip:SoundClip = getSound(inLinkageName);
  394. if (clip != null){
  395. Log.error("Sound with name '" + inLinkageName + "' already exists in movie '" + clip.movieName + "', not added", toString());
  396. return null;
  397. }
  398. var movie:SoundMovie = getMovie(inMovieName);
  399. if (movie == null){
  400. Log.error("Movie with name '" + inMovieName + "' not found, sound with name '" + inLinkageName + "' not added", toString());
  401. return null;
  402. }
  403. var mc:MovieClip = movie.createClip(inLinkageName);
  404. var sound:EventSound = new EventSound(mc);
  405. clip = new SoundClip(inLinkageName, inMovieName, sound, mc, 100);
  406. return clip;
  407. }
  408. /**
  409. */
  410. public function toString () : String {
  411. return "; org.asapframework.management.sound.SoundManager";
  412. }
  413. }