Last active
November 14, 2018 02:01
-
-
Save 1bardesign/6f9353bb6488a367ab2aeb72b999df39 to your computer and use it in GitHub Desktop.
will not work out of the box, as it relies on my class() impl and table.foreach, but should be fairly readable as a jumping off point!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
audio manager | |
]] | |
--sound source wrapper | |
local sound = class() | |
-- | |
function sound:new(source, volume, set) | |
return self:init({ | |
source = source, | |
set = set, | |
volume = volume, | |
}) | |
end | |
--stop the sound | |
function sound:stop() | |
self.set:remove(self) | |
end | |
--todo: volume/etc controls? | |
--soundset - a collection of same-audio sources that can be | |
-- played/triggered as needed and managed as a single unit. | |
local soundset = class() | |
--create a soundset | |
function soundset:new(manager, path, source_count, source_type) | |
local r = self:init({ | |
manager = manager, | |
path = path, | |
source_count = source_count, | |
sounds = {}, | |
sources = {}, | |
}) | |
for i = 1,source_count do | |
table.insert(r.sources, love.audio.newSource(path, source_type)) | |
end | |
return r | |
end | |
--update this set (stop sounds as needed) | |
function soundset:update() | |
table.foreach(self.sounds, function(sound) | |
--clean up stopped sounds | |
if not sound.source:isPlaying() then | |
sound:stop() | |
end | |
end) | |
end | |
--play a sound | |
function soundset:play(loop, reset, volume) | |
if #self.sources == 0 then | |
if reset then | |
--shift the oldest sound and recurse | |
local sound = table.remove(self.sounds, 1) | |
if sound then | |
self:remove(sound) | |
return self:play(loop, reset, volume) | |
end | |
else | |
--could not play | |
return nil | |
end | |
end | |
local source = table.remove(self.sources) | |
--setup source params | |
source:setVolume(volume * self.manager.volume) | |
source:setLooping(loop) | |
--start it | |
love.audio.play(source) | |
--init the sound | |
local sound = sound:new(source, volume, self) | |
--push to sound queue | |
table.insert(self.sounds, sound) | |
--done! | |
return sound | |
end | |
function soundset:remove(sound) | |
--stop the sound | |
love.audio.stop(sound.source) | |
--recycle the source | |
table.insert(self.sources, sound.source) | |
sound.source = nil | |
--remove the sound object | |
table.remove_value(self.sounds, sound) | |
end | |
--the actual audio manager class | |
local audio = class() | |
--create a new audio manager | |
function audio:new() | |
return self:init({ | |
sets = {}, | |
volume = 1.0, | |
}) | |
end | |
--update the audio manager | |
function audio:update() | |
table.foreach(self.sets, soundset.update) | |
end | |
--add a sound set | |
function audio:add_set(name, sound_path, source_count, source_type) | |
if not self.sets[name] then | |
if sound_path == "" then | |
error("missing sound set "..name) | |
end | |
self.sets[name] = soundset:new(self, sound_path, source_count, source_type) | |
end | |
return self.sets[name] | |
end | |
--play a sound set by name, returning the sound | |
function audio:play(name, args) | |
--(args here are default to catch unloaded sounds) | |
local set = self:add_set(name, "", 1, "static") | |
args = args or {} | |
default(args, "loop", false) | |
default(args, "reset", true) | |
default(args, "volume", 1.0) | |
return set:play(args.loop, args.reset, args.volume) | |
end | |
--stop all sounds playing for a given set name | |
function audio:stop(name) | |
if name == nil then | |
for k,v in pairs(self.sets) do | |
self:stop(k) | |
end | |
end | |
if self.sets[name] ~= nil then | |
local sounds = self.sets[name].sounds | |
while #sounds > 0 do | |
sounds[1]:stop() --(handles remove itself) | |
end | |
end | |
end | |
--volume handling | |
--get the current master volume | |
function audio:get_volume() | |
return self.volume | |
end | |
--set the current master volume | |
function audio:set_volume(volume) | |
--limit | |
volume = math.clamp(volume, 0, 1) | |
--(avoid setting everything if no change) | |
if self.volume == volume then | |
return | |
end | |
--update volume for manager and all soundsets | |
self.volume = volume | |
for name, set in pairs(self.sets) do | |
--update active sounds volume | |
table.foreach(set.sounds, function(sound) | |
sound.source:setVolume(sound.volume * volume) | |
end) | |
--update inactive sounds volume (maybe not needed) | |
table.foreach(set.sources, function(source) | |
source:setVolume(volume) | |
end) | |
end | |
end | |
return audio |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment