Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
Channel Reuse — Gideros Forum

Channel Reuse

antixantix Member
edited September 2016 in General questions
In my current project there are a limited number of sounds that will be playing. For example when the player is firing there needs to be only one sound playing, the sound of the player firing. So there seem to be two ways to accomplish this..

1. Create a new sound channel every time the user presses fire.
2. Create a single sound and restart it every time the user presses fire.

On the surface it seems logical that creating one channel and reusing it over and over would be better than creating new objects over and over. So I put it to the test and the results were interesting to say the least...

- You can reuse a channel as long as it is still currently playing.
- As soon as a channel has finished playing you can not restart it at all.

Here's some code..
local sound = Sound.new("someSound.wav") -- Load sound sample
 
local effect = sound:play(0, false, true) -- Create channel, non looping, paused
 
local function onTouched(e)
	print(effect, "position = ", effect:getPosition()) -- Dump effect and it's current play position to console
 
	if effect:isPaused() then
		effect:setPaused(false) -- Resume
	elseif effect:isPlaying() then
		effect:setPosition(0) -- Restart
	else
		effect = sound:play(0, false, false) -- It can't be restarted, create another
	end
end
 
stage:addEventListener(Event.TOUCHES_BEGIN, onTouched)
In the code above you can tap the screen which will restart the sound, as long as it has not finished playing. Once it has finished playing a new channel object needs to be created.

So this is more efficient than creating a new channel object every time the player presses fire but it would still be preferable to be able to restart a channel that has already finished. Does anyone know how this might be accomplished?

Likes: totebo

+1 -1 (+1 / -0 )Share on Facebook

Comments

  • After thinking a little more on this, I decided the best solution would be to create the channel as a looping channel and then pause the channel when it has completed. Then when the fire button is pressed, unpause the channel and set it's playback position to zero.

    Unfortunately when a channel is set to looping, it does not trigger an Event.COMPLETE event *doh*

    Is it even possible to have an event raised when a channel loops?

    Likes: totebo

    +1 -1 (+1 / -0 )Share on Facebook
  • I agree with the above and after getting used to pooling graphical objects it would make sense to be able to do it with sounds too, to avoid initialisation lag when playing the same sound many times.

    Likes: antix

    My Gideros games: www.totebo.com
    +1 -1 (+1 / -0 )Share on Facebook
  • I think the best solution would be to enable looping sounds to raise a COMPLETE event which would enable them to be paused and restarted at will.

    Sounds are a key element in pretty much any game you can think of and they should really perform a bit better.
  • SinisterSoftSinisterSoft Maintainer
    edited September 2016
    If you load a sound (wav), then you can play it at any time and it adds a channel that is released at the end. There is no apparent penalty or delay. The player just plays back the memory pointed to by the sound load.

    I load all my sounds up at the beginning and play them at will.

    eg, something like this (this is untested code, just making it up here!)...
    sounds={"splat","shot","bang"}
    soundFx={}
    for loop=1,#sounds do
      local s={}
      s.sound=Sound.new("soundfx/"..sounds[loop]..".wav")
      if s then
        sound.play=false
        soundFx[loop]=s
      end
    end
    then in my game code I have something like this if a player gets shot...
       soundFx[1].play=true
    then at the end of the game loop, just before the "end)" I have something like this:
    for loop=1,#soundFx do
      if soundFx[loop].play then
        local channel=soundFx[loop].sound:play()
        if channel then
          soundFx[loop].play=false
        end
      end
    end
    The trick is that if multiple players shoot in the same game frame then only one sound really needs to be played, not 2 or 3 - as each player will think that the sound being played is their shot. The advantage is that the mixer will only need to mix one channel.

    The routine also makes it so that if for some reason the allocation of the channel fails, then it will be retried then next game loop until it plays.

    Maybe something like this would work to replace the "if channel..." stuff above:
    if soundFx[loop].play then
     soundFx[loop].play=not soundFx[loop].sound:play()
    end
    I'm not sure, but you could try it and it gets rid of a few bytes of bytecode.

    You could improve the routine by having a counter decrement so that there will only be x retries, eg you would then have something like this in your code:
      soundFx[1].play=5  -- retry 5 times before ignoring sound
    and having this in the end of loop routine:
    for loop=1,#soundFx do
      local s=soundFx[loop]
      if s.play>0 then
        local channel=s.sound:play()
        if channel then
          s.play=0
        else
          s.play=s.play-1
        end
      end
    end

    Likes: antix

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • @SinisterSoft, that's pretty cool and the idea could be carried over to other things as well, hmm.

    However it is still creating a new channel every time a sound is played (or so it seems). What I would like to do is create one channel and just keep reusing it.

    Still, I think a merging of methods would be pretty cool too. I'll work on that a bit later this evening.

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • Thanks, I don't think that adding more channels delays things that much though. It's the number of simultaneous sounds being played that may slow things down - that's why the easy optimisation of playing the same sound only once if two (or more) people press fire at the same time is an easy optimisation. It could be extended so that it knows if a sound has just started within a frame, so ignore it as the 2nd player will think it's their sound too.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • @SinisterSoft true. I've hacked some of your code into mine..

    The first time a sound effect is played a new channel is created. Each subsequent time the sound effect is played it restarts the channel if it is already playing and creates a new channel if it has completed. There is more logic but it seems more elegant to me.

  • SHARE, SHARE, SHARE!

    (please)

    :D
    My Gideros games: www.totebo.com
  • I did that for an effect in What Rhymes With Martians (now called 'Match 3 Martians') - but if the channel was still playing then it would play the same sound faster and louder. It worked really well.

    The problem if you use the same sound channel if the same sound needs to play again, but hasn't finished is that the sound resets - it sounds good for a gimmick effect, but sounds odd if used for a normal game sound.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • I don't get it. If you just restart the channel (setPosition(0)) then isn't that just the same as playing another sound, but not creating a new channel? I've tested a bit and it seems to sound as it should.
  • SinisterSoftSinisterSoft Maintainer
    edited September 2016
    no, if one player presses fire and it last for 1/2 sec, but 1/4 sec another player presses fire - then you want two sounds to be played and mixed, not the first one restarting or it sounds like a restart.

    This 'effect' can be used as a gimmick effect though - like I mentioned I used it on a previous game so that if the sound was still playing I made the restarted sound faster and louder - so if it happened again it went faster again, etc... If the sound stopped playing then the speed was reset and the volume dropped.

    Imagine the tae tae tae tae on respectable by mel and kim...

    Likes: talis

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • Okay I get it now. For this project there's no requirement for two of the same sounds to play at once so it will work without being "gimicky" ;)

    I suppose I will have to rethink my sound effect class to accommodate for all of these interesting types of effect.
    +1 -1 (+2 / -0 )Share on Facebook
  • talistalis Guru
    edited September 2016
    There can not be a better explanation of the effect to describe to us @sinistersoft you made my day with the song:D

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • I couldn't bring myself to click the song :D
    +1 -1 (+2 / -0 )Share on Facebook
Sign In or Register to comment.