-- feos, r57shell, 2012-2018
-- gui.box frame simulates transparency

print("Hi-hat and keys may glitch if you produce sound effects.")
print("Leftclick over the displays: channel names to hide the volumes, notes to hide the keyboard.")
print(" ")
print("And praise Gocha!")

iterator = 15
kb = {x=9, y=154, on=true}
prev_keys = input.get()
semitones = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"}

volumes = {
	S1V = {0}, S1C = {},
	S2V = {0}, S2C = {},
	TV = {0},
	NV = {0},
	DPCMV = {0}
}

function Draw()
	snd = sound.get()
	keys = input.get()
	
	if iterator == 1 then
		kb.y = 30
	else
		kb.y = 154
	end
	
	-- do only at the first frame
	if #volumes.S1V == 1 then
		channels = {
			Square1  = {x=1,      y=9, vol=volumes.S1V, color=volumes.S1C, duty=0, midi=0, semitone=0, octave=0, prev_semitone=0, float = {}, floaty = {}, floatz = {}},
			Square2  = {x=1+45*1, y=9, vol=volumes.S2V, color=volumes.S2C, duty=0, midi=0, semitone=0, octave=0, prev_semitone=0, float = {}, floaty = {}, floatz = {}},
			Triangle = {x=1+45*2, y=9, vol=volumes.TV, midi=0, semitone=0, octave=0, prev_semitone=0, float = {}, floaty = {}, floatz = {}},
			Noise    = {x=1+45*3, y=9, vol=volumes.NV, midi=0, semitone=0, octave=0},
			DPCM     = {x=1+45*4, y=9, vol=volumes.DPCMV}
		}
	end

	-- update the first indices for volume tables
	-- shift the previous ones farther
	table.insert(channels.Square1.vol,  1, snd.rp2a03.square1.volume*15)
	table.insert(channels.Square2.vol,  1, snd.rp2a03.square2.volume*15)
	table.insert(channels.Triangle.vol, 1, snd.rp2a03.triangle.volume*15)
	table.insert(channels.Noise.vol,    1, snd.rp2a03.noise.volume*15)
	table.insert(channels.DPCM.vol,     1, snd.rp2a03.dpcm.volume*15)

	-- get duty and midikey for proper channels
	channels.Square1.duty = snd.rp2a03.square1.duty
	channels.Square2.duty = snd.rp2a03.square2.duty
	
	channels.Square1.midi  = snd.rp2a03.square1.midikey
	channels.Square2.midi  = snd.rp2a03.square2.midikey
	channels.Triangle.midi = snd.rp2a03.triangle.midikey
	channels.Noise.midi    = snd.rp2a03.noise.midikey

	-- guess notes
	for name, chan in pairs(channels) do
		if name == "Square1" or name == "Square2" or name == "Triangle" or name == "Noise" then
			if chan.vol[1] > 0 then
				chan.octave = math.floor((chan.midi - 12) / 12)
				chan.semitone = tostring(semitones[math.floor((chan.midi - 21) % 12) + 1])
			else chan.semitone = "--"; chan.octave = "-"
			end
		end
	end
	
	-- notes display
	gui.text(kb.x+203, kb.y,    "S1: "..channels.Square1.semitone..channels.Square1.octave,   "#ff0000ff", "#000000ff")
	gui.text(kb.x+203, kb.y+9,  "S2: "..channels.Square2.semitone..channels.Square2.octave,   "#aa00ccff", "#000000ff")
	gui.text(kb.x+204, kb.y+18, "Tr: "..channels.Triangle.semitone..channels.Triangle.octave, "#00aaffff", "#000000ff")
	gui.text(kb.x+204, kb.y+27, "Ns: "..channels.Noise.semitone..channels.Noise.octave,       "#ffffffff", "#000000ff")

-----------------
-- Draw hi-hat --
-----------------

	xhh1 = 227
	yhh1 = 18
	xhh2 = 227
	yhh2 = 18
	
	if channels.Noise.vol[1] > 0 then 
		if channels.Noise.octave >= 9 and channels.Noise.octave <= 12 then
			colorhh = "#ffaa00"
			if channels.Noise.vol[2] - channels.Noise.vol[1] < 4
			and channels.Noise.vol[2] > 0
			then yhh1 = 15
			end
		end
	else colorhh = "#00000000"
	end

	gui.line(xhh1-1,  yhh1,   xhh1+28, yhh1,   "#00000088")
	gui.line(xhh1-1,  yhh1-1, xhh1+28, yhh1-1, "#00000088")
	gui.line(xhh1-1,  yhh1-2, xhh1+28, yhh1-2, "#00000088")
	gui.line(xhh1+3,  yhh1-3, xhh1+24, yhh1-3, "#00000088")
	gui.line(xhh1+8,  yhh1-4, xhh1+19, yhh1-4, "#00000088")
	gui.line(xhh1+11, yhh1-5, xhh1+16, yhh1-5, "#00000088")
	gui.line(xhh1+12, yhh1-6, xhh1+15, yhh1-6, "#00000088")	
	gui.line(xhh2-1,  yhh2,   xhh2+28, yhh2,   "#00000088")
	gui.line(xhh2-1,  yhh2+1, xhh2+28, yhh2+1, "#00000088")
	gui.line(xhh2-1,  yhh2+2, xhh2+28, yhh2+2, "#00000088")
	gui.line(xhh2+3,  yhh2+3, xhh2+24, yhh2+3, "#00000088")
	gui.line(xhh2+8,  yhh2+4, xhh2+19, yhh2+4, "#00000088")
	gui.line(xhh2+11, yhh2+5, xhh2+16, yhh2+5, "#00000088")
	gui.line(xhh2+12, yhh2+6, xhh2+15, yhh2+6, "#00000088")

	gui.line(xhh1,    yhh1-1, xhh1+27, yhh1-1, colorhh)
	gui.line(xhh1+4,  yhh1-2, xhh1+23, yhh1-2, colorhh)
	gui.line(xhh1+9,  yhh1-3, xhh1+18, yhh1-3, colorhh)
	gui.line(xhh1+12, yhh1-4, xhh1+15, yhh1-4, colorhh)
	gui.line(xhh1+13, yhh1-5, xhh1+14, yhh1-5, colorhh)	
	gui.line(xhh2,    yhh2+1, xhh2+27, yhh2+1, colorhh)
	gui.line(xhh2+4,  yhh2+2, xhh2+23, yhh2+2, colorhh)
	gui.line(xhh2+9,  yhh2+3, xhh2+18, yhh2+3, colorhh)
	gui.line(xhh2+12, yhh2+4, xhh2+15, yhh2+4, colorhh)
	gui.line(xhh2+13, yhh2+5, xhh2+14, yhh2+5, colorhh)
	
--------------------
-- Keyboard stuff --
--------------------

	if (kb.on) then
		-- capture leftclicks
		if keys.xmouse <= 256 and keys.xmouse >= 205 and keys.ymouse >= kb.y and keys.ymouse <= kb.y+27 then
			if keys["leftclick"] and not prev_keys["leftclick"] then kb.on = false end
		end		
		-- draw the kayboard
		gui.box(kb.x-8, kb.y, kb.x+200, kb.y+16, "#ffffffff") -- white solid box
		for a = -2, 49 do gui.box(kb.x+4*a, kb.y, kb.x+4*a, kb.y+16, "#00000000") end -- black lines
		-- draw colored boxes as clean notes
		for name, chan in pairs(channels) do
			if name == "Square1" or name == "Square2" or name == "Triangle" then
				if name == "Triangle" then color = "#00aaffff"
				elseif name == "Square1" then color = "#ff0000ff"
				else color = "#aa00ccff"
				end
				
				if     chan.semitone == "C" then gui.box(kb.x+1 +28*(chan.octave-1), kb.y, kb.x+3 +28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "D" then gui.box(kb.x+5 +28*(chan.octave-1), kb.y, kb.x+7 +28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "E" then gui.box(kb.x+9 +28*(chan.octave-1), kb.y, kb.x+11+28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "F" then gui.box(kb.x+13+28*(chan.octave-1), kb.y, kb.x+15+28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "G" then gui.box(kb.x+17+28*(chan.octave-1), kb.y, kb.x+19+28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "A" then gui.box(kb.x+21+28*(chan.octave-1), kb.y, kb.x+23+28*(chan.octave-1), kb.y+16, color)
				elseif chan.semitone == "B" then gui.box(kb.x+25+28*(chan.octave-1), kb.y, kb.x+27+28*(chan.octave-1), kb.y+16, color)
				end
			end
		end		
		-- draw accidental keys
		gui.box(kb.x-3, kb.y, kb.x-5, kb.y+10, "#00000000")		
		for oct = 0, 6 do
			gui.box(kb.x+3+28*oct,  kb.y, kb.x+5+28*oct,  kb.y+10, "#00000000")
			gui.box(kb.x+7+28*oct,  kb.y, kb.x+9+28*oct,  kb.y+10, "#00000000")
			gui.box(kb.x+15+28*oct, kb.y, kb.x+17+28*oct, kb.y+10, "#00000000")
			gui.box(kb.x+19+28*oct, kb.y, kb.x+21+28*oct, kb.y+10, "#00000000")
			gui.box(kb.x+23+28*oct, kb.y, kb.x+25+28*oct, kb.y+10, "#00000000")			
		end
		-- draw colored boxes over accidental keys
		for name, chan in pairs(channels) do			
			if name == "Square1" or name == "Square2" or name == "Triangle" then
				if name == "Triangle" then color = "#00aaffff"
				elseif name == "Square1" then color = "#ff0000ff"
				else color = "#aa00ccff"
				end
				
				if     chan.semitone == "C#" then gui.box(kb.x+3 +28*(chan.octave-1), kb.y, kb.x+5 +28*(chan.octave-1), kb.y+10, color)
				elseif chan.semitone == "D#" then gui.box(kb.x+7 +28*(chan.octave-1), kb.y, kb.x+9 +28*(chan.octave-1), kb.y+10, color)
				elseif chan.semitone == "F#" then gui.box(kb.x+15+28*(chan.octave-1), kb.y, kb.x+17+28*(chan.octave-1), kb.y+10, color)
				elseif chan.semitone == "G#" then gui.box(kb.x+19+28*(chan.octave-1), kb.y, kb.x+21+28*(chan.octave-1), kb.y+10, color)
				elseif chan.semitone == "A#" then gui.box(kb.x+23+28*(chan.octave-1), kb.y, kb.x+25+28*(chan.octave-1), kb.y+10, color)
				end
			end
		end
		
		grey = "#aaaaaaaa"	
		for oct = 0, 6 do					
			gui.line(kb.x+3+28*oct,  kb.y+10, kb.x+5+28*oct,  kb.y+10, grey)
			gui.line(kb.x+7+28*oct,  kb.y+10, kb.x+9+28*oct,  kb.y+10, grey)
			gui.line(kb.x+15+28*oct, kb.y+10, kb.x+17+28*oct, kb.y+10, grey)
			gui.line(kb.x+19+28*oct, kb.y+10, kb.x+21+28*oct, kb.y+10, grey)
			gui.line(kb.x+23+28*oct, kb.y+10, kb.x+25+28*oct, kb.y+10, grey)
		end
		gui.line(kb.x-3,   kb.y+10, kb.x-5,   kb.y+10, grey)
		gui.line(kb.x-8,   kb.y,    kb.x+200, kb.y,    "#00000088")
		gui.line(kb.x-8,   kb.y+16, kb.x+200, kb.y+16, "#00000088")
		gui.line(kb.x-8,   kb.y,    kb.x-8,   kb.y+16, "#00000088")
		gui.line(kb.x+200, kb.y,    kb.x+200, kb.y+16, "#00000088")
	else
		-- capture leftclicks
		if keys.xmouse <= 256 and keys.xmouse >= 205 and keys.ymouse >= kb.y and keys.ymouse <= kb.y+27 then
			if keys["leftclick"] and not prev_keys["leftclick"] then kb.on = true end
		end
	end

--------------------
-- Floating notes --
--------------------
	
	if (kb.on) then
		for name, chan in pairs(channels) do
			if name == "Square1" or name == "Square2" or name == "Triangle" then
			
				if chan.prev_semitone ~= chan.semitone then
					local len_prev = #chan.float
					if     chan.semitone == "C"  then table.insert(chan.float, 1, kb.x+1 +28*(chan.octave-1))
					elseif chan.semitone == "D"  then table.insert(chan.float, 1, kb.x+5 +28*(chan.octave-1))
					elseif chan.semitone == "E"  then table.insert(chan.float, 1, kb.x+9 +28*(chan.octave-1))
					elseif chan.semitone == "F"  then table.insert(chan.float, 1, kb.x+13+28*(chan.octave-1))
					elseif chan.semitone == "G"  then table.insert(chan.float, 1, kb.x+17+28*(chan.octave-1))
					elseif chan.semitone == "A"  then table.insert(chan.float, 1, kb.x+21+28*(chan.octave-1))
					elseif chan.semitone == "B"  then table.insert(chan.float, 1, kb.x+25+28*(chan.octave-1))
					elseif chan.semitone == "C#" then table.insert(chan.float, 1, kb.x+3 +28*(chan.octave-1))
					elseif chan.semitone == "D#" then table.insert(chan.float, 1, kb.x+7 +28*(chan.octave-1))
					elseif chan.semitone == "F#" then table.insert(chan.float, 1, kb.x+15+28*(chan.octave-1))
					elseif chan.semitone == "G#" then table.insert(chan.float, 1, kb.x+19+28*(chan.octave-1))
					elseif chan.semitone == "A#" then table.insert(chan.float, 1, kb.x+23+28*(chan.octave-1))
					end
					if len_prev ~= #chan.float then table.insert(chan.floaty, 1, 0) table.insert(chan.floatz, 1, 0) end
				elseif chan.semitone ~= '--' then
					chan.floaty[1] = 0
				end
				
				if name == "Triangle" then color = "#00aaffff"
				elseif name == "Square1" then color = "#ff0000ff"
				else color = "#aa00ccff"
				end
			
				for i = 1, #chan.float do
					local y = kb.y+chan.floaty[i]
					local z = kb.y+chan.floatz[i]
					chan.floaty[i] = chan.floaty[i] + 1
					chan.floatz[i] = chan.floatz[i] + 1
					if y+17<=z+15 then
						if movie.framecount()%2 == 0 then gui.box(chan.float[i]-1, y+16, chan.float[i]+3, z+16, "#eedd2200") end
						gui.box(chan.float[i], y+17, chan.float[i]+2, z+15, color)
					end
				end
				while #chan.float ~= 0 and chan.floaty[#chan.float] > 224 do
					table.remove(chan.float,  #chan.float)
					table.remove(chan.floaty, #chan.floaty)
					table.remove(chan.floatz, #chan.floatz)
				end
			end
		end
	end

---------------------
-- Volumes display --
---------------------

	for name, chan in pairs(channels) do
		if name == "Square1" or name == "Square2" then
			-- set color for each duty value
			if chan.duty == 0 then table.insert(chan.color,1,"#aaff00ff")
			elseif chan.duty == 1 then table.insert(chan.color,1,"#00ff00ff")
			elseif chan.duty == 2 then table.insert(chan.color,1,"#00bb00ff")
			else table.insert(chan.color,1,"#008800ff")
			end
		end
		-- capture leftclicks
		if iterator == 15 then
			if keys.ymouse <= 24 and keys.ymouse >= 0 then
				if keys["leftclick"] and not prev_keys["leftclick"] then iterator = 1 end
			end
		else
			if keys.ymouse <= 24 and keys.ymouse >= 0 then
				if keys["leftclick"] and not prev_keys["leftclick"] then iterator = 15 end
			end
		end
		-- draw volumes
		gui.text(chan.x, 9, name, "#ffffffff", "#000000ff")	
		if iterator <=14 then
			-- draw just first volume values
			gui.text(chan.x, chan.y+9+1, chan.vol[1])
			if tonumber(chan.vol[1]) > 0 then
				for j = 0, chan.vol[1]-1 do
					gui.box(chan.x+13+j*2, chan.y+9, chan.x+15+j*2, chan.y+8+9, "#000000ff")
					gui.line(chan.x+14+j*2, chan.y+1+9, chan.x+14+j*2, chan.y+7+9, "#00ff00ff")
					if name == "Square1" or name == "Square2" then
						-- color comes from duty
						gui.text(chan.x+38, chan.y, chan.duty, chan.color[1], "#000000ff")
						gui.line(chan.x+14+j*2, chan.y+1+9, chan.x+14+j*2, chan.y+7+9, chan.color[1])
					end
				end
			end
		else
			-- draw all 15 volume values
			for i = 1, #chan.vol do
				gui.text(chan.x, chan.y+i*9+1, chan.vol[i])
				if tonumber(chan.vol[i]) > 0 then
					for j = 0, chan.vol[i]-1 do
						gui.box(chan.x+13+j*2, chan.y+i*9, chan.x+15+j*2, chan.y+8+i*9, "#000000ff")
						gui.line(chan.x+14+j*2, chan.y+1+i*9, chan.x+14+j*2, chan.y+7+i*9, "#00ff00ff")
						if name == "Square1" or name == "Square2" then
							-- color comes from duty
							gui.text(chan.x+38, chan.y, chan.duty, chan.color[1], "#000000ff")
							gui.line(chan.x+14+j*2, chan.y+1+i*9, chan.x+14+j*2, chan.y+7+i*9, chan.color[i])
						end
					end
				end
			end
		end
		-- keep the table limited
		table.remove(chan.vol, 15)
		
		-- highlight the first values
		-- 30 Hz blinking, works properly if your monitor is set to 60 Hz
		if chan.vol[1] > 0 and movie.framecount()%2 == 0 then
			gui.box(chan.x+12, chan.y+8, chan.x+14+chan.vol[1]*2, chan.y+18, "#ffcc0000")
		end
	end	
	
	for name, chan in pairs(channels) do
		if name == "Square1" or name == "Square2" or name == "Triangle" then
			chan.prev_semitone = chan.semitone
		end
	end
	
	prev_keys = keys
end
emu.registerafter(Draw);