From d603619ad3cc0e5f7ac942e41469462be43e2f5d Mon Sep 17 00:00:00 2001 From: Desour Date: Wed, 14 Sep 2022 20:02:46 +0200 Subject: [PATCH] Devtest: Add jukebox --- .gitignore | 2 + LICENSE.txt | 1 + games/devtest/mods/soundstuff/init.lua | 4 + games/devtest/mods/soundstuff/jukebox.lua | 323 ++++++++++++++++++ games/devtest/mods/soundstuff/mod.conf | 1 + .../gitignored_sounds/custom_sounds_here.txt | 2 + .../textures/soundstuff_jukebox.png | Bin 0 -> 123 bytes 7 files changed, 333 insertions(+) create mode 100644 games/devtest/mods/soundstuff/init.lua create mode 100644 games/devtest/mods/soundstuff/jukebox.lua create mode 100644 games/devtest/mods/soundstuff/sounds/gitignored_sounds/custom_sounds_here.txt create mode 100644 games/devtest/mods/soundstuff/textures/soundstuff_jukebox.png diff --git a/.gitignore b/.gitignore index 647b2ed00..551a34c07 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,8 @@ build/.cmake/ /bin/ /games/* !/games/devtest/ +/games/devtest/mods/soundstuff/sounds/gitignored_sounds/* +!/games/devtest/mods/soundstuff/sounds/gitignored_sounds/custom_sounds_here.txt /cache /textures/* !/textures/base/ diff --git a/LICENSE.txt b/LICENSE.txt index 77228684a..7c30a1d2c 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -77,6 +77,7 @@ SmallJoker: textures/base/pack/server_favorite_delete.png (based on server_favorite.png) DS: + games/devtest/mods/soundstuff/textures/soundstuff_jukebox.png games/devtest/mods/testtools/textures/testtools_branding_iron.png License of Minetest source code diff --git a/games/devtest/mods/soundstuff/init.lua b/games/devtest/mods/soundstuff/init.lua new file mode 100644 index 000000000..07458aea9 --- /dev/null +++ b/games/devtest/mods/soundstuff/init.lua @@ -0,0 +1,4 @@ + +local path = minetest.get_modpath("soundstuff") .. "/" +dofile(path .. "sound_event_items.lua") +dofile(path .. "jukebox.lua") diff --git a/games/devtest/mods/soundstuff/jukebox.lua b/games/devtest/mods/soundstuff/jukebox.lua new file mode 100644 index 000000000..ecba5baa1 --- /dev/null +++ b/games/devtest/mods/soundstuff/jukebox.lua @@ -0,0 +1,323 @@ +local F = minetest.formspec_escape + +-- hashed node pos -> sound handle +local played_sounds = {} + +-- all of these can be set via the formspec +local meta_keys = { + -- SimpleSoundSpec + "sss.name", + "sss.gain", + "sss.pitch", + "sss.fade", + -- sound parameters + "sparam.gain", + "sparam.pitch", + "sparam.fade", + "sparam.loop", + "sparam.pos", + "sparam.object", + "sparam.to_player", + "sparam.exclude_player", + "sparam.max_hear_distance", + -- fade + "fade.step", + "fade.gain", + -- other + "ephemeral", +} + +local function get_all_metadata(meta) + return { + sss = { + name = meta:get_string("sss.name"), + gain = meta:get_string("sss.gain"), + pitch = meta:get_string("sss.pitch"), + fade = meta:get_string("sss.fade"), + }, + sparam = { + gain = meta:get_string("sparam.gain"), + pitch = meta:get_string("sparam.pitch"), + fade = meta:get_string("sparam.fade"), + loop = meta:get_string("sparam.loop"), + pos = meta:get_string("sparam.pos"), + object = meta:get_string("sparam.object"), + to_player = meta:get_string("sparam.to_player"), + exclude_player = meta:get_string("sparam.exclude_player"), + max_hear_distance = meta:get_string("sparam.max_hear_distance"), + }, + fade = { + gain = meta:get_string("fade.gain"), + step = meta:get_string("fade.step"), + }, + ephemeral = meta:get_string("ephemeral"), + } +end + +local function log_msg(msg) + minetest.log("action", msg) + minetest.chat_send_all(msg) +end + +local function try_call(f, ...) + local function log_on_err(success, errmsg, ...) + if not success then + log_msg("[soundstuff:jukebox] Call failed: "..errmsg) + else + return errmsg, ... + end + end + + return log_on_err(pcall(f, ...)) +end + +local function show_formspec(pos, player) + local meta = minetest.get_meta(pos) + + local md = get_all_metadata(meta) + + local pos_hash = minetest.hash_node_position(pos) + local sound_handle = played_sounds[pos_hash] + + local fs = {} + local function fs_add(str) + table.insert(fs, str) + end + + fs_add([[ + formspec_version[6] + size[14,11] + ]]) + + -- SimpleSoundSpec + fs_add(string.format([[ + container[0.5,0.5] + box[-0.1,-0.1;4.2,3.2;#EBEBEB20] + style[*;font=mono,bold] + label[0,0.25;SimpleSoundSpec] + style[*;font=mono] + field[0.00,1.00;4,0.75;sss.name;name;%s] + field[0.00,2.25;1,0.75;sss.gain;gain;%s] + field[1.25,2.25;1,0.75;sss.pitch;pitch;%s] + field[2.50,2.25;1,0.75;sss.fade;fade;%s] + container_end[] + field_close_on_enter[sss.name;false] + field_close_on_enter[sss.gain;false] + field_close_on_enter[sss.pitch;false] + field_close_on_enter[sss.fade;false] + ]], F(md.sss.name), F(md.sss.gain), F(md.sss.pitch), F(md.sss.fade))) + + -- sound parameter table + fs_add(string.format([[ + container[5.5,0.5] + box[-0.1,-0.1;4.2,10.2;#EBEBEB20] + style[*;font=mono,bold] + label[0,0.25;sound parameter table] + style[*;font=mono] + field[0.00,1;1,0.75;sparam.gain;gain;%s] + field[1.25,1;1,0.75;sparam.pitch;pitch;%s] + field[2.50,1;1,0.75;sparam.fade;fade;%s] + field[0,2.25;4,0.75;sparam.loop;loop;%s] + field[0,3.50;4,0.75;sparam.pos;pos;%s] + field[0,4.75;4,0.75;sparam.object;object;%s] + field[0,6.00;4,0.75;sparam.to_player;to_player;%s] + field[0,7.25;4,0.75;sparam.exclude_player;exclude_player;%s] + field[0,8.50;4,0.75;sparam.max_hear_distance;max_hear_distance;%s] + container_end[] + field_close_on_enter[sparam.gain;false] + field_close_on_enter[sparam.pitch;false] + field_close_on_enter[sparam.fade;false] + field_close_on_enter[sparam.loop;false] + field_close_on_enter[sparam.pos;false] + field_close_on_enter[sparam.object;false] + field_close_on_enter[sparam.to_player;false] + field_close_on_enter[sparam.exclude_player;false] + field_close_on_enter[sparam.max_hear_distance;false] + tooltip[sparam.object;Get a name with the Branding Iron.] + ]], F(md.sparam.gain), F(md.sparam.pitch), F(md.sparam.fade), F(md.sparam.loop), + F(md.sparam.pos), F(md.sparam.object), F(md.sparam.to_player), + F(md.sparam.exclude_player), F(md.sparam.max_hear_distance))) + + -- fade + fs_add(string.format([[ + container[10.75,3] + box[-0.1,-0.1;3.2,3.2;#EBEBEB20] + style[*;font=mono,bold] + label[0,0.25;fade] + style[*;font=mono] + field[0.00,1;1,0.75;fade.step;step;%s] + field[1.25,1;1,0.75;fade.gain;gain;%s] + ]], F(md.fade.step), F(md.fade.gain))) + if not sound_handle then + fs_add([[ + box[0,2;3,0.75;#363636FF] + label[0.25,2.375;no sound] + ]]) + else + fs_add([[ + button[0,2;3,0.75;btn_fade;Fade] + ]]) + end + fs_add([[ + container_end[] + field_close_on_enter[fade.step;false] + field_close_on_enter[fade.gain;false] + ]]) + + -- ephemeral + fs_add(string.format([[ + checkbox[0.5,5;ephemeral;ephemeral;%s] + ]], md.ephemeral)) + + -- play/stop and release buttons + if not sound_handle then + fs_add([[ + container[10.75,0.5] + button[0,0;3,0.75;btn_play;Play] + container_end[] + ]]) + else + fs_add([[ + container[10.75,0.5] + button[0,0;3,0.75;btn_stop;Stop] + button[0,1;3,0.75;btn_release;Release] + container_end[] + ]]) + end + + -- save and quit button + fs_add([[ + button_exit[10.75,10;3,0.75;btn_save_quit;Save & Quit] + ]]) + + minetest.show_formspec(player:get_player_name(), "soundstuff:jukebox@"..pos:to_string(), + table.concat(fs)) +end + +minetest.register_node("soundstuff:jukebox", { + description = "Jukebox\nAllows to play arbitrary sounds.", + tiles = {"soundstuff_jukebox.png"}, + groups = {dig_immediate = 2}, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + -- SimpleSoundSpec + meta:set_string("sss.name", "") + meta:set_string("sss.gain", "") + meta:set_string("sss.pitch", "") + meta:set_string("sss.fade", "") + -- sound parameters + meta:set_string("sparam.gain", "") + meta:set_string("sparam.pitch", "") + meta:set_string("sparam.fade", "") + meta:set_string("sparam.loop", "") + meta:set_string("sparam.pos", pos:to_string()) + meta:set_string("sparam.object", "") + meta:set_string("sparam.to_player", "") + meta:set_string("sparam.exclude_player", "") + meta:set_string("sparam.max_hear_distance", "") + -- fade + meta:set_string("fade.gain", "") + meta:set_string("fade.step", "") + -- other + meta:set_string("ephemeral", "") + + meta:mark_as_private(meta_keys) + end, + + on_rightclick = function(pos, _node, clicker, _itemstack, _pointed_thing) + show_formspec(pos, clicker) + end, +}) + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname:sub(1, 19) ~= "soundstuff:jukebox@" then + return false + end + + local pos = vector.from_string(formname, 20) + if not pos or pos ~= pos:round() then + minetest.log("error", "[soundstuff:jukebox] Invalid formname.") + return true + end + + local meta = minetest.get_meta(pos) + + for _, k in ipairs(meta_keys) do + if fields[k] then + meta:set_string(k, fields[k]) + end + end + meta:mark_as_private(meta_keys) + + local pos_hash = minetest.hash_node_position(pos) + local sound_handle = played_sounds[pos_hash] + + if not sound_handle then + if fields.btn_play then + local md = get_all_metadata(meta) + + local sss = { + name = md.sss.name, + gain = tonumber(md.sss.gain), + pitch = tonumber(md.sss.pitch), + fade = tonumber(md.sss.fade), + } + local sparam = { + gain = tonumber(md.sparam.gain), + pitch = tonumber(md.sparam.pitch), + fade = tonumber(md.sparam.fade), + loop = minetest.is_yes(md.sparam.loop), + pos = vector.from_string(md.sparam.pos), + object = testtools.get_branded_object(md.sparam.object), + to_player = md.sparam.to_player, + exclude_player = md.sparam.exclude_player, + max_hear_distance = tonumber(md.sparam.max_hear_distance), + } + local ephemeral = minetest.is_yes(md.ephemeral) + + log_msg(string.format( + "[soundstuff:jukebox] Playing sound: minetest.sound_play(%s, %s, %s)", + string.format("{name=\"%s\", gain=%s, pitch=%s, fade=%s}", + sss.name, sss.gain, sss.pitch, sss.fade), + string.format("{gain=%s, pitch=%s, fade=%s, loop=%s, pos=%s, " + .."object=%s, to_player=\"%s\", exclude_player=\"%s\", max_hear_distance=%s}", + sparam.gain, sparam.pitch, sparam.fade, sparam.loop, sparam.pos, + sparam.object and "", sparam.to_player, sparam.exclude_player, + sparam.max_hear_distance), + tostring(ephemeral))) + + sound_handle = try_call(minetest.sound_play, sss, sparam, ephemeral) + + played_sounds[pos_hash] = sound_handle + show_formspec(pos, player) + end + + else + if fields.btn_stop then + log_msg("[soundstuff:jukebox] Stopping sound: minetest.sound_stop()") + + try_call(minetest.sound_stop, sound_handle) + + elseif fields.btn_release then + log_msg("[soundstuff:jukebox] Releasing handle.") + + played_sounds[pos_hash] = nil + show_formspec(pos, player) + + elseif fields.btn_fade then + local md = get_all_metadata(meta) + + local step = tonumber(md.fade.step) + local gain = tonumber(md.fade.gain) + + log_msg(string.format( + "[soundstuff:jukebox] Fading sound: minetest.sound_fade(, %s, %s)", + step, gain)) + + try_call(minetest.sound_fade, sound_handle, step, gain) + end + end + + return true +end) diff --git a/games/devtest/mods/soundstuff/mod.conf b/games/devtest/mods/soundstuff/mod.conf index 2c631e2da..a6ed6d450 100644 --- a/games/devtest/mods/soundstuff/mod.conf +++ b/games/devtest/mods/soundstuff/mod.conf @@ -1,2 +1,3 @@ name = soundstuff description = Example items and nodes for testing sound effects +depends = testtools diff --git a/games/devtest/mods/soundstuff/sounds/gitignored_sounds/custom_sounds_here.txt b/games/devtest/mods/soundstuff/sounds/gitignored_sounds/custom_sounds_here.txt new file mode 100644 index 000000000..f07d44bae --- /dev/null +++ b/games/devtest/mods/soundstuff/sounds/gitignored_sounds/custom_sounds_here.txt @@ -0,0 +1,2 @@ +Put your own testing sounds here. The folder is gitignored. +Using a sound-pack is also possible. diff --git a/games/devtest/mods/soundstuff/textures/soundstuff_jukebox.png b/games/devtest/mods/soundstuff/textures/soundstuff_jukebox.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c17a669db76b28dd336c75e07a6bde822a6720 GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9oB=)|u0Z