Page 1 of 3
Sound Effect / Forward + Jump? / Collision (kinda)
Posted: Fri Dec 10, 2010 4:09 am
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?
Re: Sound Effect
Posted: Fri Dec 10, 2010 4:51 am
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*.
Re: Sound Effect
Posted: Fri Dec 10, 2010 9:19 am
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.
Re: Sound Effect
Posted: Fri Dec 10, 2010 9:50 am
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.
Re: Sound Effect
Posted: Fri Dec 10, 2010 3:01 pm
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
Re: Sound Effect
Posted: Fri Dec 10, 2010 3:40 pm
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:
Re: Sound Effect
Posted: Fri Dec 10, 2010 4:03 pm
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.
Re: Sound Effect
Posted: Fri Dec 10, 2010 4:13 pm
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.
Re: Sound Effect
Posted: Fri Dec 10, 2010 7:12 pm
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.
Re: Sound Effect
Posted: Fri Dec 10, 2010 10:37 pm
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