diff --git a/output/luaScripts/SoundDisplay.lua b/output/luaScripts/SoundDisplay.lua index 3cde7070..eb5854f7 100644 --- a/output/luaScripts/SoundDisplay.lua +++ b/output/luaScripts/SoundDisplay.lua @@ -5,52 +5,207 @@ -- * sound.get() --------------------------------------------------------------------------- -- Usage: --- The script allows you to observe raw data of 5 sound channels. +-- The script allows you to observe data of 5 sound channels. -- Analysing such info you can notice some regularities in how -- the data oscillates/changes when ingame music plays. -- Then you can write scripts similar to \taseditor\TrackNoise.lua -- to facilitate synchronous dances in TAS movies. --------------------------------------------------------------------------- +square1 = {x=1, y=8, on=true}; +square2 = {x=129, y=8, on=true}; +triangle = {x=1, y=67, on=true}; +noise = {x=129, y=67, on=true}; +dpcm = {x=1, y=118, on=true}; + +semitones = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"}; +duty_ratio = {"12.5%", "25%", "50%", "75%"}; +duty_color = {"purple", "magenta", "orange", "yellow"}; +key_color = {"#000000FF", "#202020FF", "#205050FF", "#008080FF", "#00C0C0FF", "#00FFFFFF", "#FFFFFFFF", "#FFFF00FF", "#FFFFFFFF", "#FFFF00FF", "#FFFFFFFF", "#FFFF00FF", "#FFFFFFFF", "#FFFF00FF", "#FFFFFFFF"}; +noise_color = {long="orange", short = "yellow"}; + +sample_names = { + -- Here you can specify custom names for DMC samples (to display name instead of just address) + -- For example, here are two samples for Contra(U) ROM + Sample_FC00 = {name="Kick", color="#C0C0C0FF"}, + Sample_FCC0 = {name="Snare", color="#80C0FFFF"}, +} + function everyframe() snd = sound.get(); - gui.text(0, 8, "Square 1:"); - gui.text(0, 16, snd.rp2a03.square1.volume); - gui.text(0, 24, snd.rp2a03.square1.frequency); - gui.text(0, 32, snd.rp2a03.square1.midikey); - gui.text(0, 40, snd.rp2a03.square1.duty); - gui.text(0, 48, snd.rp2a03.square1.regs.frequency); + if (square1.on) then + gui.text(square1.x, square1.y, "SQUARE 1:"); - gui.text(128, 8, "Square 2:"); - gui.text(128, 16, snd.rp2a03.square2.volume); - gui.text(128, 24, snd.rp2a03.square2.frequency); - gui.text(128, 32, snd.rp2a03.square2.midikey); - gui.text(128, 40, snd.rp2a03.square2.duty); - gui.text(128, 48, snd.rp2a03.square2.regs.frequency); + Volume = snd.rp2a03.square1.volume; + gui.text(square1.x, square1.y + 8, "Volume:"); + gui.box(square1.x + 32, square1.y + 7, square1.x + 32+15, square1.y + 15, "#006000FF", "black"); + gui.box(square1.x + 32, square1.y + 7, square1.x + 32 + Volume * 15, square1.y + 15, "green", "clear"); + gui.text(square1.x + 48, square1.y + 8, string.format("%g", Volume)); - gui.text(0, 64, "Triangle:"); - gui.text(0, 72, snd.rp2a03.triangle.volume); - gui.text(0, 80, snd.rp2a03.triangle.frequency); - gui.text(0, 88, snd.rp2a03.triangle.midikey); - gui.text(0, 96, snd.rp2a03.triangle.regs.frequency); + Frequency = snd.rp2a03.square1.frequency; + gui.text(square1.x, square1.y + 16, "Frequency: " .. string.format("%g", Frequency) .. "Hz"); - gui.text(128, 64, "Noise:"); - gui.text(128, 72, snd.rp2a03.noise.volume); - gui.text(128, 80, tostring(snd.rp2a03.noise.short)); - gui.text(128, 88, snd.rp2a03.noise.frequency); - gui.text(128, 96, snd.rp2a03.noise.midikey); - gui.text(128, 104, snd.rp2a03.noise.regs.frequency); + Midikey = snd.rp2a03.square1.midikey; + gui.box(square1.x-1, square1.y + 23, square1.x + 127, square1.y + 31, "#008080FF", "black") + gui.box(square1.x-1, square1.y + 23, square1.x-1 + Midikey, square1.y + 31, "#00C0C0FF", "black") + Keycolor = key_color[math.floor(Volume * 15) + 1]; + gui.box(square1.x-1 + Midikey-1, square1.y + 23, square1.x-1 + Midikey+1, square1.y + 31, "white", Keycolor) + Note = math.floor((Midikey - 21) % 12); + Octave = math.floor((Midikey - 12) / 12); + Semitone = tostring(semitones[Note + 1]) .. Octave; + gui.text(square1.x, square1.y + 32, "Note: " .. Semitone .. " "); + gui.text(square1.x + 50, square1.y + 32, "(" .. string.format("%g", Midikey) .. ")"); - gui.text(0, 120, "DPCM:"); - gui.text(0, 128, snd.rp2a03.dpcm.volume); - gui.text(0, 136, snd.rp2a03.dpcm.frequency); - gui.text(0, 144, snd.rp2a03.dpcm.midikey); - gui.text(0, 152, snd.rp2a03.dpcm.dmcaddress); - gui.text(0, 160, snd.rp2a03.dpcm.dmcsize); - gui.text(0, 168, tostring(snd.rp2a03.dpcm.dmcloop)); - gui.text(0, 176, snd.rp2a03.dpcm.dmcseed); - gui.text(0, 184, snd.rp2a03.dpcm.regs.frequency); + Period = snd.rp2a03.square1.regs.frequency; + IndicatorColor = "#" .. string.format("%x", Period % 256) .. "0000FF"; + gui.text(square1.x, square1.y + 40, "Period:"); + gui.box(square1.x + 31, square1.y + 39, square1.x + 39, square1.y + 47, IndicatorColor, "black"); + gui.text(square1.x + 40, square1.y + 40, string.format("%g", Period)); + + Duty = snd.rp2a03.square1.duty; + gui.text(square1.x, square1.y + 48, "Duty #" .. Duty .. " (" .. duty_ratio[Duty + 1] .. ")", duty_color[Duty + 1]); + end + + if (square2.on) then + gui.text(square2.x, square2.y, "SQUARE 2:"); + + Volume = snd.rp2a03.square2.volume; + gui.text(square2.x, square2.y + 8, "Volume:"); + gui.box(square2.x + 32, square2.y + 7, square2.x + 32+15, square2.y + 15, "#006000FF", "black"); + gui.box(square2.x + 32, square2.y + 7, square2.x + 32 + Volume * 15, square2.y + 15, "green", "clear"); + gui.text(square2.x + 48, square2.y + 8, string.format("%g", Volume)); + + Frequency = snd.rp2a03.square2.frequency; + gui.text(square2.x, square2.y + 16, "Frequency: " .. string.format("%g", Frequency) .. "Hz"); + + Midikey = snd.rp2a03.square2.midikey; + gui.box(square2.x-1, square2.y + 23, square2.x + 127, square2.y + 31, "#008080FF", "black") + gui.box(square2.x-1, square2.y + 23, square2.x-1 + Midikey, square2.y + 31, "#00C0C0FF", "black") + Keycolor = key_color[math.floor(Volume * 15) + 1]; + gui.box(square2.x-1 + Midikey-1, square2.y + 23, square2.x-1 + Midikey+1, square2.y + 31, "white", Keycolor) + Note = math.floor((Midikey - 21) % 12); + Octave = math.floor((Midikey - 12) / 12); + Semitone = tostring(semitones[Note + 1]) .. Octave; + gui.text(square2.x, square2.y + 32, "Note: " .. Semitone .. " "); + gui.text(square2.x + 50, square2.y + 32, "(" .. string.format("%g", Midikey) .. ")"); + + Period = snd.rp2a03.square2.regs.frequency; + IndicatorColor = "#" .. string.format("%x", Period % 256) .. "0000FF"; + gui.text(square2.x, square2.y + 40, "Period:"); + gui.box(square2.x + 31, square2.y + 39, square2.x + 39, square2.y + 47, IndicatorColor, "black"); + gui.text(square2.x + 40, square2.y + 40, string.format("%g", Period)); + + Duty = snd.rp2a03.square2.duty; + gui.text(square2.x, square2.y + 48, "Duty #" .. Duty .. " (" .. duty_ratio[Duty + 1] .. ")", duty_color[Duty + 1]); + end + + if (triangle.on) then + gui.text(triangle.x, triangle.y, "TRIANGLE:"); + + Volume = snd.rp2a03.triangle.volume; + gui.text(triangle.x, triangle.y + 8, "Volume:"); + gui.box(triangle.x + 32, triangle.y + 7, triangle.x + 32+15, triangle.y + 15, "#006000FF", "black"); + gui.box(triangle.x + 32, triangle.y + 7, triangle.x + 32 + Volume * 15, triangle.y + 15, "#00A000FF", "clear"); + gui.text(triangle.x + 48, triangle.y + 8, string.format("%g", Volume)); + + Frequency = snd.rp2a03.triangle.frequency; + gui.text(triangle.x, triangle.y + 16, "Frequency: " .. string.format("%g", Frequency) .. "Hz"); + + Midikey = snd.rp2a03.triangle.midikey; + gui.box(triangle.x-1, triangle.y + 23, triangle.x + 127, triangle.y + 31, "#008080FF", "black") + gui.box(triangle.x-1, triangle.y + 23, triangle.x-1 + Midikey, triangle.y + 31, "#00C0C0FF", "black") + if (Volume ~= 0) then gui.box(triangle.x-1 + Midikey-1, triangle.y + 23, triangle.x-1 + Midikey+1, triangle.y + 31, "white", "black") end; + Note = math.floor((Midikey - 21) % 12); + Octave = math.floor((Midikey - 12) / 12); + Semitone = tostring(semitones[Note + 1]) .. Octave; + gui.text(triangle.x, triangle.y + 32, "Note: " .. Semitone .. " "); + gui.text(triangle.x + 50, triangle.y + 32, "(" .. string.format("%g", Midikey) .. ")"); + + Period = snd.rp2a03.triangle.regs.frequency; + IndicatorColor = "#" .. string.format("%x", Period % 256) .. "0000FF"; + gui.text(triangle.x, triangle.y + 40, "Period:"); + gui.box(triangle.x + 31, triangle.y + 39, triangle.x + 39, triangle.y + 47, IndicatorColor, "black"); + gui.text(triangle.x + 40, triangle.y + 40, string.format("%g", Period)); + end + + if (noise.on) then + gui.text(noise.x, noise.y, "NOISE:"); + + Volume = snd.rp2a03.noise.volume; + gui.text(noise.x, noise.y + 8, "Volume:"); + gui.box(noise.x + 32, noise.y + 7, noise.x + 32+15, noise.y + 15, "#006000FF", "black"); + gui.box(noise.x + 32, noise.y + 7, noise.x + 32 + Volume * 15, noise.y + 15, "green", "clear"); + gui.text(noise.x + 48, noise.y + 8, string.format("%g", Volume)); + + Frequency = snd.rp2a03.noise.frequency; + gui.text(noise.x, noise.y + 16, "Frequency: " .. string.format("%g", Frequency) .. "Hz"); + + Midikey = snd.rp2a03.noise.midikey; + gui.box(noise.x-1, noise.y + 23, noise.x + 127, noise.y + 31, "#008080FF", "black") + gui.box(noise.x-1, noise.y + 23, noise.x-1 + (Midikey/2), noise.y + 31, "#00C0C0FF", "black") + Keycolor = key_color[math.floor(Volume * 15) + 1]; + gui.box(noise.x-1 + (Midikey/2)-1, noise.y + 23, noise.x-1 + (Midikey/2)+1, noise.y + 31, "white", Keycolor) + Note = math.floor((Midikey - 21) % 12); + Octave = math.floor((Midikey - 12) / 12); + Semitone = tostring(semitones[Note + 1]) .. Octave; + gui.text(noise.x, noise.y + 32, "Note: " .. Semitone .. " "); + gui.text(noise.x + 58, noise.y + 32, "(" .. string.format("%g", Midikey) .. ")"); + + Period = snd.rp2a03.noise.regs.frequency; + IndicatorColor = "#" .. string.format("%X", Period % 256) .. "0000FF"; + gui.text(noise.x, noise.y + 40, "Period:"); + gui.box(noise.x + 31, noise.y + 39, noise.x + 39, noise.y + 47, IndicatorColor, "black"); + gui.text(noise.x + 40, noise.y + 40, string.format("%g", Period)); + + if (snd.rp2a03.noise.short) then + gui.text(noise.x, noise.y + 48, "Mode: short", noise_color.short); + else + gui.text(noise.x, noise.y + 48, "Mode: long", noise_color.long); + end + end + + if (dpcm.on) then + gui.text(dpcm.x, dpcm.y, "DPCM:"); + + Volume = snd.rp2a03.dpcm.volume; + gui.text(dpcm.x, dpcm.y + 8, "Volume:"); + gui.box(dpcm.x + 32, dpcm.y + 7, dpcm.x + 32+15, dpcm.y + 15, "#006000FF", "black"); + gui.box(dpcm.x + 32, dpcm.y + 7, dpcm.x + 32 + Volume * 15, dpcm.y + 15, "#00A000FF", "clear"); + gui.text(dpcm.x + 48, dpcm.y + 8, string.format("%g", Volume)); + + Frequency = snd.rp2a03.dpcm.frequency; + gui.text(dpcm.x, dpcm.y + 16, "Frequency: " .. string.format("%g", Frequency) .. "Hz"); + + Midikey = snd.rp2a03.dpcm.midikey; + gui.box(dpcm.x-1, dpcm.y + 23, dpcm.x + 127, dpcm.y + 31, "#008080FF", "black") + gui.box(dpcm.x-1, dpcm.y + 23, dpcm.x-1 + (Midikey/2), dpcm.y + 31, "#00C0C0FF", "black") + if (Volume ~= 0) then gui.box(dpcm.x-1 + (Midikey/2)-1, dpcm.y + 23, dpcm.x-1 + (Midikey/2)+1, dpcm.y + 31, "white", "black") end; + Note = math.floor((Midikey - 21) % 12); + Octave = math.floor((Midikey - 12) / 12); + Semitone = tostring(semitones[Note + 1]) .. Octave; + gui.text(dpcm.x, dpcm.y + 32, "Note: " .. Semitone .. " "); + gui.text(dpcm.x + 50, dpcm.y + 32, "(" .. string.format("%g", Midikey) .. ")"); + + Period = snd.rp2a03.dpcm.regs.frequency; + IndicatorColor = "#" .. string.format("%x", Period % 256) .. "0000FF"; + gui.text(dpcm.x, dpcm.y + 40, "Period:"); + gui.box(dpcm.x + 31, dpcm.y + 39, dpcm.x + 39, dpcm.y + 47, IndicatorColor, "black"); + gui.text(dpcm.x + 40, dpcm.y + 40, string.format("%g", Period)); + + if (snd.rp2a03.dpcm.dmcloop) then + gui.text(dpcm.x, dpcm.y + 48, "Sample: $" .. string.format("%X", snd.rp2a03.dpcm.dmcaddress) .. " (" .. snd.rp2a03.dpcm.dmcsize .. " bytes looped)", "orange"); + else + gui.text(dpcm.x, dpcm.y + 48, "Sample: $" .. string.format("%X", snd.rp2a03.dpcm.dmcaddress) .. " (" .. snd.rp2a03.dpcm.dmcsize .. " bytes)"); + end + + Sample_id = "Sample_" .. string.format("%X", snd.rp2a03.dpcm.dmcaddress); + if (sample_names[Sample_id] ~= nil) then + gui.text(dpcm.x + 170, dpcm.y + 48, sample_names[Sample_id].name, sample_names[Sample_id].color); + end + + gui.text(dpcm.x, dpcm.y + 56, "DMC seed: " .. string.format("%X", snd.rp2a03.dpcm.dmcseed)); + end end emu.registerafter(everyframe);