Benignly Designed Sound Manager

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Benignly Designed Sound Manager

Post by vrld »

Because the one thing I like about Flash/ActionScript3 is how they handle audio playback and seeing new lovers often have trouble understanding love's audio architecture, I sat down and tried to emulate the AS3 behavior. The result is the
Benignly Designed Sound Manager

BDSM overwrites love.audio.newSource, love.audio.play and love.audio.stop, so that one source can be played multiple times.

love.audio.newSource(what, how)
Returns a new bdsm source. The parameters are the same as for the old love.audio.newSource().

love.audio.play(source) and source:play()
Plays the source and returns a handle to the player. The player is the same as love.audio's Source object. In contrast to love.audio, you can safely ignore the handles.

love.audio.stop(source) and source:stop()
Stops all instances of source. If source is omitted, it will stop all the sources.

The source code is rather short: Warning: OLD CODE

Code: Select all

local newSource = love.audio.newSource
local stop = love.audio.stop

local function remove_stopped(sources)
	local remove = {}
	for _, s in pairs(sources) do
		remove[s] = true
	end
	for s, _ in pairs(remove) do
		sources[s] = nil
	end
end

function love.audio.newSource(what, how)
	return {
		play = function(self)
			remove_stopped(self.handles)

			local s = newSource(what, how)
			s:setLooping(self.looping)
			s:setPitch(self.pitch)
			s:setVolume(self.volume)

			self.handles[s] = s
			s:play()
			return s
		end,

		stop = function(self)
			for _, s in pairs(self.handles) do
				s:stop()
			end
			self.handles = {}
		end,

		setLooping = function(self, v) self.looping = not not v   end,
		setPitch   = function(self, v) self.pitch   = tonumber(v) end,
		setVolume  = function(self, v) self.volume  = tonumber(v) end,

		looping = false,
		pitch = 1,
		volume = 1,
		handles = {},
	}
end

function love.audio.play(what)
	assert(what.handles, "Can only play source objects.")
	return what:play()
end

function love.audio.stop(what)
	if what and what.stop then return what:stop() end
	stop()
end
Example code:

Code: Select all

require 'bdsm'

function love.load()
	music = love.audio.newSource('music.ogg', 'stream')
	music:setLooping(true) -- set default value for all players
	music:setVolume(.3)
	love.audio.play(music) -- the handle can be ignored

	woosh = love.audio.newSource('woosh.ogg', 'static')

	love.graphics.setFont(30)
end

function love.draw()
	love.graphics.print('Press a key!', 20,20)
end

function love.keypressed()
	local h = woosh:play() -- same as love.audio.play(woosh)
	h:setPitch(.5 + math.random() * 3) -- set pitch for individual players
end
Can you see yourself using this?
If not: why?
What can be improved?

Edit:
This is now on github: https://github.com/vrld/Stuff/tree/master/bdsm
Attachments
example.love
Simple example. Old version.
(2.09 MiB) Downloaded 427 times
Last edited by vrld on Mon Oct 24, 2011 4:48 pm, edited 1 time in total.
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
Taehl
Dreaming in associative arrays
Posts: 1025
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

Re: Benignly Designed Sound Manager

Post by Taehl »

I like it (I'm assuming it works fully, rather than testing it). About the only reason I could see myself using TEsound instead of this is for two features: Sound tags (so you can set the volume or pitch of many different sounds together, thus enabling things like a "sound effect volume" option) and being able to pass it a table of sounds and it'll choose one at random. Also, lovely name.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
User avatar
adnzzzzZ
Party member
Posts: 305
Joined: Sun Dec 26, 2010 11:04 pm
Location: Porto Alegre, Brazil

Re: Benignly Designed Sound Manager

Post by adnzzzzZ »

I have been playing with sound synthesis using LÖVE and I have designed something very similar to what you have here (I think, maybe: https://github.com/adonaac/love/tree/master/ss). But for what I'm doing I still have some problems with emulating a buffer and/or pop/click noises at the end and start of sources (although I think this has to do with the way I'm handling the samples)...

Regardless, your solution to my problems look a lot better. I will use this soon and report on what I think of it. Thanks!
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Benignly Designed Sound Manager

Post by Robin »

Very interesting, I might want to use that (seems perfect for Jams, for example). The only thing is that I might want to distinguish between BDSM Sources and regular old Sources.
Help us help you: attach a .love.
User avatar
headchant
Party member
Posts: 105
Joined: Fri Sep 03, 2010 12:39 pm
Contact:

Re: Benignly Designed Sound Manager

Post by headchant »

In combination with your proxy stuff this could extremely simplify the whole sound managing business.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: Benignly Designed Sound Manager

Post by T-Bone »

Great name. Will check it out.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Benignly Designed Sound Manager

Post by kikito »

I like this very much! (IMHO this is how LÖVE should handle all sound, I've already talked about this)
vrld wrote:What can be improved?
Only two things:
  • Put it on github (or some other public repo). Or put a link on the forum, if it's already there.
  • newSource creates a lot of functions nearly identical. Wouldn't it be possible to extract them to a metatable?
When I write def I mean function.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Benignly Designed Sound Manager

Post by vrld »

Late reply, but better late than never. Thanks for the feedback :)
Taehl wrote:two features: Sound tags (so you can set the volume or pitch of many different sounds together, thus enabling things like a "sound effect volume" option)
That is a great idea! Tags can be played/stopped/pitched/whatevered by using love.audio.tags.tagname.foo, e.g. love.audio.tags.effects.setPitch(0.6). Doing stuff on tags will act upon all sources and their playing instances in that tag. By default, all sources are members of the 'all' tag, so you can act on all sources via love.audio.tags.all.

Likewise, modifying a source's pitch, volume or looping behavior will effect all playing instances of that source. So be careful with that.
Taehl wrote:and being able to pass it a table of sounds and it'll choose one at random.
Not quite sure what that means: Playing a shuffled playlist, or just choosing a sound to play, i.e.:

Code: Select all

sounds = table.shuffle{'foo.ogg', 'bar.ogg', 'baz.ogg'} -- doesn't exist
source = love.audio.newSource(sounds[1])
souce:play()
adnzzzzZ wrote: But for what I'm doing I still have some problems with emulating a buffer and/or pop/click noises at the end and start of sources
Just to clarify: This lib has nothing to do with sound synthesis, and it will not remove the clicking sounds. These are caused by your sound not having zero crossings at the beginning and end. To get rid of them, make sure the last sample you write is 0.0, either by using an envelope, or by making the sound duration a multiple of the wavelength of your wave function. On a side note (haha, get it? :ehem:), you might be interested in Moan.

Robin wrote:The only thing is that I might want to distinguish between BDSM Sources and regular old Sources.
Doable, but hackish:
  • function isLoveSource(s) return type(s) == "userdata" and s:typeOf("Source") end
  • function isLoveSource(s) return s.instances ~= nil end
  • function isLoveSource(s) return love.tags.all[s] ~= nil end
Kikito wrote:Put it on github
Done: https://github.com/vrld/Stuff/
The name will probably change in the future, since there already is bdsm for LÖVE.
Kikito wrote:newSource creates a lot of functions nearly identical. Wouldn't it be possible to extract them to a metatable?
Good point. Also done.
Kikito wrote:Put it on github
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
Taehl
Dreaming in associative arrays
Posts: 1025
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

Re: Benignly Designed Sound Manager

Post by Taehl »

Sounds tags are in? Awesome.
vrld wrote:
Taehl wrote:and being able to pass it a table of sounds and it'll choose one at random.
Not quite sure what that means: Playing a shuffled playlist, or just choosing a sound to play, i.e.:

Code: Select all

sounds = table.shuffle{'foo.ogg', 'bar.ogg', 'baz.ogg'} -- doesn't exist
source = love.audio.newSource(sounds[1])
souce:play()
Choosing a sound to play. What I enjoy doing are things like:

Code: Select all

-- in love.load or content.lua
sounds = {
	growl = {
		"sounds/growl01.ogg", "sounds/growl02.ogg", "sounds/growl03.ogg", "sounds/growl04.ogg", "sounds/growl05.ogg", "sounds/growl06.ogg", "sounds/growl07.ogg", "sounds/growl08.ogg",
	},
}


-- somewhere in my game's code
-- This plays one growl sound at random
TEsound.play(sounds.growl)

-- That's functionally equivalent to, but much nicer to type, than
TEsound.play(sounds.growl[math.random(#sounds.growl)])
-- or in this case,
love.audio.play(love.audio.newSource(sounds.growl[math.random(#sounds.growl)], "stream"))
Also worth mentioning is that if you loop a random sound like this in TEsound, it'll choose a different sound each time. So you could very easily play a random list of music, for example. Would that be possible in BDSM?

... I don't think you mentioned how to add tags to sounds in BDSM...
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
User avatar
slime
Solid Snayke
Posts: 3133
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Benignly Designed Sound Manager

Post by slime »

Taehl wrote:Sounds tags are in? Awesome.
vrld wrote:
Taehl wrote:and being able to pass it a table of sounds and it'll choose one at random.
Not quite sure what that means: Playing a shuffled playlist, or just choosing a sound to play, i.e.:

Code: Select all

sounds = table.shuffle{'foo.ogg', 'bar.ogg', 'baz.ogg'} -- doesn't exist
source = love.audio.newSource(sounds[1])
souce:play()
Choosing a sound to play. What I enjoy doing are things like:

Code: Select all

-- in love.load or content.lua
sounds = {
	growl = {
		"sounds/growl01.ogg", "sounds/growl02.ogg", "sounds/growl03.ogg", "sounds/growl04.ogg", "sounds/growl05.ogg", "sounds/growl06.ogg", "sounds/growl07.ogg", "sounds/growl08.ogg",
	},
}


-- somewhere in my game's code
-- This plays one growl sound at random
TEsound.play(sounds.growl)

-- That's functionally equivalent to, but much nicer to type, than
TEsound.play(sounds.growl[math.random(#sounds.growl)])
-- or in this case,
love.audio.play(love.audio.newSource(sounds.growl[math.random(#sounds.growl)], "stream"))
Also worth mentioning is that if you loop a random sound like this in TEsound, it'll choose a different sound each time. So you could very easily play a random list of music, for example. Would that be possible in BDSM?

... I don't think you mentioned how to add tags to sounds in BDSM...
Is it really that hard to do the random stuff yourself? I don't see it being an essential part of a sound library. :P
Post Reply

Who is online

Users browsing this forum: No registered users and 174 guests