LOVELY_INTEGRITY = 'a89ca7b9273fee523938c932a6467dfa383c8e44b527c8da74869b0ae75efe92' require "love.audio" require "love.sound" require "love.system" if (love.system.getOS() == 'OS X' )and (jit.arch == 'arm64' or jit.arch == 'arm') then jit.off() end --vars needed for sound manager thread CHANNEL = love.thread.getChannel("sound_request") LOAD_CHANNEL = love.thread.getChannel('load_channel') LOAD_CHANNEL:push('audio thread start') DISABLE_SFX = false SMODS_Sounds = {} --create all sounds from resources and play one each to load into mem SOURCES = {} local sound_files = love.filesystem.getDirectoryItems("resources/sounds") for _, filename in ipairs(sound_files) do local extension = string.sub(filename, -4) for i = 1, 1 do if extension == '.ogg' then LOAD_CHANNEL:push('audio file - '..filename) local sound_code = string.sub(filename, 1, -5) local s = { sound = love.audio.newSource("resources/sounds/"..filename,string.find(sound_code,'music') and "stream" or 'static'), filepath = "resources/sounds/"..filename } SOURCES[sound_code] = {} table.insert(SOURCES[sound_code], s) s.sound_code = sound_code s.sound:setVolume(0) love.audio.play(s.sound) s.sound:stop() end end end function PLAY_SOUND(args) args.per = args.per or 1 args.vol = args.vol or 1 SOURCES[args.sound_code] = SOURCES[args.sound_code] or {} for _, s in ipairs(SOURCES[args.sound_code]) do if s.sound and not s.sound:isPlaying() then s.original_pitch = args.per s.original_volume = args.vol s.created_on_pause = args.overlay_menu s.created_on_state = args.state s.sfx_handled = 0 s.transition_timer = 0 SET_SFX(s, args) love.audio.play(s.sound) return s end end local should_stream = (string.find(args.sound_code,'music') or string.find(args.sound_code,'ambient')) local c = SMODS_Sounds[args.sound_code] local s = c and {sound = love.audio.newSource(love.sound.newDecoder(c.data), c.should_stream and 'stream' or 'static'), per = c.per, vol = c.vol } or {sound = love.audio.newSource("resources/sounds/"..args.sound_code..'.ogg', should_stream and "stream" or 'static')} table.insert(SOURCES[args.sound_code], s) s.sound_code = args.sound_code s.original_pitch = ((args.type ~= "sound") and s.per) or args.per or 1 s.original_volume = ((args.type ~= "sound") and s.vol) or args.vol or 1 s.created_on_pause = (args.overlay_menu and true or false) s.created_on_state = args.state s.sfx_handled = 0 s.transition_timer = 0 SET_SFX(s, args) love.audio.play(s.sound) return s end function STOP_AUDIO() for _, source in pairs(SOURCES) do for _, s in pairs(source) do if s.sound:isPlaying() then s.sound:stop() end end end end function SET_SFX(s, args) if string.find(s.sound_code,'music') then if s.sound_code == args.desired_track then s.current_volume = s.current_volume or 1 s.current_volume = 1*(args.dt*3) + (1-(args.dt*3))*s.current_volume else s.current_volume = s.current_volume or 0 s.current_volume = 0*(args.dt*3) + (1-(args.dt*3))*s.current_volume end s.sound:setVolume(s.current_volume*s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.music_volume/100.0)) s.sound:setPitch(s.original_pitch*args.pitch_mod) else if s.temp_pitch ~= s.original_pitch then s.sound:setPitch(s.original_pitch) s.temp_pitch = s.original_pitch end local sound_vol = s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.game_sounds_volume/100.0) if s.created_on_state == 13 then sound_vol = sound_vol*args.splash_vol end if sound_vol <= 0 then s.sound:stop() else s.sound:setVolume(sound_vol) end end end function MODULATE(args) if args.desired_track ~= '' then local sound = ((SOURCES[current_track or {}] or {})[1] or {}).sound if not sound or not sound:isPlaying() then RESTART_MUSIC(args) end end for k, v in pairs(SOURCES) do local i=1 while i <= #v do if not v[i].sound:isPlaying() then v[i].sound:release() table.remove(v, i) else i = i + 1 end end current_track = args.desired_track for _, s in pairs(v) do if s.sound and s.sound:isPlaying() and s.original_volume then SET_SFX(s, args) end end end end function RESTART_MUSIC(args) for k, v in pairs(SOURCES) do if string.find(k,'music') then for i, s in ipairs(v) do s.sound:stop() end SOURCES[k] = {} args.per = 0.7 args.vol = 0.6 args.sound_code = k local s = PLAY_SOUND(args) s.initialized = true end end end function AMBIENT(args) for k, v in pairs(SOURCES) do if args.ambient_control[k] then local start_ambient = args.ambient_control[k].vol*(args.sound_settings.volume/100.0)*(args.sound_settings.game_sounds_volume/100.0) > 0 for i, s in ipairs(v) do if s.sound and s.sound:isPlaying() and s.original_volume then s.original_volume = args.ambient_control[k].vol SET_SFX(s, args) start_ambient = false end end if start_ambient then args.sound_code = k args.vol = args.ambient_control[k].vol args.per = args.ambient_control[k].per PLAY_SOUND(args) end end end end function RESET_STATES(state) for k, v in pairs(SOURCES) do for i, s in ipairs(v) do s.created_on_state = state end end end LOAD_CHANNEL:push('finished') while true do --Monitor the channel for any new requests local request = CHANNEL:demand() -- Value from channel if request then if request.type == 'kill' then return end --If the request is for an update to the music track, handle it here if false then elseif request.type == 'sound' then PLAY_SOUND(request) elseif request.type == 'sound_source' then SMODS_Sounds[request.sound_code] = { sound_code = request.sound_code, data = request.data, sound = sound, per = request.per, vol = request.vol, } SOURCES[request.sound_code] = {} elseif request.type == 'stop' then STOP_AUDIO() elseif request.type == 'modulate' then MODULATE(request) if request.ambient_control then AMBIENT(request) end elseif request.type == 'restart_music' then RESTART_MUSIC(request) elseif request.type == 'reset_states' then for k, v in pairs(SOURCES) do for i, s in ipairs(v) do s.created_on_state = request.state end end end end end