Sound Effect / Forward + Jump? / Collision (kinda)

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Ryne
Party member
Posts: 444
Joined: Fri Jan 29, 2010 11:10 am

Sound Effect / Forward + Jump? / Collision (kinda)

Post by Ryne »

Hello again, I'm back with more problems. I have a basic sound created for jumping:

Code: Select all

	audiosrc = {}
	audiosrc.jump = love.audio.newSource("snd/jump.wav", "static" )
Then I have the sound being played in my jump like this:

Code: Select all

	elseif love.keyboard.isDown('x') and player.dir == "right" then -- jump
	love.audio.play(audiosrc.jump)
	curranim = anim.jumpright
	jumping = true
	
	elseif love.keyboard.isDown('x') and player.dir == "left" then
	love.audio.play(audiosrc.jump)
	curranim = anim.jumpleft
	jumping = true
I know the jump code is ugly right now, but when the player jump's it play's the sound just fine, but only once. I can jump about 4-5 times after the first sound and hear nothing, but after a certain amount of time (like 3-5sec) it will play on another jump. Anyone know what's causing this?

EDIT: After adding "love.audio.stop()" to the "else" if no key is down it works but only if I keep held the jump button. So I'm assuming there needs to be some sort of duration?
Last edited by Ryne on Sat Dec 11, 2010 7:28 pm, edited 2 times in total.
@rynesaur
User avatar
Mud
Citizen
Posts: 98
Joined: Fri Nov 05, 2010 4:54 am

Re: Sound Effect

Post by Mud »

If a given sound source is currently playing and you call play again, it won't start over. You have to either wait until it's done, or call 'stop' on it.

Code: Select all

love.audio.stop(sound)
love.audio.play(sound) 
If you want another instance of the same sound to sound to play, such that it overlaps with the current sound, then you need to create a new instance of the audio source and play *that*.
User avatar
thelinx
The Strongest
Posts: 857
Joined: Fri Sep 26, 2008 3:56 pm
Location: Sweden

Re: Sound Effect

Post by thelinx »

Like Mud said, a sound source can only be playing one at a time. I'll steal a metaphor I read somewhere and tell it to you:

Think of sound sources like a trumpet. The trumpet can't play the more than once at a time. So, what do you do to solve this issue?
You add more trumpets.

The easiest way to do this is to use a library like Soundmanager (LÖVE-class also has this functionality) to create and play sources for you on demand.

Basically, you need to create your sound as a SoundData, and when you want to play it, create a Source from the SoundData and play that.
User avatar
prototypez
Prole
Posts: 14
Joined: Wed Jul 21, 2010 8:17 pm

Re: Sound Effect

Post by prototypez »

A technique I learned from the inimitable 'Ten Second War' is to create a table of identical sound sources thusly:

Code: Select all


sounds = {}

for i = 1, 10 do
    sounds[i] = love.audio.newSource(yoursound, "static")
end

soundcounter = 0
Then, when you play your sound, do it like this:

Code: Select all


    love.audio.play(sounds[soundcounter])

    soundcounter = soundcounter + 1
    if soundcounter > table.getn(sounds) then
      soundcounter = 1
    end


Kinda cheesy, and you're still limited to whatever amount of sounds you have in the table playing at the same time, but for smaller low mem sounds it workd pretty good for me.
I love dashes... -- omnomnomnom oishii desu!
User avatar
Ryne
Party member
Posts: 444
Joined: Fri Jan 29, 2010 11:10 am

Re: Sound Effect

Post by Ryne »

prototypez wrote:A technique I learned from the inimitable 'Ten Second War' is to create a table of identical sound sources thusly:

Code: Select all


sounds = {}

for i = 1, 10 do
    sounds[i] = love.audio.newSource(yoursound, "static")
end

soundcounter = 0
Then, when you play your sound, do it like this:

Code: Select all


    love.audio.play(sounds[soundcounter])

    soundcounter = soundcounter + 1
    if soundcounter > table.getn(sounds) then
      soundcounter = 1
    end


Kinda cheesy, and you're still limited to whatever amount of sounds you have in the table playing at the same time, but for smaller low mem sounds it workd pretty good for me.
To be honest, I actually thought of doing that on my own, I just assumed I was working with sounds wrong, and therefore it wouldn't be as complicated as that.

EDIT: Actually When I use this code outside of update it doesn't work, once inside update it cause sever lag, about 2 fps in the game. This only happens if the iterator is inside of update:

Code: Select all

for i = 1, 10 do
    sounds[i] = love.audio.newSource(yoursound, "static")
end
@rynesaur
User avatar
tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

Re: Sound Effect

Post by tentus »

I'm going to pull a Zac and post an entire block of code: this is a pared-down version of what I use in my game, hopefully you can adapt it to your needs.

Early in the main game I have this:

Code: Select all

require "subclass/sfx.lua"
sfx = soundfx:new()
And then this is the subclass sfx file (please note that I am using classes to make this work):

Code: Select all

require "subclass/class.lua"
soundfx = class:new() 

function soundfx:init()
	self.sfx_jump = love.audio.newSource("media/sfx/jump.ogg", "static")
	self.sfx_break = love.audio.newSource("media/sfx/break.ogg", "static")
	self.sfx_death = love.audio.newSource("media/sfx/death.ogg", "static")
	self.tempsound = nil
end

function soundfx:play(sound)
	if sound == "jump" then
		self.tempsound = self.sfx_jump
	elseif sound == "break" then
		self.tempsound = self.sfx_break
	elseif sound == "death" then
		self.tempsound = self.sfx_death
	end
	love.audio.stop(self.tempsound)
	love.audio.play(self.tempsound)
end
And then this can be called from any other function in the game:

Code: Select all

	sfx:play("jump")
Kurosuke needs beta testers
User avatar
TechnoCat
Inner party member
Posts: 1611
Joined: Thu Jul 30, 2009 12:31 am
Location: Denver, CO
Contact:

Re: Sound Effect

Post by TechnoCat »

The problem I foresee with the 10 second war method is that if you have 10 sounds going at once, that will work, but if you have 10 sounds followed by another 10 sounds quickly, the last 10 sounds will go unheard.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Sound Effect

Post by Robin »

@tentus: your code could be simplified like this:

Code: Select all

require "subclass/class.lua"
soundfx = class:new() 

function soundfx:init()
	self.jump = love.audio.newSource("media/sfx/jump.ogg", "static")
	self.break = love.audio.newSource("media/sfx/break.ogg", "static")
	self.death = love.audio.newSource("media/sfx/death.ogg", "static")
end

function soundfx:play(sound)
	love.audio.stop(self[sound])
	love.audio.play(self[sound])
end
What the best solution is depends on what you want: for example, the sound of your own death is likely just played once, so you wouldn't want to use stop(). If it is the sound of the death of a random mook, you'll want to take the soundmanager approach, like thelinx pointed out, which scales well.
Help us help you: attach a .love.
User avatar
tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

Re: Sound Effect

Post by tentus »

Robin wrote:@tentus: your code could be simplified like this:

Code: Select all

require "subclass/class.lua"
soundfx = class:new() 

function soundfx:init()
	self.jump = love.audio.newSource("media/sfx/jump.ogg", "static")
	self.break = love.audio.newSource("media/sfx/break.ogg", "static")
	self.death = love.audio.newSource("media/sfx/death.ogg", "static")
end

function soundfx:play(sound)
	love.audio.stop(self[sound])
	love.audio.play(self[sound])
end
What the best solution is depends on what you want: for example, the sound of your own death is likely just played once, so you wouldn't want to use stop(). If it is the sound of the death of a random mook, you'll want to take the soundmanager approach, like thelinx pointed out, which scales well.
@Robin: Thanks, I appreciate it. I didn't use that method before because it pooped out when I first tested it, but now I realize it's because "break" is a keyword in Lua... doh. All I have to do is rename break to something like "crunch" and it works perfectly. I love the way that half of programming (for me) is fixing dumb errors that I should have seen the first time around.
Kurosuke needs beta testers
User avatar
Mud
Citizen
Posts: 98
Joined: Fri Nov 05, 2010 4:54 am

Re: Sound Effect

Post by Mud »

TechnoCat wrote:The problem I foresee with the 10 second war method is that if you have 10 sounds going at once, that will work, but if you have 10 sounds followed by another 10 sounds quickly, the last 10 sounds will go unheard.
Yeah, my solution was to use the same circular buffer idea, but start with only 1 source and allocate others only if necessary. The worst case usage establishes how many sources you buffer for a particular sound. Once that's hit, there's no more allocating sources, just cycling through existing ones. If a sound is played infrequently, you end up with only one source, and the fast path to it is reasonably direct:

Code: Select all

  function Sound:play()
    repeat
       if sources[self.current]:isStopped() then
          love.audio.play(sources[self.current])
          return
          -- check others sources, starting with oldest moving toward most recently played
Here's the full code for it:

Code: Select all

Sound = class()

function Sound:init(filename)
   self.raw = love.sound.newSoundData(filename)
   self.sources = { love.audio.newSource(self.raw, 'static') }
   self.current = 1
end

function Sound:play()
   local start, sources = self.current, self.sources
   repeat
      if sources[self.current]:isStopped() then
         love.audio.play(sources[self.current])
         return
      end
      self.current = self.current % #sources + 1
   until self.current == start

   -- no free sources available, create a new one
   self.current = #sources + 1
   sources[self.current] = love.audio.newSource(self.raw, 'static')
   love.audio.play(sources[self.current])
end
Post Reply

Who is online

Users browsing this forum: No registered users and 66 guests