balatro-mods/lovely/dump/engine/sound_manager.lua
2025-01-19 15:01:49 +08:00

223 lines
7.3 KiB
Lua

LOVELY_INTEGRITY = '72872b3b4770af870f29bca0a9c04f8e62103c150ae3d5e6600706da63ac8e0b'
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