10 Replies Latest reply on Sep 20, 2007 12:25 PM by kglad

    Sucky Sound API in AS3

    Chris Ivey
      When I first heard that Adobe had overhauled the sound API in AS3, I was excited. However, now that I'm trying to write audio support for a fairly large application, I'm less enthusiastic about it. It seems that the architects were determined to learn nothing from the old API, and that the only use case they examined was for building an .mp3 player with a visualizer.

      Frankly, I couldn't care less about the byteArray data. If I want a visualizer, I'll download Winamp. I just want to play sounds - but I need to play a lot of them; and track multiple instances of the same sound.

      My problem is with the asymmetrical relationship between sounds and sound instances, (Sound and SoundChannel).

      I find it curious that the constructor for a SoundChannel object is linked to the play() method of Sound:

      (var mySoundChannel:SoundChannel = mySound.play() ;)

      Why not allow us to set the sound property of a SoundChannel object, and then expose a play method on it?

      The biggest problem I have is that the SoundChannel object fails to expose some rather important properties, such as:

      - what sound it's playing
      - what the duration is (playhead position isn't much use without this)
      -how many times it has been set to loop
      -which iteration it is on, if looping

      .. and then it goes on to dispatch an utterly useless soundComplete event, which leaves you asking the question: "what sound was this, anyway?"

      I wouldn't mind nearly so much, if it weren't for the fact that some one for some impenetrably idiotic reason, chose to make SoundChannel FINAL.

      I could change my copy, but I'm writing an API as part of a framework, so that's a bad idea.

      I have been limping along, using associative arrays to link references of soundChannels to Sounds, but this is really kludgy and unwieldy. Has anyone come up with a more elegant workaround?

      Chris Ivey
        • 1. Re: Sucky Sound API in AS3
          kglad Adobe Community Professional & MVP
          one of the nice things about flash is, it's extensible. if you find the sound class fails to meet your needs, extend it to a class that includes the things you want.
          • 2. Re: Sucky Sound API in AS3
            Chris Ivey Level 1
            Extensibility is great. I extend classes all the time. However, SoundChannel, (the class you would generally extend in this case, so you can access its sound property), is marked FINAL. This means you *can't* extend it. This is why I wrote:

            " I wouldn't mind nearly so much, if it weren't for the fact that some one for some impenetrably idiotic reason, chose to make SoundChannel FINAL." I needed to vent.

            That's also why I need a workaround. I can fix some ills by extending Sound, (which isn't FINAL), but this doesn't help address the fact that you're usually manipulating SoundChannel instances, not Sound objects.

            I don't like my current workaround, since it doesn't elegantly handle situations where you have multiple instances of the same sound, and some are set to loop while some aren't.

            Currently, I'm using the array index of a sound that's playing to look up a matching SoundChannel, and vice versa. This is proving to break down quickly when you have multiple SoundChannel instances playing, and you're not sure which one you should be manipulating.

            If you're building a game, for example, it doesn't take long before you have a lot of sounds running around...
            • 3. Re: Sucky Sound API in AS3
              cayennecode Level 1
              If inheritance is a no go why not composition, or decoration?
              • 4. Re: Sucky Sound API in AS3
                kglad Adobe Community Professional & MVP
                i wouldn't extend the soundchannel class. i'd extend the sound class and add a class property for the soundchannel because that seems to be irking you. for example:

                • 5. Sucky Sound API in AS3
                  Chris Ivey Level 1
                  Thanks guys.

                  I have basically ended up using a composition object based on the Sound class - extending Sound and adding array members to it where I can stash SoundChannel objects - a slightly more evolved approach of what kglad was getting at above, (after all, you have to track multiple channels, and also keep track of which sounds are looping, and how many iterations they've run through).

                  This way I can iterate through all the soundChannel instances bound to a sound, and I can also keep track of how many times looped soundChannel instances have repeated. This works, but it involves a good deal of brute force, which "feels" wrong to me. It also forces me to make assumptions about how things should behave - for example, if I get a call to fade a sound out - do I only manipulate the last instance of it, or every instance, or do I build in yet another property and lable instances?...

                  Imagine how much simpler handling audio would be, if, for example, you could dynamically bind ID's and event handlers to SoundChannel instances...

                  At any rate, I have a workable solution now that's much neater than external arrays - even if it has more lines of code, and more properties to keep track of than I would have liked. Thanks for your help.
                  • 6. Re: Sucky Sound API in AS3
                    kglad Adobe Community Professional & MVP
                    why not have one sound instance for each sound like i did in my above code? then each sound has a reference to, for example, its own soundchannel.

                    the only master class you might need would be one that would contain a reference to all the sound instances created.
                    • 7. Sucky Sound API in AS3
                      cayennecode Level 1
                      yeah, I believe you should pursue kglad's suggestion, in that each sound object has it's own SoundChannel member, as a Sound Has-A SoundChannel, right?

                      You can customize events, to pass SoundChannel properties, and implement this within your custom Sound class. Check it: http://www.gskinner.com/blog/archives/2007/07/building_a_stat_1.html

                      I might think of setting up your structure as such.

                      Sound Control Class responsible for instancing IveySound instances. IveySound instances have SoundChannel members, and dispatch customEvents on certain events such as 'LOOP_RESTARTED', 'SOUND_ENDED, etc'. But I would make the IveySound instance responsible for tracking it's number of loops, and disposal.

                      The customEvents pass the IveySound instance name, and any other pertinent info.

                      Sound Control Class listens for these events, as well as user-interaction events, so that when your user scores a point, the Sound Control class can instance an IveySound('score.mp3', 1), which has a loop property of 1 so it only plays once, then disposes itself. Whereas when the user enters level 2, the Sound Control Class can instance an IveySound('level2.mp3', 0, 'levelLoop'), which loops infinitely until the Sound Control Class tells all IveySound instances with levelLoop members to stop. etc
                      • 8. Sucky Sound API in AS3
                        Chris Ivey Level 1
                        Whoa guys!

                        I think you're not understanding what I'm talking about, and it's important to clarify in case someone else reads this and is lead astray.

                        Binding individual soundChannel instances to sound objects is a very, very bad idea. In a game, for example, you almost never end up playing only one instance of a sound at a time. Loading multiple sound instances into memory would be a huge waste, and it takes time. How would you handle this? What if you loaded five instances of a sound effect into memory, and you needed to play a sixth while the five your created were all playing? You'd have to load a new instance of the sound, and then by the time you accessed your hard drive, everything would be out of synch.

                        You need to be able to dynamically create instances of sounds as you play them. That's why you can't have a 1to1 relationship between sounds and soundChannels.

                        And what's with the link to Mr. Skinner's article on creating eventDispatcher objects from inside static classes? That's nice. I do, coincidentally, use exactly that mechanism where appropriate. However, it has nothing to do with this situation.
                        • 9. Sucky Sound API in AS3
                          cayennecode Level 1
                          I've never done what you're doing with streaming multiple sound objects simultaneously, so don't know the performance limitations that would encounter.

                          But in my case I am using a class which extends Sound, and has SoundChannel as a class member. I also have a static event object which broadcasts info about that sound object, so I know it's position, id, and other info.
                          • 10. Re: Sucky Sound API in AS3
                            kglad Adobe Community Professional & MVP
                            soundChannel instances are already bound to an individual Sound. there's nothing you can do about that.

                            your issue was accessing the soundChannel instance via its Sound instance. and i gave you a solution allowing your access the soundChannel instance via a sound instance.

                            if you want to reuse the same sound instance then remove the URLRequest and play() method from the constructor. otherwise, just kill the sound instance when it's no longer needed.