From 4db16b54bda2a5dc1a67add8ec271330c68ebb64 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 14 Feb 2021 20:58:06 -0500 Subject: [PATCH] Add an audio module --- data/lua/core/_initial.lua | 6 - data/lua/core/audio.lua | 30 +++ .../project.pbxproj | 5 + src/scripting/game_lua_kernel.cpp | 109 +------- src/scripting/game_lua_kernel.hpp | 3 - src/scripting/lua_audio.cpp | 245 +++++++++++++++++- src/soundsource.cpp | 21 +- src/soundsource.hpp | 13 +- 8 files changed, 321 insertions(+), 111 deletions(-) create mode 100644 data/lua/core/audio.lua diff --git a/data/lua/core/_initial.lua b/data/lua/core/_initial.lua index 64eae4e9922b..07501ffdc0d1 100644 --- a/data/lua/core/_initial.lua +++ b/data/lua/core/_initial.lua @@ -74,9 +74,3 @@ end unpack = wesnoth.deprecate_api('unpack', 'table.unpack', 3, '1.17', table.unpack) math.pow = wesnoth.deprecate_api('math.pow', '^', 3, '1.17', function(a,b) return a ^ b end) wesnoth.compare_versions = wesnoth.deprecate_api('wesnoth.compare_versions', 'versions.compare', 1, nil, versions.compare) -if wesnoth.kernel_type() == "Game Lua Kernel" then - -- wesnoth.wml_actions.music doesn't exist yet at this point, so create a helper function instead. - wesnoth.set_music = wesnoth.deprecate_api('wesnoth.set_music', 'wesnoth.music_list', 1, nil, function(cfg) - wesnoth.wml_actions.music(cfg) - end) -end diff --git a/data/lua/core/audio.lua b/data/lua/core/audio.lua new file mode 100644 index 000000000000..e514ed272995 --- /dev/null +++ b/data/lua/core/audio.lua @@ -0,0 +1,30 @@ + +if wesnoth.kernel_type() == "Game Lua Kernel" then + -- Only deprecation stubs for now + wesnoth.play_sound = wesnoth.deprecate_api('wesnoth.play_sound', 'wesnoth.audio.play', 1, nil, wesnoth.audio.play) + wesnoth.sound_volume = wesnoth.deprecate_api('wesnoth.sound_volume', 'wesnoth.audio.volume', 1, nil, function(volume) + local old_volume = wesnoth.audio.volume + if type(volume) == 'number' then + wesnoth.audio.volume = volume + end + return old_volume + end) + wesnoth.add_sound_source = wesnoth.deprecate_api('wesnoth.add_sound_source', 'wesnoth.audio.sources', 1, nil, function(cfg) + wesnoth.audio.sources[cfg.id] = cfg + end, 'Assign a config to the sound source ID') + wesnoth.get_sound_source = wesnoth.deprecate_api('wesnoth.get_sound_source', 'wesnoth.audio.sources', 1, nil, function(id) + return wesnoth.audio.sources[id] + end, 'Index by the sound source ID') + wesnoth.remove_sound_source = wesnoth.deprecate_api('wesnoth.remove_sound_source', 'wesnoth.audio.sources', 1, nil, function(id) + wesnoth.audio.sources[id] = nil + end, 'Assign nil to the sound source ID') + wesnoth.music_list = wesnoth.deprecate_api('wesnoth.music_list', 'wesnoth.audio.music_list', 1, nil, setmetatable({}, { + __len = function() return #wesnoth.audio.music_list end, + __index = function(self, key) return wesnoth.audio.music_list[key] end, + __newindex = function(self, key, value) wesnoth.audio.music_list[key] = value end, + })) + -- wesnoth.wml_actions.music doesn't exist yet at this point, so create a helper function instead. + wesnoth.set_music = wesnoth.deprecate_api('wesnoth.set_music', 'wesnoth.audio.music_list', 1, nil, function(cfg) + wesnoth.wml_actions.music(cfg) + end) +end diff --git a/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj b/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj index 391a290e9693..e13552c8f9b5 100644 --- a/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj +++ b/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj @@ -1035,6 +1035,7 @@ 91E3570B1CACC9B200774252 /* singleplayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC2F600C1A048E220018C9D6 /* singleplayer.cpp */; }; 91ECD5D21BA11A5200B25CF1 /* unit_creator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91ECD5D01BA11A5200B25CF1 /* unit_creator.cpp */; }; 91F8E12E260A25E2002312BA /* lua_mathx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F8E12D260A25E1002312BA /* lua_mathx.cpp */; }; + 91F8E135260A2676002312BA /* lua_audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F8E133260A2676002312BA /* lua_audio.cpp */; }; 91FAC70A1C7FBC3400DAB2C3 /* lua_formula_bridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */; }; 91FBBAD81CB6BC3F00470BFE /* filesystem_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FBBAD71CB6BC3F00470BFE /* filesystem_sdl.cpp */; }; 91FBBADB1CB6D1B700470BFE /* markov_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FBBAD91CB6D1B700470BFE /* markov_generator.cpp */; }; @@ -2210,6 +2211,7 @@ 91EF6C001C9E22E400E2A733 /* reference_counter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = reference_counter.hpp; sourceTree = ""; }; 91F8E12C260A25E1002312BA /* lua_mathx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lua_mathx.hpp; sourceTree = ""; }; 91F8E12D260A25E1002312BA /* lua_mathx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_mathx.cpp; sourceTree = ""; }; + 91F8E133260A2676002312BA /* lua_audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_audio.cpp; sourceTree = ""; }; 91FAC7081C7F931900DAB2C3 /* lua_formula_bridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lua_formula_bridge.hpp; sourceTree = ""; }; 91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_formula_bridge.cpp; sourceTree = ""; }; 91FBBAD71CB6BC3F00470BFE /* filesystem_sdl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filesystem_sdl.cpp; sourceTree = ""; }; @@ -4615,6 +4617,7 @@ 91B621E21B76BAF300B00E0F /* context.hpp */, EC218EA21A106673007C910C /* game_lua_kernel.cpp */, 91B621E41B76BB0100B00E0F /* game_lua_kernel.hpp */, + 91F8E133260A2676002312BA /* lua_audio.cpp */, EC3863621EB6286E0048B0C8 /* lua_audio.cpp */, EC3863631EB6286E0048B0C8 /* lua_audio.hpp */, 461DC52B241F836200B9DD10 /* lua_color.cpp */, @@ -4668,6 +4671,7 @@ ECA1E1001A12755B00426E00 /* mapgen_lua_kernel.cpp */, 91B621EF1B76BB3200B00E0F /* mapgen_lua_kernel.hpp */, 91B621F01B76BB3500B00E0F /* push_check.hpp */, + EC3863631EB6286E0048B0C8 /* lua_audio.hpp */, ); path = scripting; sourceTree = ""; @@ -5473,6 +5477,7 @@ 46F92E732174F6A400602C1C /* addon_list.cpp in Sources */, 46F92E8D2174F6A400602C1C /* password_box.cpp in Sources */, 46F92DF92174F6A400602C1C /* unit_list.cpp in Sources */, + 91F8E135260A2676002312BA /* lua_audio.cpp in Sources */, 46F92E952174F6A400602C1C /* spacer.cpp in Sources */, 627F1EDB175AF35C000042E0 /* aspect_advancements.cpp in Sources */, EC386CF1195119AA006004ED /* animation_component.cpp in Sources */, diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 5405e3ea263b..88b6a061dfbe 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -2436,23 +2436,6 @@ int game_lua_kernel::intf_simulate_combat(lua_State *L) return 4; } -/** - * Modifies the music playlist. - * - Arg 1: WML table, or nil to force changes. - */ -static int intf_set_music(lua_State *L) -{ - deprecated_message("wesnoth.set_music", DEP_LEVEL::INDEFINITE, "", "Use the wesnoth.playlist table instead!"); - if (lua_isnoneornil(L, 1)) { - sound::commit_music_changes(); - return 0; - } - - config cfg = luaW_checkconfig(L, 1); - sound::play_music_config(cfg); - return 0; -} - /** * Plays a sound, possibly repeated. * - Arg 1: string. @@ -2467,26 +2450,6 @@ int game_lua_kernel::intf_play_sound(lua_State *L) return 0; } -/** - * Gets/sets the current sound volume - * - Arg 1: (optional) New volume to set - * - Return: Original volume - */ -static int intf_sound_volume(lua_State* L) -{ - int vol = preferences::sound_volume(); - lua_pushnumber(L, sound::get_sound_volume() * 100.0 / vol); - if(lua_isnumber(L, 1)) { - float rel = lua_tonumber(L, 1); - if(rel < 0.0f || rel > 100.0f) { - return luaL_argerror(L, 1, "volume must be in range 0..100"); - } - vol = static_cast(rel*vol / 100.0f); - sound::set_sound_volume(vol); - } - return 1; -} - /** * Scrolls to given tile. * - Arg 1: location. @@ -3783,60 +3746,6 @@ int game_lua_kernel::intf_teleport(lua_State *L) return 0; } -/** - * Removes a sound source by its ID - * Arg 1: sound source ID - */ -int game_lua_kernel::intf_remove_sound_source(lua_State *L) -{ - soundsource::manager* man = play_controller_.get_soundsource_man(); - std::string id = luaL_checkstring(L, 1); - man->remove(id); - return 0; -} - -/** - * Add a new sound source - * Arg 1: Table containing keyword arguments - */ -int game_lua_kernel::intf_add_sound_source(lua_State *L) -{ - soundsource::manager* man = play_controller_.get_soundsource_man(); - config cfg = luaW_checkconfig(L, 1); - try { - soundsource::sourcespec spec(cfg); - man->add(spec); - man->update(); - } catch (const bad_lexical_cast &) { - ERR_LUA << "Error when parsing sound_source config: invalid parameter." << std::endl; - ERR_LUA << "sound_source config was: " << cfg.debug() << std::endl; - ERR_LUA << "Skipping this sound source..." << std::endl; - } - return 0; -} - -/** - * Get an existing sound source - * Arg 1: The sound source ID - * Return: Config of sound source info, or nil if it didn't exist - * This is a copy of the sound source info, so you need to call - * add_sound_source again after changing it. - */ -int game_lua_kernel::intf_get_sound_source(lua_State *L) -{ - soundsource::manager* man = play_controller_.get_soundsource_man(); - std::string id = luaL_checkstring(L, 1); - config cfg = man->get(id); - if(cfg.empty()) { - return 0; - } - // Sound sources do not know their own string ID - // Thus, we need to add this manually - cfg["id"] = id; - luaW_pushconfig(L, cfg); - return 1; -} - /** * Logs a message * Arg 1: (optional) Logger; "wml" for WML errors or deprecations @@ -4017,11 +3926,8 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports { "get_viewing_side", &intf_get_viewing_side }, { "invoke_synced_command", &intf_invoke_synced_command }, { "modify_ai", &intf_modify_ai_old }, - { "set_music", &intf_set_music }, - { "sound_volume", &intf_sound_volume }, { "unsynced", &intf_do_unsynced }, { "add_event_handler", &dispatch<&game_lua_kernel::intf_add_event > }, - { "add_sound_source", &dispatch<&game_lua_kernel::intf_add_sound_source > }, { "allow_end_turn", &dispatch<&game_lua_kernel::intf_allow_end_turn > }, { "allow_undo", &dispatch<&game_lua_kernel::intf_allow_undo > }, { "cancel_action", &dispatch<&game_lua_kernel::intf_cancel_action > }, @@ -4036,7 +3942,6 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports { "fire_event_by_id", &dispatch2<&game_lua_kernel::intf_fire_event, true > }, { "get_all_vars", &dispatch<&game_lua_kernel::intf_get_all_vars > }, { "get_end_level_data", &dispatch<&game_lua_kernel::intf_get_end_level_data > }, - { "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > }, { "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day > }, { "get_max_liminal_bonus", &dispatch<&game_lua_kernel::intf_get_max_liminal_bonus > }, { "get_variable", &dispatch<&game_lua_kernel::intf_get_variable > }, @@ -4044,11 +3949,9 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports { "log", &dispatch<&game_lua_kernel::intf_log > }, { "message", &dispatch<&game_lua_kernel::intf_message > }, { "open_help", &dispatch<&game_lua_kernel::intf_open_help > }, - { "play_sound", &dispatch<&game_lua_kernel::intf_play_sound > }, { "print", &dispatch<&game_lua_kernel::intf_print > }, { "redraw", &dispatch<&game_lua_kernel::intf_redraw > }, { "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > }, - { "remove_sound_source", &dispatch<&game_lua_kernel::intf_remove_sound_source > }, { "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > }, { "select_hex", &dispatch<&game_lua_kernel::intf_select_hex > }, { "set_time_of_day", &dispatch<&game_lua_kernel::intf_set_time_of_day > }, @@ -4272,6 +4175,18 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports lua_setfield(L, -2, "interface"); lua_pop(L, 1); + // Create the audio module + cmd_log_ << "Adding audio module...\n"; + static luaL_Reg const audio_callbacks[] { + { "play", &dispatch<&game_lua_kernel::intf_play_sound > }, + { nullptr, nullptr } + }; + lua_getglobal(L, "wesnoth"); + lua_newtable(L); + luaL_setfuncs(L, audio_callbacks, 0); + lua_setfield(L, -2, "audio"); + lua_pop(L, 1); + // Create the playlist table with its metatable cmd_log_ << lua_audio::register_table(L); diff --git a/src/scripting/game_lua_kernel.hpp b/src/scripting/game_lua_kernel.hpp index 7d9750cae98d..670caad29935 100644 --- a/src/scripting/game_lua_kernel.hpp +++ b/src/scripting/game_lua_kernel.hpp @@ -166,9 +166,6 @@ class game_lua_kernel : public lua_kernel_base int intf_fire_event(lua_State *L, const bool by_id); int intf_fire_wml_menu_item(lua_State *L); int intf_teleport(lua_State *L); - int intf_remove_sound_source(lua_State *L); - int intf_add_sound_source(lua_State *L); - int intf_get_sound_source(lua_State *L); int intf_log(lua_State *L); int intf_toggle_fog(lua_State *L, const bool clear); int intf_get_fog_or_shroud(lua_State *L, bool fog); diff --git a/src/scripting/lua_audio.cpp b/src/scripting/lua_audio.cpp index 28a0911c1401..14382dba02a8 100644 --- a/src/scripting/lua_audio.cpp +++ b/src/scripting/lua_audio.cpp @@ -21,6 +21,8 @@ See the COPYING file for more details. #include "sound.hpp" #include "sound_music_track.hpp" #include "preferences/general.hpp" +#include "resources.hpp" +#include "soundsource.hpp" #include static lg::log_domain log_audio("audio"); @@ -29,6 +31,7 @@ static lg::log_domain log_audio("audio"); #define ERR_AUDIO LOG_STREAM(err, log_audio) static const char* Track = "music track"; +static const char* Source = "sound source"; class lua_music_track { std::shared_ptr track; @@ -68,6 +71,35 @@ static lua_music_track* get_track(lua_State* L, int i) { return static_cast(luaL_checkudata(L, i, Track)); } +class lua_sound_source { + soundsource::sourcespec spec; +public: + explicit lua_sound_source(const soundsource::sourcespec& spec) : spec(spec) {} + lua_sound_source(lua_sound_source&) = delete; + soundsource::sourcespec& operator*() { + return spec; + } + const soundsource::sourcespec& operator*() const { + return spec; + } + soundsource::sourcespec* operator->() { + return &spec; + } + const soundsource::sourcespec* operator->() const { + return &spec; + } +}; + +static lua_sound_source& push_source(lua_State* L, const soundsource::sourcespec& spec) { + lua_sound_source* src = new(L) lua_sound_source(spec); + luaL_setmetatable(L, Source); + return *src; +} + +static lua_sound_source& get_source(lua_State* L, int i) { + return *static_cast(luaL_checkudata(L, i, Source)); +} + /** * Destroys a lua_music_track object before it is collected (__gc metamethod). */ @@ -301,12 +333,193 @@ static int impl_track_eq(lua_State* L) { return 1; } +/** + * Get an existing sound source + * Key: The sound source ID + */ +static int impl_sndsrc_get(lua_State* L) { + if(!resources::soundsources) { + return 0; + } + std::string id = luaL_checkstring(L, 2); + if(!resources::soundsources->contains(id)) { + return 0; + } + push_source(L, resources::soundsources->get(id)); + return 1; +} + +/** + * Adds or removes a sound source by its ID + * Key: sound source ID + * Value: Table containing keyword arguments, existing sound source userdata, or nil to delete + */ +static int impl_sndsrc_set(lua_State* L) { + if(!resources::soundsources) { + return 0; + } + std::string id = luaL_checkstring(L, 2); + config cfg; + if(lua_isnil(L, 3)) { + resources::soundsources->remove(id); + } else if(luaW_toconfig(L, 1, cfg)) { + cfg["id"] = id; + soundsource::sourcespec spec(cfg); + resources::soundsources->add(spec); + resources::soundsources->update(); + } else { + auto& src = get_source(L, 3); + resources::soundsources->add(*src); + resources::soundsources->update(); + } + return 0; +} +static int impl_source_collect(lua_State* L) +{ + lua_sound_source& u = get_source(L, 1); + u.lua_sound_source::~lua_sound_source(); + return 0; +} + +static int impl_source_get(lua_State* L) { + lua_sound_source& src = get_source(L, 1); + const char* m = luaL_checkstring(L, 2); + return_string_attrib("id", src->id()); + return_vector_string_attrib("sounds", utils::split(src->files())); + return_int_attrib("delay", src->minimum_delay()); + return_int_attrib("chance", src->chance()); + return_int_attrib("loop", src->loops()); + return_int_attrib("range", src->full_range()); + return_int_attrib("fade_range", src->fade_range()); + return_bool_attrib("check_fogged", src->check_fogged()); + return_bool_attrib("check_shrouded", src->check_shrouded()); + return_cfg_attrib("__cfg", src->write(cfg)); + + if(strcmp(m, "locations") == 0) { + const auto& locs = src->get_locations(); + lua_createtable(L, locs.size(), 0); + for(const auto& loc : locs) { + luaW_pushlocation(L, loc); + lua_rawseti(L, -1, lua_rawlen(L, -2) + 1); + } + } + + return luaW_getmetafield(L, 1, m); +} + +static int impl_source_set(lua_State* L) { + lua_sound_source& src = get_source(L, 1); + const char* m = luaL_checkstring(L, 2); + modify_int_attrib("delay", src->set_minimum_delay(value)); + modify_int_attrib("chance", src->set_chance(value)); + modify_int_attrib("loop", src->set_loops(value)); + modify_int_attrib("range", src->set_full_range(value)); + modify_int_attrib("fade_range", src->set_fade_range(value)); + modify_bool_attrib("check_fogged", src->set_check_fogged(value)); + modify_bool_attrib("check_shrouded", src->set_check_shrouded(value)); + + if(strcmp(m, "sounds") == 0) { + std::string files; + if(lua_istable(L, 3)) { + files = utils::join(lua_check>(L, 3)); + } else { + files = luaL_checkstring(L, 3); + } + src->set_files(files); + } + + if(strcmp(m, "locations") == 0) { + std::vector locs; + locs.resize(1); + if(luaW_tolocation(L, 3, locs[0])) { + + } else { + locs.clear(); + for(lua_pushnil(L); lua_next(L, 3); lua_pop(L, 1)) { + locs.push_back(luaW_checklocation(L, -1)); + } + } + src->set_locations(locs); + } + + // Now apply the change + resources::soundsources->add(*src); + resources::soundsources->update(); + return 0; +} + +static int impl_source_eq(lua_State* L) { + lua_sound_source& a = get_source(L, 1); + lua_sound_source& b = get_source(L, 2); + if(a->id() != b->id()) { + lua_pushboolean(L, false); + return 1; + } + lua_pushboolean(L, + a->files() == b->files() && + a->minimum_delay() == b->minimum_delay() && + a->chance() == b->chance() && + a->loops() == b->loops() && + a->full_range() == b->full_range() && + a->fade_range() == b->fade_range() && + a->check_fogged() == b->check_fogged() && + a->check_shrouded() == b->check_shrouded() && + std::set(a->get_locations().begin(), a->get_locations().end()) == std::set(b->get_locations().begin(), b->get_locations().end()) + ); + return 1; +} + +/** + * Gets the current sound volume + * - Return: Current volume + */ +static int impl_audio_get(lua_State* L) +{ + std::string m = luaL_checkstring(L, 2); + if(m != "volume") return 0; + int vol = preferences::sound_volume(); + lua_pushnumber(L, sound::get_sound_volume() * 100.0 / vol); + return 1; +} + +/** + * Sets the current sound volume + * - Arg: New volume to set + */ +static int impl_audio_set(lua_State* L) +{ + std::string m = luaL_checkstring(L, 2); + if(m != "volume") { + lua_rawset(L, 1); + return 0; + } + int vol = preferences::sound_volume(); + lua_pushnumber(L, sound::get_sound_volume() * 100.0 / vol); + float rel = lua_tonumber(L, 2); + if(rel < 0.0f || rel > 100.0f) { + return luaL_argerror(L, 1, "volume must be in range 0..100"); + } + vol = static_cast(rel*vol / 100.0f); + sound::set_sound_volume(vol); + return 0; +} + namespace lua_audio { std::string register_table(lua_State* L) { + // Metatable to enable the volume attribute + luaW_getglobal(L, "wesnoth", "audio"); + lua_createtable(L, 0, 2); + static luaL_Reg vol_callbacks[] { + { "__index", impl_audio_get }, + { "__newindex", impl_audio_set }, + { nullptr, nullptr }, + }; + luaL_setfuncs(L, vol_callbacks, 0); + lua_setmetatable(L, -2); + // The music playlist metatable - lua_getglobal(L, "wesnoth"); lua_newuserdatauv(L, 0, 0); - lua_createtable(L, 0, 4); + lua_createtable(L, 0, 10); static luaL_Reg pl_callbacks[] { { "__index", impl_music_get }, { "__newindex", impl_music_set }, @@ -324,6 +537,20 @@ namespace lua_audio { lua_setfield(L, -2, "__metatable"); lua_setmetatable(L, -2); lua_setfield(L, -2, "music_list"); + + // The sound source map metatable + lua_newuserdatauv(L, 0, 0); + lua_createtable(L, 0, 3); + static luaL_Reg slm_callbacks[] { + { "__index", impl_sndsrc_get }, + { "__newindex", impl_sndsrc_set }, + { nullptr, nullptr }, + }; + luaL_setfuncs(L, slm_callbacks, 0); + lua_pushstring(L, "sound source map"); + lua_setfield(L, -2, "__metatable"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "sources"); lua_pop(L, 1); // The music track metatable @@ -338,6 +565,20 @@ namespace lua_audio { luaL_setfuncs(L, track_callbacks, 0); lua_pushstring(L, Track); lua_setfield(L, -2, "__metatable"); + lua_pop(L, 1); + + // The sound source metatable + luaL_newmetatable(L, Source); + static luaL_Reg source_callbacks[] { + {"__gc", impl_source_collect}, + { "__index", impl_source_get }, + { "__newindex", impl_source_set }, + { "__eq", impl_source_eq }, + { nullptr, nullptr }, + }; + luaL_setfuncs(L, source_callbacks, 0); + lua_pushstring(L, Source); + lua_setfield(L, -2, "__metatable"); return "Adding music playlist table..."; } diff --git a/src/soundsource.cpp b/src/soundsource.cpp index dd6a78278896..314e4eec049f 100644 --- a/src/soundsource.cpp +++ b/src/soundsource.cpp @@ -52,7 +52,7 @@ void manager::add(const sourcespec &spec) sources_[spec.id()].reset(new positional_source(spec)); } -config manager::get(const std::string &id) +sourcespec manager::get(const std::string &id) { config cfg; positional_source_iterator it = sources_.find(id); @@ -73,6 +73,11 @@ void manager::remove(const std::string &id) } } +bool manager::contains(const std::string& id) +{ + return sources_.find(id) != sources_.end(); +} + void manager::update() { unsigned int time = SDL_GetTicks(); @@ -215,6 +220,20 @@ void positional_source::write_config(config& cfg) const write_locations(locations_, cfg); } +void sourcespec::write(config& cfg) const +{ + cfg["id"] = id_; + cfg["sounds"] = files_; + cfg["delay"] = min_delay_; + cfg["chance"] = chance_; + cfg["check_fogged"] = check_fogged_; + cfg["check_shrouded"] = check_shrouded_; + cfg["loop"] = loops_; + cfg["full_range"] = range_; + cfg["fade_range"] = faderange_; + write_locations(locations_, cfg); +} + sourcespec::sourcespec(const config& cfg) : id_(cfg["id"]), files_(cfg["sounds"]), diff --git a/src/soundsource.hpp b/src/soundsource.hpp index ef5709048887..a07b68d0980f 100644 --- a/src/soundsource.hpp +++ b/src/soundsource.hpp @@ -93,7 +93,8 @@ class manager : public events::observer // add or replace a soundsource void add(const sourcespec &source); void remove(const std::string &id); - config get(const std::string &id); + sourcespec get(const std::string &id); + bool contains(const std::string& id); void update(); // checks which sound sources are visible @@ -114,7 +115,7 @@ class manager : public events::observer class sourcespec { const std::string id_; - const std::string files_; + std::string files_; int min_delay_; int chance_; @@ -172,6 +173,10 @@ class sourcespec return locations_; } + void set_locations(const std::vector& locs) { + locations_ = locs; + } + int full_range() const { return range_; } void set_full_range(int value) { @@ -199,6 +204,10 @@ class sourcespec const std::string& id() const { return id_; } const std::string& files() const { return files_; } + + void set_files(const std::string& f) { + files_ = f; + } }; } // namespace soundsource