Rename to SLAM. Add readme

This commit is contained in:
Matthias Richter 2011-12-02 14:00:57 +01:00
parent 0ace40cf66
commit 50c9e08279
3 changed files with 321 additions and 0 deletions

155
slam/README.md Normal file
View File

@ -0,0 +1,155 @@
SLAM
====
... is the **Simple [LÖVE] Audio Manager** formerly known as the
**Benignly Designed Sound Manager.** It's a minimally invasive
augmentation of [LÖVE]'s audio module. In contrast to sources that
can only have one simultaneous playing instance, SLAM sources
create *instances* when played. This way you can play one source
multiple times at once. Each instance will inherit the settings
(volume, speed, looping, ...) of it's SLAM source, but can
override them.
SLAM also features tags, which can be used to modify a number of
sources at the same time.
Example
-------
require 'slam'
function love.load()
music = love.audio.newSource('music.ogg', 'stream') -- creates a new SLAM source
music:setLooping(true) -- all instances will be looping
music:setVolume(.3) -- set volume for all instances
love.audio.play(music) -- play music
woosh = love.audio.newSource({'woosh1.ogg', 'woosh2.ogg'}, 'static')
end
function love.keypressed()
local instance = woosh:play() -- creates a new instance
instance:setPitch(.5 + math.random() * .5) -- set pitch for this instance only
end
Reference
---------
### Operations on Sources
source = love.audio.newSource(what, how)
Returns a new SLAM source. Accepts the same parameters as
[love.audio.newSource](http://love2d.org/wiki/love.audio.newSource), with one major
difference: `what` can be a table, in which case each new playing instance will
pick an item of that table at random.
instance = love.audio.play(source)
instance = source:play()
Plays a source and returns a handle to the player instance. Instances will inherit
the settings (looping, pitch, volume) of `source`.
love.audio.stop(source)
source:stop()
Stops all playing instances of a source.
love.audio.stop()
Stops all playing instances.
source:isStatic()
Returns `true` if the source is static, `false` otherwise.
looping = source:isLooping()
source:setLooping(looping)
pitch = source:getPitch()
source:setPitch(pitch)
volume = source:getVolume()
source:setVolume(volume)
Sets properties for all instances. Affects playing instances immediately. For details
on the parameters, see the [LÖVE wiki](http://love2d.org/wiki/Source).
### Instances
All functions that affect LÖVE Sources can be applied to SLAM instances. These are:
love.audio.pause(instance)
instance:pause()
instance:isPaused()
love.audio.play(instance)
instance:play()
love.audio.resume(instance)
instance:resume()
love.audio.rewind(instance)
instance:rewind()
instance:getDirection()
instance:setDirection()
instance:getPitch()
instance:setPitch()
instance:getPosition()
instance:setPosition()
instance:getVelocity()
instance:setVelocity()
instance:getVolume()
instance:setVolume()
instance:isLooping()
instance:setLooping()
See the [LÖVE wiki](http://love2d.org/wiki/Source) for details.
### Tags
With tags you can group several sources together and call functions upon them. A
simple example might be this:
-- add some stuff to the background tag
drums:addTags('music')
baseline:addTags('background', 'music') -- a source can have multiple tags
muttering:addTags('background')
noise:addTags('background')
cars:addTags('background')
(...)
love.audio.tags.background.setVolume(0) -- mute all background sounds
love.audio.tags.music.setVolume(.1) -- ... but keep the music alive
#### Functions
source:addTags(tag, ...)
Adds one or more tags to a source. By default, all sources are member of the tag `all`.
source:removeTags(tag, ...)
Remove one or more tags from a source.
love.audio.tags.TAG.FUNCTION(...)
love.audio.tags[TAG].FUNCTION(...)
Calls `FUNCTION` on all sources tagged with `TAG`.
[LÖVE]: http://love2d.org

166
slam/slam.lua Normal file
View File

@ -0,0 +1,166 @@
-- Simple LÖVE Audio Manager
--
-- Copyright (c) 2011 Matthias Richter
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- Except as contained in this notice, the name(s) of the above copyright holders
-- shall not be used in advertising or otherwise to promote the sale, use or
-- other dealings in this Software without prior written authorization.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
--
local newInstance = love.audio.newSource
local stop = love.audio.stop
------------------
-- source class --
------------------
local Source = {}
Source.__index = Source
Source.__newindex = error
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
local function get_what(what)
if type(what) == 'table' then
return what[math.random(1,#what)]
end
return what
end
local play_instance, stop_instance
function Source:play()
remove_stopped(self.instances)
local instance = newInstance(get_what(self.what), self.how)
-- overwrite instance:stop() and instance:play()
if not (play_instance and stop_instance) then
play_instance = getmetatable(instance).play
getmetatable(instance).play = error
stop_instance = getmetatable(instance).stop
getmetatable(instance).stop = function(this)
stop_instance(this)
self.instances[this] = nil
end
end
instance:setLooping(self.looping)
instance:setPitch(self.pitch)
instance:setVolume(self.volume)
self.instances[instance] = instance
play_instance(instance)
return instance
end
function Source:stop()
for s in pairs(self.instances) do
s:stop()
end
self.instances = {}
end
function Source:addTags(tag, ...)
if not tag then return end
love.audio.tags[tag][self] = self
return Source.addTags(self, ...)
end
function Source:removeTags(tag, ...)
if not tag then return end
love.audio.tags[tag][self] = nil
return Source.removeTags(self, ...)
end
function Source:isStatic()
return how ~= "stream"
end
-- getter/setter for looping, pitch and volume
for _, property in ipairs{'looping', 'pitch', 'volume'} do
local name = property:sub(1,1):upper() .. property:sub(2)
Source['get' .. name] = function(self)
return self[property]
end
Source['set' .. name] = function(self, val)
self[property] = val
for s in pairs(self.instances) do
s['set' .. name](s, val)
end
end
end
Source.isLooping = Source.getLooping
--------------------------
-- love.audio interface --
--------------------------
function love.audio.newSource(what, how)
local s = {
what = what,
how = how,
instances = {},
looping = false,
pitch = 1,
volume = 1,
}
love.audio.tags.all[s] = s
return setmetatable(s, Source)
end
function love.audio.play(what)
assert(what and what.instances, "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
----------
-- tags --
----------
local Tag = { __mode = "kv" }
function Tag:__index(func)
-- calls a function on all tagged sources
return function(...)
for s in pairs(self) do
assert(type(s[func]) == "function", ("`%s' does not name a function."):format(func))
s[func](s, ...)
end
end
end
love.audio.tags = setmetatable({}, {
__newindex = error,
__index = function(t,k)
local tag = setmetatable({}, Tag)
rawset(t, k, tag)
return tag
end,
})