Add files via upload
|
@ -0,0 +1,360 @@
|
|||
synth={playing={}}
|
||||
|
||||
synth.resettime=function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local mark1 = meta:get_int("mark1")
|
||||
minetest.get_node_timer(pos):stop()
|
||||
meta:set_int("play",0)
|
||||
meta:set_int("timeline",mark1>0 and mark1-1 or 0)
|
||||
meta:set_int("scroll",math.floor(mark1*0.3))
|
||||
synth.playing[minetest.pos_to_string(pos)] = nil
|
||||
synth.form(pos)
|
||||
end
|
||||
|
||||
synth.form=function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local locked = meta:get_int("locked")
|
||||
if meta:get_int("updating") == 0 or (locked == 1 and meta:get_string("user") ~= meta:get_string("owner")) then
|
||||
return
|
||||
end
|
||||
|
||||
local notes = meta:get_string("notes")
|
||||
local size = meta:get_int("size")
|
||||
local bsize = size*0.3
|
||||
local s = meta:get_int("scroll")
|
||||
local b = ""
|
||||
local idx = 0
|
||||
local idy = 1
|
||||
local note = ""
|
||||
local toggle = 0
|
||||
local play = meta:get_int("play")
|
||||
local mark1 = meta:get_int("mark1")
|
||||
local mark2 = meta:get_int("mark2")
|
||||
|
||||
for x=-0.3,size/3,0.3 do
|
||||
if mark2 ~= 0 and idx == mark1 then
|
||||
note = "synth_timeline.png^synth_play.png"
|
||||
toggle = 1
|
||||
else
|
||||
if mark2 ~= 0 and idx == mark2 then
|
||||
toggle = 0
|
||||
note = "synth_timeline.png"
|
||||
elseif toggle == 1 then
|
||||
note = "synth_timeline.png"
|
||||
else
|
||||
note = "default_air.png"
|
||||
end
|
||||
end
|
||||
|
||||
b=b .. "image_button[" .. (x-s) .."," .. 0.6 .. ";0.5,0.5;" .. note .. ";mark:".. idx ..";]"
|
||||
idx=idx+1
|
||||
end
|
||||
|
||||
idx=0
|
||||
|
||||
for y=0.9,4.6,0.3 do
|
||||
for x=-0.3,size/3,0.3 do
|
||||
if string.find(notes,"," .. idx .."x" .. idy .."!") then
|
||||
note = "synth_b1.png"
|
||||
toggle = 1
|
||||
else
|
||||
note = "synth_b0.png"
|
||||
toggle = 0
|
||||
end
|
||||
b=b .. "image_button[" .. (x-s) .."," .. y .. ";0.5,0.5;" .. note .. ";note:" .. toggle ..":" ..idx ..":" .. idy ..";]"
|
||||
idx = idx + 1
|
||||
end
|
||||
idx = 0
|
||||
idy = idy + 1
|
||||
end
|
||||
|
||||
meta:set_string("formspec",
|
||||
"size[16,5]"
|
||||
.."scrollbar[-0.3,4.9;16.4,0.5;horizontal;scroll;" .. s .."]"
|
||||
.. (play == 0 and "image_button[-0.3,-0.3;1,1;synth_play.png;play;]" or "image_button[-0.3,-0.3;1,1;synth_pause.png;pause;]image["..(-0.3)..",1;0.5,4.6;synth_timeline.png]")
|
||||
..b
|
||||
|
||||
.. (meta:get_int("repeat") == 0 and "image_button[1.3,-0.3;1,1;synth_none.png;repeat_off;]" or "image_button[1.3,-0.3;1,1;synth_repeat.png;repeat_on;]")
|
||||
.."image_button[0.5,-0.3;1,1;synth_stop.png;stop;]"
|
||||
.."image_button[2.1,-0.3;1,1;synth_clearnspc.png;clearnspc;]"
|
||||
|
||||
.. (mark2 ~=0 and "image_button[2.9,-0.3;1,1;synth_delete.png;delete;]image_button[3.7,-0.3;1,1;synth_copy.png;copy;]image_button[4.4,-0.3;1,1;synth_paste.png;paste;]" or "")
|
||||
|
||||
.. (locked == 1 and "image_button[5.2,-0.3;1,1;synth_lock.png;lock_on;]" or "image_button[5.2,-0.3;1,1;synth_nolock.png;lock_off;]")
|
||||
|
||||
.."tooltip[play;Play]tooltip[pause;Pause]tooltip[stop;stop]tooltip[repeat_on;Repeat]tooltip[repeat_off;Repeat disabled]tooltip[clearnspc;Clear note space]tooltip[copy;Copy marked notes]tooltip[paste;Paste copied notes]tooltip[delete;Delete marked notes]tooltip[lock_on;Setable by everyone]tooltip[lock_off;Setable only by you]"
|
||||
)
|
||||
end
|
||||
|
||||
minetest.register_node("synth:synth", {
|
||||
description = "Synthesizer",
|
||||
groups = {oddly_breakable_by_hand=1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
tiles = {
|
||||
"synth_synth.png",
|
||||
"synth_synthsides.png"
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.1875, 0.5, -0.25, 0.5},
|
||||
{-0.5, -0.5, -0.5, 0.5, -0.3125, -0.1875},
|
||||
}
|
||||
},
|
||||
on_timer = function (pos, elapsed)
|
||||
local meta = minetest.get_meta(pos)
|
||||
--playing
|
||||
if meta:get_int("play") == 1 then
|
||||
local timeline = meta:get_int("timeline")
|
||||
local mark1 = meta:get_int("mark1")
|
||||
local mark2 = meta:get_int("mark2")
|
||||
|
||||
meta:set_int("timeline",timeline+ 1)
|
||||
|
||||
meta:set_int("scroll",math.floor(meta:get_int("timeline")*0.3))
|
||||
local notes = synth.playing[minetest.pos_to_string(pos)]
|
||||
|
||||
if not notes then
|
||||
synth.resettime(pos)
|
||||
return false
|
||||
end
|
||||
|
||||
local t = notes.notes[timeline ..""]
|
||||
|
||||
if t then
|
||||
minetest.sound_play("synth_sp" .. t.y, {pos=pos, gain = 1})
|
||||
end
|
||||
|
||||
if (mark2 ~= 0 and timeline >= mark2) or timeline >= meta:get_int("size") then
|
||||
if meta:get_int("repeat") == 1 then
|
||||
meta:set_int("timeline",mark1)
|
||||
else
|
||||
synth.resettime(pos)
|
||||
synth.form(pos)
|
||||
return false
|
||||
end
|
||||
end
|
||||
synth.form(pos)
|
||||
return true
|
||||
|
||||
--scrollbar timer
|
||||
elseif meta:get_int("scrolltimer") == 1 then
|
||||
meta:set_int("scrolltimer",0)
|
||||
synth.form(pos)
|
||||
return false
|
||||
end
|
||||
end,
|
||||
on_receive_fields=function(pos, formname, pressed, sender)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if pressed.quit then
|
||||
meta:set_int("updating",0)
|
||||
elseif pressed.repeat_on then
|
||||
meta:set_int("repeat",0)
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.repeat_off then
|
||||
meta:set_int("repeat",1)
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.play then
|
||||
meta:set_int("play",1)
|
||||
local mark1 = meta:get_int("mark1")
|
||||
meta:set_int("timeline",mark1 ~=0 and mark1 or meta:get_int("timeline"))
|
||||
minetest.get_node_timer(pos):start(0.1)
|
||||
synth.playing[minetest.pos_to_string(pos)] = {notes={}}
|
||||
local d = synth.playing[minetest.pos_to_string(pos)]
|
||||
for i,v in pairs(string.split(string.gsub(meta:get_string("notes"),"!",""),",")) do
|
||||
local s = string.split(v,"x")
|
||||
d.notes[s[1]] = {x=s[1],y=s[2]}
|
||||
end
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.pause then
|
||||
minetest.get_node_timer(pos):stop()
|
||||
meta:set_int("play",0)
|
||||
synth.playing[minetest.pos_to_string(pos)] = nil
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.stop then
|
||||
synth.resettime(pos)
|
||||
return
|
||||
elseif pressed.clearnspc then
|
||||
local xmax = 0
|
||||
for i,v in pairs(string.split(string.gsub(meta:get_string("notes"),"!",""),",")) do
|
||||
local s = string.split(v,"x")
|
||||
local x = tonumber(s[1])
|
||||
if x > xmax then
|
||||
xmax = x
|
||||
end
|
||||
end
|
||||
meta:set_int("size",xmax+40)
|
||||
meta:set_int("mark1",0)
|
||||
meta:set_int("mark2",0)
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.delete then
|
||||
local mark1 = meta:get_int("mark1")
|
||||
local mark2 = meta:get_int("mark2")
|
||||
|
||||
if mark1+mark2 ~= 0 then
|
||||
local notes = ""
|
||||
for i,v in pairs(string.split(string.gsub(meta:get_string("notes"),"!",""),",")) do
|
||||
local s = string.split(v,"x")
|
||||
local x = tonumber(s[1])
|
||||
if not (x > mark1-1 and x < mark2+1) then
|
||||
notes = notes .. "," .. x .."x" .. s[2] .."!"
|
||||
end
|
||||
end
|
||||
meta:set_string("notes",notes)
|
||||
synth.form(pos)
|
||||
end
|
||||
return
|
||||
|
||||
elseif pressed.copy then
|
||||
local mark1 = meta:get_int("mark1")
|
||||
local mark2 = meta:get_int("mark2")
|
||||
if mark2 > 0 then
|
||||
local copy = ""
|
||||
local copytmp = {}
|
||||
for i,v in pairs(string.split(string.gsub(meta:get_string("notes"),"!",""),",")) do
|
||||
local s = string.split(v,"x")
|
||||
local sx = tonumber(s[1])
|
||||
copytmp[sx] = copytmp[sx] or {}
|
||||
|
||||
table.insert(copytmp[sx],s[2])
|
||||
end
|
||||
local nempty
|
||||
local text = ""
|
||||
local x = 0
|
||||
for i=mark1,mark2 do
|
||||
for ii,y in pairs(copytmp[i] or {}) do
|
||||
nempty = true
|
||||
text = text .. y .. ","
|
||||
end
|
||||
if not nempty then
|
||||
text = text .. "."
|
||||
end
|
||||
text = text .. ";"
|
||||
if nempty then
|
||||
copy = copy .. text
|
||||
text = ""
|
||||
end
|
||||
nempty = nil
|
||||
end
|
||||
meta:set_string("copy",copy)
|
||||
end
|
||||
return
|
||||
elseif pressed.paste then
|
||||
local mark1 = meta:get_int("mark1") - 1
|
||||
local mark2 = meta:get_int("mark2")
|
||||
if mark2 > 0 then
|
||||
local copy = meta:get_string("copy")
|
||||
local data = ""
|
||||
for i,v in pairs(string.split(copy,";")) do
|
||||
for ii,y in pairs(string.split(v,",")) do
|
||||
|
||||
if y ~= "." then
|
||||
data = data .. "," .. (mark1+i) .. "x" .. y .."!"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
meta:set_string("notes",meta:get_string("notes") .. data)
|
||||
synth.form(pos)
|
||||
end
|
||||
return
|
||||
elseif pressed.lock_off then
|
||||
meta:set_int("locked",1)
|
||||
synth.form(pos)
|
||||
return
|
||||
elseif pressed.lock_on then
|
||||
meta:set_int("locked",0)
|
||||
synth.form(pos)
|
||||
return
|
||||
end
|
||||
--note/button pressed
|
||||
for i,n in pairs(pressed) do
|
||||
--note
|
||||
if string.sub(i,1,5) == "note:" then
|
||||
local b = string.split(i,":")
|
||||
if b[2] == "1" then -- on
|
||||
local notes = string.gsub(meta:get_string("notes"),"," .. b[3] .. "x" .. b[4].."!","")
|
||||
meta:set_string("notes", notes)
|
||||
else
|
||||
meta:set_string("notes",meta:get_string("notes") .."," .. b[3] .. "x" .. b[4] .."!")
|
||||
local size = meta:get_int("size")
|
||||
local b3 = tonumber(b[3])
|
||||
if b3 >= size-20 then
|
||||
meta:set_int("size",size+20-(size-b3))
|
||||
end
|
||||
if b3 > meta:get_int("xmax") then
|
||||
meta:get_int("xmax",b3)
|
||||
end
|
||||
minetest.sound_play("synth_sp" .. b[4], {pos=pos, gain = 1})
|
||||
end
|
||||
synth.form(pos)
|
||||
return
|
||||
--mark
|
||||
elseif string.sub(i,1,5) == "mark:" then
|
||||
local n = tonumber(string.sub(i,6,-1))
|
||||
|
||||
local mark1 = meta:get_int("mark1")
|
||||
local mark2 = meta:get_int("mark2")
|
||||
|
||||
if mark1 + mark2 == 0 then -- first click / create mark
|
||||
meta:set_int("mark2",n+1)
|
||||
meta:set_int("mark1",n)
|
||||
elseif n == mark1 then -- n clear mark
|
||||
meta:set_int("mark2",0)
|
||||
meta:set_int("mark1",0)
|
||||
elseif n > mark1+(mark2-mark1)/2 then --n > mark1 +50%
|
||||
meta:set_int("mark2",n)
|
||||
else -- n < mark1 +50%
|
||||
meta:set_int("mark1",n)
|
||||
|
||||
end
|
||||
synth.form(pos)
|
||||
return
|
||||
end
|
||||
end
|
||||
if pressed.scroll then
|
||||
local scroll = string.sub(pressed.scroll,5,-1)
|
||||
if tonumber(scroll) ~= meta:get_int("scroll",scroll) then
|
||||
meta:set_int("scrolltimer",1)
|
||||
minetest.get_node_timer(pos):stop()
|
||||
minetest.get_node_timer(pos):start(0.3)
|
||||
meta:set_int("scroll",scroll)
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
after_place_node = function(pos, placer, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("size",40)
|
||||
meta:set_int("updating",1)
|
||||
meta:set_int("locked",1)
|
||||
meta:set_string("owner",placer:get_player_name())
|
||||
synth.form(pos)
|
||||
end,
|
||||
on_destruct=function(pos)
|
||||
synth.playing[minetest.pos_to_string(pos)]=nil
|
||||
end,
|
||||
on_rightclick = function(pos,node,player,itemstack,pointed_thing)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("updating",1)
|
||||
meta:set_string("user",player:get_player_name())
|
||||
synth.form(pos)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output="synth:synth",
|
||||
recipe={
|
||||
{"default:tin_ingot","default:copper_ingot","default:steel_ingot"},
|
||||
{"default:electric_lump","default:electric_lump","default:electric_lump"},
|
||||
{"materials:plant_extracts","group:wood","materials:plant_extracts"},
|
||||
},
|
||||
})
|
After Width: | Height: | Size: 155 KiB |
|
@ -0,0 +1,18 @@
|
|||
name = synth
|
||||
description = a synthesizer
|
||||
depends = default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 219 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 221 B |
After Width: | Height: | Size: 307 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 273 B |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 295 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 181 B |