mirror of
https://github.com/libretro/MesenCE.git
synced 2026-11-10 11:11:32 -10:00
1503 lines
49 KiB
Lua
1503 lines
49 KiB
Lua
-----------------------
|
|
-- Name: Piano Roll (NES)
|
|
-- Author: zeta0134
|
|
-- Based on: https://github.com/zeta0134/mesen-piano-roll
|
|
-----------------------
|
|
|
|
local consoleType = emu.getState()["consoleType"]
|
|
if consoleType ~= "Nes" then
|
|
emu.displayMessage("Script", "This script only works on the NES.")
|
|
return
|
|
end
|
|
|
|
local NTSC_CPU_FREQUENCY = 1.789773 * 1024.0 * 1024.0
|
|
local LOWEST_NOTE_FREQ = 55.0 -- ~A0
|
|
local HIGHEST_NOTE_FREQ = 4434.922 -- ~C#8
|
|
local PIANO_ROLL_WIDTH = 240
|
|
local PIANO_ROLL_KEYS = 76
|
|
local PIANO_ROLL_KEY_HEIGHT = 2
|
|
local PIANO_ROLL_HEIGHT = PIANO_ROLL_KEYS * PIANO_ROLL_KEY_HEIGHT
|
|
local NOISE_KEY_HEIGHT = 2
|
|
local NOISE_ROLL_HEIGHT = NOISE_KEY_HEIGHT * 16
|
|
local NOISE_ROLL_OFFSET = 200
|
|
local SQUARE1_COLORS = {0xFFA0A0, 0xFF40FF, 0xFF4040}
|
|
SQUARE1_COLORS[4] = SQUARE1_COLORS[2]
|
|
local SQUARE2_COLORS = {0xFFE0A0, 0xFFC040, 0xFFFF40}
|
|
SQUARE2_COLORS[4] = SQUARE2_COLORS[2]
|
|
local TRIANGLE_COLORS = {0x40FF40}
|
|
local NOISE_COLORS = {0x4040FF, 0x40FFFF}
|
|
local DMC_BASE_COLOR = 0x806040A0
|
|
local DMC_PLAYING_COLOR = 0x8040C0
|
|
local DMC_OFFSET = 178
|
|
local DMC_HEIGHT = 19
|
|
local BACKGROUND_COLOR = 0x80000000
|
|
local PIANO_STRING_BLACK_COLOR = 0x80101010
|
|
local PIANO_STRING_WHITE_COLOR = 0x80060606
|
|
local NOISE_STRING_BLACK_COLOR = 0x80060606
|
|
local NOISE_STRING_WHITE_COLOR = 0x800A0A0A
|
|
|
|
local settings = {
|
|
background="solid"
|
|
}
|
|
|
|
local shadow_apu = {}
|
|
for address = 0x4000, 0x4017 do
|
|
shadow_apu[address] = 0
|
|
end
|
|
|
|
local shadow_triangle = {}
|
|
shadow_triangle.lc_reload = false
|
|
shadow_triangle.lc_value = 0
|
|
|
|
function clock_linear_counter()
|
|
if shadow_triangle.lc_reload then
|
|
shadow_triangle.lc_value = shadow_apu[0x4008] & 0x7F
|
|
else
|
|
if shadow_triangle.lc_value > 0 then
|
|
shadow_triangle.lc_value = shadow_triangle.lc_value - 1
|
|
end
|
|
end
|
|
if shadow_apu[0x4008] & 0x80 == 0 then
|
|
shadow_triangle.lc_reload = false
|
|
end
|
|
end
|
|
|
|
function clock_shadow_frame_sequencer()
|
|
clock_linear_counter()
|
|
clock_linear_counter()
|
|
clock_linear_counter()
|
|
clock_linear_counter()
|
|
end
|
|
|
|
function apu_register_write(address, value)
|
|
shadow_apu[address] = value
|
|
if address == 0x400B then
|
|
shadow_triangle.lc_reload = true
|
|
end
|
|
end
|
|
|
|
emu.addEventCallback(clock_shadow_frame_sequencer, emu.eventType.endFrame)
|
|
emu.addMemoryCallback(apu_register_write, emu.callbackType.write, 0x4000 , 0x4017)
|
|
|
|
function set_background()
|
|
if settings.background == "solid" then
|
|
BACKGROUND_COLOR = 0x000000
|
|
PIANO_STRING_BLACK_COLOR = 0x101010
|
|
PIANO_STRING_WHITE_COLOR = 0x060606
|
|
NOISE_STRING_BLACK_COLOR = 0x060606
|
|
NOISE_STRING_WHITE_COLOR = 0x0A0A0A
|
|
DMC_BASE_COLOR = 0x006040A0
|
|
end
|
|
if settings.background == "transparent" then
|
|
BACKGROUND_COLOR = 0x80000000
|
|
PIANO_STRING_BLACK_COLOR = 0x80101010
|
|
PIANO_STRING_WHITE_COLOR = 0x80060606
|
|
NOISE_STRING_BLACK_COLOR = 0x80060606
|
|
NOISE_STRING_WHITE_COLOR = 0x800A0A0A
|
|
DMC_BASE_COLOR = 0x806040A0
|
|
end
|
|
if settings.background == "clear" then
|
|
BACKGROUND_COLOR = 0xFF000000
|
|
PIANO_STRING_BLACK_COLOR = 0xFF000000
|
|
PIANO_STRING_WHITE_COLOR = 0xFF000000
|
|
NOISE_STRING_BLACK_COLOR = 0xFF060606
|
|
NOISE_STRING_WHITE_COLOR = 0xFF0A0A0A
|
|
DMC_BASE_COLOR = 0x806040A0
|
|
end
|
|
end
|
|
-- call this once to initialize
|
|
set_background()
|
|
|
|
function toggle_background()
|
|
if settings.background == "clear" then
|
|
settings.background = "transparent"
|
|
elseif settings.background == "transparent" then
|
|
settings.background = "solid"
|
|
elseif settings.background == "solid" then
|
|
settings.background = "clear"
|
|
end
|
|
set_background()
|
|
end
|
|
|
|
function tiny_a(x, y, color)
|
|
emu.drawLine(x,y+1,x, y+4, color)
|
|
emu.drawLine(x+2,y+1,x+2, y+4, color)
|
|
emu.drawPixel(x+1,y,color)
|
|
emu.drawPixel(x+1,y+2,color)
|
|
end
|
|
|
|
function tiny_b(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
emu.drawPixel(x+2, y+1, color)
|
|
emu.drawPixel(x+2, y+3, color)
|
|
end
|
|
|
|
function tiny_c(x, y, color)
|
|
emu.drawLine(x, y+1, x, y+3, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_d(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
emu.drawLine(x+2, y+1, x+2, y+3,color)
|
|
end
|
|
|
|
function tiny_e(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_f(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
end
|
|
|
|
function tiny_g(x, y, color)
|
|
emu.drawLine(x, y+1, x, y+3, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
emu.drawLine(x+2, y+2, x+2, y+3, color)
|
|
end
|
|
|
|
function tiny_h(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
end
|
|
|
|
function tiny_i(x, y, color)
|
|
emu.drawLine(x, y, x+2, y, color)
|
|
emu.drawLine(x, y+4, x+2, y+4, color)
|
|
emu.drawLine(x+1, y+1, x+1, y+3, color)
|
|
end
|
|
|
|
function tiny_j(x, y, color)
|
|
emu.drawLine(x, y, x+2, y, color)
|
|
emu.drawLine(x+2, y+1, x+2, y+3, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
emu.drawPixel(x, y+3, color)
|
|
end
|
|
|
|
function tiny_k(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawLine(x+2, y, x+2, y+1, color)
|
|
emu.drawLine(x+2, y+3, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_l(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_m(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y+1, x+1, y+2, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_n(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawLine(x+2, y+1, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_o(x, y, color)
|
|
emu.drawLine(x, y+1, x, y+3, color)
|
|
emu.drawLine(x+2, y+1, x+2, y+3, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_p(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+2, y+1, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
end
|
|
|
|
function tiny_q(x, y, color)
|
|
emu.drawLine(x, y+1, x, y+3, color)
|
|
emu.drawLine(x+2, y+1, x+2, y+3, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+3, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_r(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+2, y+1, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawLine(x+2, y+3, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_s(x, y, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawPixel(x, y+1, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+2, y+3, color)
|
|
emu.drawLine(x, y+4, x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_t(x, y, color)
|
|
emu.drawLine(x, y, x+2, y, color)
|
|
emu.drawLine(x+1, y+1, x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_u(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_v(x, y, color)
|
|
emu.drawLine(x, y, x, y+3, color)
|
|
emu.drawLine(x+2, y, x+2, y+3, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_w(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y+2, x+1, y+3, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_x(x, y, color)
|
|
emu.drawLine(x, y, x, y+1, color)
|
|
emu.drawLine(x+2, y, x+2, y+1, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawLine(x, y+3, x, y+4, color)
|
|
emu.drawLine(x+2, y+3, x+2, y+4, color)
|
|
end
|
|
|
|
function tiny_y(x, y, color)
|
|
emu.drawLine(x, y, x, y+2, color)
|
|
emu.drawLine(x+2, y, x+2, y+2, color)
|
|
emu.drawLine(x+1, y+2, x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_z(x, y, color)
|
|
emu.drawLine(x, y, x+2, y, color)
|
|
emu.drawLine(x+2,y+1,x,y+3, color)
|
|
emu.drawLine(x,y+4,x+2,y+4, color)
|
|
end
|
|
|
|
function tiny_0(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_1(x, y, color)
|
|
emu.drawLine(x+1, y, x+1, y+4, color)
|
|
emu.drawLine(x, y+4, x+2, y+4, color)
|
|
emu.drawPixel(x, y+1,color)
|
|
end
|
|
|
|
function tiny_2(x, y, color)
|
|
emu.drawLine(x, y, x+1, y, color)
|
|
emu.drawLine(x+2,y+1,x,y+3, color)
|
|
emu.drawLine(x,y+4,x+2,y+4, color)
|
|
end
|
|
|
|
function tiny_3(x, y, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawLine(x, y, x+1, y, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawLine(x, y+4, x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_4(x, y, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawLine(x, y, x, y+2, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
end
|
|
|
|
function tiny_5(x, y, color)
|
|
emu.drawLine(x, y, x+2, y, color)
|
|
emu.drawLine(x, y+1, x, y+2, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+2, y+3, color)
|
|
emu.drawLine(x,y+4,x+1,y+4, color)
|
|
end
|
|
|
|
function tiny_6(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+1, y, x+2, y, color)
|
|
emu.drawLine(x+1, y+2, x+2, y+2, color)
|
|
emu.drawLine(x+1, y+4, x+2, y+4, color)
|
|
emu.drawPixel(x+2, y+3, color)
|
|
end
|
|
|
|
function tiny_7(x, y, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawLine(x, y, x+1, y, color)
|
|
end
|
|
|
|
function tiny_8(x, y, color)
|
|
emu.drawLine(x, y, x, y+4, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+1, y+4, color)
|
|
end
|
|
|
|
function tiny_9(x, y, color)
|
|
emu.drawLine(x+2, y, x+2, y+4, color)
|
|
emu.drawLine(x, y, x+1, y, color)
|
|
emu.drawLine(x, y+2, x+1, y+2, color)
|
|
emu.drawLine(x, y+4, x+1, y+4, color)
|
|
emu.drawPixel(x, y+1, color)
|
|
end
|
|
|
|
function tiny_hex_char(x, y, value, color)
|
|
local hex_functions = {
|
|
tiny_0, tiny_1, tiny_2, tiny_3, tiny_4, tiny_5, tiny_6, tiny_7,
|
|
tiny_8, tiny_9, tiny_a, tiny_b, tiny_c, tiny_d, tiny_e, tiny_f}
|
|
if hex_functions[value+1] then
|
|
hex_functions[value+1](x,y,color)
|
|
end
|
|
end
|
|
|
|
function tiny_hex(x, y, value, color, width)
|
|
while width > 0 do
|
|
width = width - 1
|
|
tiny_hex_char(x + width * 4, y, value & 0xF, color)
|
|
value = value >> 4
|
|
end
|
|
end
|
|
|
|
local char_functions = {
|
|
tiny_a, tiny_b, tiny_c, tiny_d, tiny_e, tiny_f,
|
|
tiny_g, tiny_h, tiny_i, tiny_j, tiny_k, tiny_l,
|
|
tiny_m, tiny_n, tiny_o, tiny_p, tiny_q, tiny_r,
|
|
tiny_s, tiny_t, tiny_u, tiny_v, tiny_w, tiny_x,
|
|
tiny_y, tiny_z
|
|
}
|
|
|
|
local num_functions = {
|
|
tiny_0, tiny_1, tiny_2, tiny_3, tiny_4,
|
|
tiny_5, tiny_6, tiny_7, tiny_8, tiny_9
|
|
}
|
|
|
|
function tiny_char(x, y, character_code, color)
|
|
if character_code >= string.byte("a", 1) and character_code <= string.byte("z") then
|
|
char_functions[character_code - string.byte("a") + 1](x, y, color)
|
|
end
|
|
if character_code >= string.byte("A", 1) and character_code <= string.byte("Z") then
|
|
char_functions[character_code - string.byte("A") + 1](x, y, color)
|
|
end
|
|
if character_code >= string.byte("0", 1) and character_code <= string.byte("9") then
|
|
num_functions[character_code - string.byte("0") + 1](x, y, color)
|
|
end
|
|
end
|
|
|
|
function tiny_string(x, y, str, color)
|
|
for i = 1, #str do
|
|
tiny_char(x + ((i-1) * 4), y, string.byte(str, i), color)
|
|
end
|
|
end
|
|
|
|
function frequency_to_coordinate(note_frequency, lowest_freq, highest_freq, viewport_height)
|
|
local highest_log = math.log(highest_freq)
|
|
local lowest_log = math.log(lowest_freq)
|
|
local range = highest_log - lowest_log
|
|
local note_log = math.log(note_frequency)
|
|
|
|
local coordinate = (note_log - lowest_log) * viewport_height / range
|
|
if coordinate >= 0 and coordinate < viewport_height then
|
|
return coordinate
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
function pulse_frequency(pulse_period)
|
|
return NTSC_CPU_FREQUENCY / (16.0 * (pulse_period + 1.0))
|
|
end
|
|
|
|
function triangle_frequency(triangle_period)
|
|
return NTSC_CPU_FREQUENCY / (32.0 * (triangle_period + 1.0))
|
|
end
|
|
|
|
function unpack_argb(color)
|
|
return ((color & 0xFF000000) >> 24), ((color & 0xFF0000) >> 16), ((color & 0xFF00) >> 8), (color & 0xFF)
|
|
end
|
|
|
|
function pack_argb(a, r, g, b)
|
|
return (a << 24) | (r << 16) | (g << 8) | (b)
|
|
end
|
|
|
|
function apply_brightness(color, brightness)
|
|
local a, r, g, b = unpack_argb(color)
|
|
r = math.floor(r * brightness)
|
|
g = math.floor(g * brightness)
|
|
b = math.floor(b * brightness)
|
|
return pack_argb(a, r, g, b)
|
|
end
|
|
|
|
function apply_transparency(color, alpha)
|
|
local a, r, g, b = unpack_argb(color)
|
|
a = math.floor(0xFF * (1.0 - alpha))
|
|
return pack_argb(a, r, g, b)
|
|
end
|
|
|
|
local square1_roll = {}
|
|
local square2_roll = {}
|
|
local triangle_roll = {}
|
|
local noise_roll = {}
|
|
local dmc_roll = {}
|
|
|
|
function initialize_piano_roll()
|
|
for i = 1, PIANO_ROLL_WIDTH - 1 do
|
|
local channel_state = {}
|
|
-- this is enough for pulse, triangle, and noise
|
|
channel_state.enabled = false
|
|
-- dmc calculates a delta, so it needs full dummy samples
|
|
channel_state.playing = false
|
|
channel_state.delta = 0
|
|
|
|
table.insert(square1_roll, channel_state)
|
|
table.insert(square2_roll, channel_state)
|
|
table.insert(triangle_roll, channel_state)
|
|
table.insert(noise_roll, channel_state)
|
|
table.insert(dmc_roll, channel_state)
|
|
end
|
|
end
|
|
|
|
initialize_piano_roll()
|
|
|
|
function update_piano_roll(channel, state_table)
|
|
local channel_state = {}
|
|
local coordinate = frequency_to_coordinate(channel.frequency, LOWEST_NOTE_FREQ, HIGHEST_NOTE_FREQ, PIANO_ROLL_HEIGHT)
|
|
if coordinate then
|
|
channel_state.y = PIANO_ROLL_HEIGHT - coordinate
|
|
end
|
|
if channel.envelope then
|
|
-- pulse channels
|
|
channel_state.volume = channel.envelope.volume
|
|
channel_state.enabled = channel.envelope.volume ~= 0 and channel.lengthCounter.counter > 0
|
|
channel_state.duty = channel.duty
|
|
else
|
|
-- triangle channels
|
|
channel_state.volume = 6
|
|
channel_state.enabled =
|
|
channel.lengthCounter.counter > 0 and
|
|
shadow_triangle.lc_value > 0 and
|
|
channel.period > 2 and
|
|
channel.enabled
|
|
channel_state.duty = 0
|
|
end
|
|
|
|
table.insert(state_table, channel_state)
|
|
if #state_table > PIANO_ROLL_WIDTH then
|
|
table.remove(state_table, 1)
|
|
end
|
|
end
|
|
|
|
local noise_period_table = {}
|
|
noise_period_table[4] = 0
|
|
noise_period_table[8] = 1
|
|
noise_period_table[16] = 2
|
|
noise_period_table[32] = 3
|
|
noise_period_table[64] = 4
|
|
noise_period_table[96] = 5
|
|
noise_period_table[128] = 6
|
|
noise_period_table[160] = 7
|
|
noise_period_table[202] = 8
|
|
noise_period_table[254] = 9
|
|
noise_period_table[380] = 10
|
|
noise_period_table[508] = 11
|
|
noise_period_table[762] = 12
|
|
noise_period_table[1016] = 13
|
|
noise_period_table[2034] = 14
|
|
noise_period_table[4068] = 15
|
|
|
|
function debug_table_keys(name, t)
|
|
local keys = {}
|
|
for k,v in pairs(t) do
|
|
keys[#keys+1] = k
|
|
end
|
|
emu.log(name..": "..table.concat(keys, ","))
|
|
end
|
|
|
|
function update_noise_roll(channel, state_table)
|
|
local channel_state = {}
|
|
if noise_period_table[channel.period + 1] then
|
|
channel_state.y = noise_period_table[channel.period + 1] * NOISE_KEY_HEIGHT
|
|
channel_state.period = noise_period_table[channel.period + 1]
|
|
channel_state.mode = channel.modeFlag
|
|
end
|
|
if channel.envelope.constantVolume then
|
|
channel_state.volume = channel.envelope.volume
|
|
else
|
|
channel_state.volume = channel.envelope.counter
|
|
end
|
|
channel_state.enabled = channel_state.volume ~= 0 and channel.lengthCounter.counter > 0
|
|
|
|
table.insert(state_table, channel_state)
|
|
if #state_table > PIANO_ROLL_WIDTH then
|
|
table.remove(state_table, 1)
|
|
end
|
|
end
|
|
|
|
local old_dmc_level = 0
|
|
|
|
local dmc_period_table = {}
|
|
dmc_period_table[428] = 0
|
|
dmc_period_table[380] = 1
|
|
dmc_period_table[340] = 2
|
|
dmc_period_table[320] = 3
|
|
dmc_period_table[286] = 4
|
|
dmc_period_table[254] = 5
|
|
dmc_period_table[226] = 6
|
|
dmc_period_table[214] = 7
|
|
dmc_period_table[190] = 8
|
|
dmc_period_table[160] = 9
|
|
dmc_period_table[142] = 10
|
|
dmc_period_table[128] = 11
|
|
dmc_period_table[106] = 12
|
|
dmc_period_table[84] = 13
|
|
dmc_period_table[72] = 14
|
|
dmc_period_table[54] = 15
|
|
|
|
function update_dmc_roll(channel, state_table)
|
|
local channel_state = {}
|
|
local dmc_playing = channel.bytesRemaining > 0
|
|
local delta = math.abs(channel.outputVolume - old_dmc_level)
|
|
channel_state.playing = dmc_playing
|
|
channel_state.delta = delta
|
|
channel_state.address = channel.sampleAddr
|
|
|
|
if dmc_period_table[channel.period + 1] then
|
|
channel_state.rate = dmc_period_table[channel.period + 1]
|
|
end
|
|
table.insert(state_table, channel_state)
|
|
if #state_table > PIANO_ROLL_WIDTH then
|
|
table.remove(state_table, 1)
|
|
end
|
|
old_dmc_level = channel.outputVolume
|
|
end
|
|
|
|
function draw_piano_roll(emu, state_table, duty_colors)
|
|
for x = 1, #state_table do
|
|
if state_table[x].enabled and state_table[x].y then
|
|
local volume = state_table[x].volume
|
|
local y = state_table[x].y - 2
|
|
local foreground = duty_colors[state_table[x].duty + 1]
|
|
-- outer lines, drawn at brightness dependant on volume
|
|
local outermost_volume = math.max(0, volume - 8) / 8
|
|
local outermost_brightness = math.min(1.0, outermost_volume)
|
|
emu.drawLine(x - 1, y-2, x - 1, y+2, apply_transparency(foreground, outermost_brightness))
|
|
local innermost_volume = volume / 8
|
|
local innermost_brightness = math.min(1.0, innermost_volume)
|
|
emu.drawLine(x - 1, y-1, x - 1, y+1, apply_transparency(foreground, innermost_brightness))
|
|
-- center line, always drawn at full brightness when playing
|
|
emu.drawPixel(x - 1, y, foreground)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_noise_roll(emu, state_table, duty_colors)
|
|
for x = 1, #state_table do
|
|
if state_table[x].enabled and state_table[x].y then
|
|
local volume = state_table[x].volume
|
|
local y = state_table[x].y
|
|
local foreground = duty_colors[1]
|
|
if state_table[x].mode then
|
|
foreground = duty_colors[2]
|
|
end
|
|
-- outer lines, drawn at brightness dependant on volume
|
|
local outermost_volume = math.max(0, volume - 8) / 8
|
|
local outermost_brightness = math.min(1.0, outermost_volume)
|
|
emu.drawLine(x - 1, NOISE_ROLL_OFFSET + y-2, x - 1, NOISE_ROLL_OFFSET + y+2, apply_transparency(foreground, outermost_brightness))
|
|
local innermost_volume = volume / 8
|
|
local innermost_brightness = math.min(1.0, innermost_volume)
|
|
emu.drawLine(x - 1, NOISE_ROLL_OFFSET + y-1, x - 1, NOISE_ROLL_OFFSET + y+1, apply_transparency(foreground, innermost_brightness))
|
|
-- center line, always drawn at full brightness when playing
|
|
emu.drawPixel(x - 1, NOISE_ROLL_OFFSET + y, foreground)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_piano_background()
|
|
emu.drawRectangle(0, 0, 256, 240, BACKGROUND_COLOR, true)
|
|
end
|
|
|
|
function draw_piano_strings()
|
|
local black_string = PIANO_STRING_BLACK_COLOR
|
|
local white_string = PIANO_STRING_WHITE_COLOR
|
|
local string_colors = {
|
|
white_string, --C
|
|
white_string, --B
|
|
black_string, --Bb
|
|
white_string, --A
|
|
black_string, --Ab
|
|
white_string, --G
|
|
black_string, --Gb
|
|
white_string, --F
|
|
white_string, --E
|
|
black_string, --Eb
|
|
white_string, --D
|
|
black_string, --Db
|
|
}
|
|
|
|
for i = 0, PIANO_ROLL_KEYS do
|
|
local string_color = string_colors[i%12 + 1]
|
|
local y = i*PIANO_ROLL_KEY_HEIGHT
|
|
emu.drawLine(0, y, PIANO_ROLL_WIDTH, y, string_color)
|
|
end
|
|
end
|
|
|
|
function draw_noise_strings()
|
|
local noise_string_colors = {
|
|
NOISE_STRING_BLACK_COLOR,
|
|
NOISE_STRING_WHITE_COLOR
|
|
}
|
|
for i = 0, 15 do
|
|
local y = i * NOISE_KEY_HEIGHT
|
|
emu.drawLine(0, NOISE_ROLL_OFFSET + y, PIANO_ROLL_WIDTH, NOISE_ROLL_OFFSET + y, noise_string_colors[(i%2)+1])
|
|
end
|
|
end
|
|
|
|
local white_key_border = 0x404040
|
|
local white_key = 0x505050
|
|
local black_key = 0x000000
|
|
local black_key_border = 0x181818
|
|
local upper_key_pixels = {
|
|
white_key, -- C
|
|
white_key_border,
|
|
white_key, -- B
|
|
black_key, black_key, black_key, -- Bb
|
|
white_key, -- A
|
|
black_key, black_key, black_key, -- Ab
|
|
white_key, -- G
|
|
black_key, black_key, black_key, -- Gb
|
|
white_key, -- F
|
|
white_key_border,
|
|
white_key, -- E
|
|
black_key, black_key, black_key, -- Eb
|
|
white_key, -- D
|
|
black_key, black_key, black_key, -- Db
|
|
}
|
|
|
|
local lower_key_pixels = {
|
|
white_key, -- C (bottom half)
|
|
white_key_border,
|
|
white_key, white_key, -- B
|
|
white_key_border,
|
|
white_key, white_key, white_key, -- A
|
|
white_key_border,
|
|
white_key, white_key, white_key, -- G
|
|
white_key_border,
|
|
white_key, white_key, -- F
|
|
white_key_border,
|
|
white_key, white_key, -- E
|
|
white_key_border,
|
|
white_key, white_key, white_key, -- D
|
|
white_key_border,
|
|
white_key, -- C (top half)
|
|
}
|
|
|
|
function draw_piano_keys()
|
|
-- first, draw the keys themselves
|
|
for y = 0, PIANO_ROLL_KEYS * PIANO_ROLL_KEY_HEIGHT do
|
|
local upper_key_color = upper_key_pixels[y % #upper_key_pixels + 1]
|
|
local lower_key_color = lower_key_pixels[y % #lower_key_pixels + 1]
|
|
emu.drawLine(240, y, 248, y, upper_key_color)
|
|
emu.drawLine(248, y, 256, y, lower_key_color)
|
|
end
|
|
|
|
-- now clean up the border between the key and the piano roll
|
|
emu.drawLine(240, 0, 240, PIANO_ROLL_HEIGHT, black_key_border)
|
|
end
|
|
|
|
function draw_right_white_key(y, color)
|
|
emu.drawLine(248, y + 1, 256, y + 1, color)
|
|
emu.drawLine(240, y, 256, y, color)
|
|
end
|
|
|
|
function draw_center_white_key(y, color)
|
|
emu.drawLine(248, y - 1, 256, y - 1, color)
|
|
emu.drawLine(240, y, 256, y, color)
|
|
emu.drawLine(248, y + 1, 256, y + 1, color)
|
|
end
|
|
|
|
function draw_left_white_key(y, color)
|
|
emu.drawLine(240, y, 256, y, color)
|
|
emu.drawLine(248, y - 1, 256, y - 1, color)
|
|
end
|
|
|
|
function draw_black_key(y, color)
|
|
emu.drawLine(241, y - 1, 247, y - 1, color)
|
|
emu.drawLine(241, y, 247, y, color)
|
|
emu.drawLine(241, y + 1, 247, y + 1, color)
|
|
end
|
|
|
|
function draw_key_spot(note, duty_colors)
|
|
if (note.y == nil or note.enabled == false) then
|
|
return
|
|
end
|
|
local key_drawing_functions = {
|
|
draw_left_white_key, --C
|
|
draw_right_white_key, --B
|
|
draw_black_key, --Bb
|
|
draw_center_white_key,--A
|
|
draw_black_key, --Ab
|
|
draw_center_white_key,--G
|
|
draw_black_key, --Gb
|
|
draw_left_white_key, --F
|
|
draw_right_white_key, --E
|
|
draw_black_key, --Eb
|
|
draw_center_white_key,--D
|
|
draw_black_key, --Db
|
|
}
|
|
|
|
local base_color = duty_colors[note.duty + 1]
|
|
|
|
-- Calculate two key spots, based on tuning. This helps to
|
|
-- highlight intentionally out of tune notes, and lights up the closest
|
|
-- piano keys relative to standard tuning. The brightness of each pad is
|
|
-- relative to the tuning offset, so the brighter key is (usually) the
|
|
-- real note
|
|
|
|
local note_key = (note.y - 2) / PIANO_ROLL_KEY_HEIGHT
|
|
local base_key = math.floor(note_key)
|
|
local base_percent = 1.0 - (note_key % 1)
|
|
local adjacent_key = math.ceil(note_key)
|
|
local adjacent_percent = note_key % 1
|
|
|
|
-- Now take both of these colors and apply some transparency based on volume
|
|
local volume_percent = (note.volume / 15) * 0.75 + 0.25
|
|
base_percent = base_percent * volume_percent
|
|
adjacent_percent = adjacent_percent * volume_percent
|
|
|
|
local base_y = base_key * PIANO_ROLL_KEY_HEIGHT
|
|
local base_key_color = apply_transparency(base_color, base_percent)
|
|
|
|
local adjacent_y = adjacent_key * PIANO_ROLL_KEY_HEIGHT
|
|
local adjacent_key_color = apply_transparency(base_color, adjacent_percent)
|
|
|
|
key_drawing_functions[base_key % 12 + 1](base_y, base_key_color)
|
|
key_drawing_functions[adjacent_key % 12 + 1](adjacent_y, adjacent_key_color)
|
|
end
|
|
|
|
function draw_pad(x, y, value, foreground, background)
|
|
emu.drawRectangle(x, y-1, 4, 9, background, true)
|
|
emu.drawLine(x+4, y, x+4, y+6, background)
|
|
tiny_hex_char(x+1,y+1,value,foreground)
|
|
end
|
|
|
|
function draw_noise_pads(active_note, duty_colors)
|
|
local pad_colors = {
|
|
0x101010,
|
|
0x121212,
|
|
0x141414,
|
|
0x161616,
|
|
0x181818,
|
|
0x1A1A1A,
|
|
0x1C1C1C,
|
|
0x1E1E1E,
|
|
0x202020,
|
|
0x222222,
|
|
0x242424,
|
|
0x262626,
|
|
0x282828,
|
|
0x2A2A2A,
|
|
0x2C2C2C,
|
|
0x2E2E2E,
|
|
}
|
|
|
|
for i = 0, 15 do
|
|
local x = 240 + ((i % 4) * 4)
|
|
local y = i * 2 + NOISE_ROLL_OFFSET - 3
|
|
local color = pad_colors[(0xF - i) + 1]
|
|
local hex_value = 0xF - i;
|
|
if (active_note.y and active_note.enabled and active_note.period == i) then
|
|
color = duty_colors[1]
|
|
if active_note.mode then
|
|
color = duty_colors[2]
|
|
end
|
|
end
|
|
draw_pad(x, y, hex_value, apply_brightness(color, 1.8), color)
|
|
end
|
|
|
|
emu.drawLine(240, NOISE_ROLL_OFFSET - 4, 240, NOISE_ROLL_OFFSET + 30, 0x101010)
|
|
emu.drawLine(241, NOISE_ROLL_OFFSET + 30, 243, NOISE_ROLL_OFFSET + 30, NOISE_STRING_BLACK_COLOR)
|
|
end
|
|
|
|
function draw_dmc_roll(emu, state_table)
|
|
for x = 1, #state_table do
|
|
local y = DMC_OFFSET
|
|
local color = DMC_PLAYING_COLOR
|
|
if not state_table[x].playing then
|
|
color = DMC_BASE_COLOR
|
|
end
|
|
-- width of "sample" based on delta, maximum is 127
|
|
local sample_offset = math.floor((state_table[x].delta / 127) * DMC_HEIGHT)
|
|
emu.drawLine(x - 1, y - sample_offset, x - 1, y + sample_offset, color)
|
|
end
|
|
end
|
|
|
|
function draw_dmc_head(note)
|
|
local foreground = 0x404040
|
|
local background = 0x202020
|
|
if note.playing then
|
|
foreground = DMC_PLAYING_COLOR
|
|
background = apply_brightness(DMC_PLAYING_COLOR, 0.5)
|
|
end
|
|
emu.drawRectangle(242, DMC_OFFSET - 6, 13, 13, background, true)
|
|
emu.drawRectangle(241, DMC_OFFSET - 5, 15, 11, background, true)
|
|
emu.drawLine(240, DMC_OFFSET - 3, 240, DMC_OFFSET + 3, 0x101010)
|
|
tiny_hex(241, DMC_OFFSET - 2, note.address, foreground, 4)
|
|
end
|
|
|
|
local old_mouse_state = {}
|
|
|
|
function is_region_clicked(x ,y, width, height, mouse_state)
|
|
if mouse_state.left and not old_mouse_state.left then
|
|
if mouse_state.x >= x and mouse_state.x < x + width and mouse_state.y >= y and mouse_state.y < y + height then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function handle_input()
|
|
local mouse_state = emu.getMouseState()
|
|
if is_region_clicked(0, 0, 256, 240, mouse_state) then
|
|
toggle_background()
|
|
end
|
|
old_mouse_state = mouse_state
|
|
end
|
|
|
|
-- drawing functions for various icons in the register display
|
|
function draw_raw_registers(x, y, box_color, shadow_color, numeral_color, background_color, values)
|
|
emu.drawRectangle(x+1, y+1, 36, 7, shadow_color)
|
|
emu.drawRectangle(x, y, 36, 7, box_color, true)
|
|
for i = 1, 4 do
|
|
emu.drawRectangle(x + ((i - 1) * 9) + 1, y + 1, 7, 5, background_color, true)
|
|
if values[i] ~= nil then
|
|
tiny_hex(x + ((i - 1) * 9) + 1, y + 1, values[i], numeral_color, 2)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_duty_12(x, y, color)
|
|
emu.drawLine(x, y+3, x+4, y+3, color)
|
|
emu.drawLine(x+1, y+1, x+1, y+2, color)
|
|
end
|
|
|
|
function draw_duty_25(x, y, color)
|
|
emu.drawLine(x, y+3, x+1, y+3, color)
|
|
emu.drawLine(x+3, y+3, x+4, y+3, color)
|
|
emu.drawLine(x+1, y+1, x+3, y+1, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+3, y+2, color)
|
|
end
|
|
|
|
function draw_duty_50(x, y, color)
|
|
emu.drawLine(x, y+3, x+2, y+3, color)
|
|
emu.drawLine(x+2, y+1, x+4, y+1, color)
|
|
emu.drawPixel(x+2, y+2, color)
|
|
end
|
|
|
|
function draw_duty_75(x, y, color)
|
|
emu.drawLine(x, y+1, x+1, y+1, color)
|
|
emu.drawLine(x+3, y+1, x+4, y+1, color)
|
|
emu.drawLine(x+1, y+3, x+3, y+3, color)
|
|
emu.drawPixel(x+1, y+2, color)
|
|
emu.drawPixel(x+3, y+2, color)
|
|
end
|
|
|
|
local duty_icon_functions = {draw_duty_12, draw_duty_25, draw_duty_50, draw_duty_75}
|
|
|
|
function draw_duty_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, duty_cycle, playing)
|
|
local icon_color = light_color
|
|
if playing then
|
|
icon_color = selected_light_color
|
|
end
|
|
emu.drawLine(x, y+6, x+2, y+6, icon_color)
|
|
emu.drawLine(x+2, y, x+2, y+5, icon_color)
|
|
emu.drawLine(x+3, y, x+6, y, icon_color)
|
|
emu.drawLine(x+7, y, x+7, y+5, icon_color)
|
|
emu.drawLine(x+7, y+6, x+9, y+6, icon_color)
|
|
|
|
emu.drawRectangle(x+12, y+1, 25, 7, shadow_color)
|
|
emu.drawRectangle(x+11, y, 25, 7, box_color, true)
|
|
|
|
for i = 1, 4 do
|
|
if playing and duty_cycle == (i - 1) then
|
|
emu.drawRectangle(x + ((i - 1) * 6) + 12, y + 1, 5, 5, selected_dark_color, true)
|
|
duty_icon_functions[i](x + ((i - 1) * 6) + 12, y + 1, selected_light_color)
|
|
else
|
|
emu.drawRectangle(x + ((i - 1) * 6) + 12, y + 1, 5, 5, dark_color, true)
|
|
duty_icon_functions[i](x + ((i - 1) * 6) + 12, y + 1, light_color)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_sweep_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, sweep_byte)
|
|
local negate = ((sweep_byte & 0x40) ~= 0)
|
|
local period = ((sweep_byte & 0x70) >> 4)
|
|
local shift = ((sweep_byte & 0x07))
|
|
local enabled = ((sweep_byte & 0x80) ~= 0) and (shift ~= 0)
|
|
|
|
local icon_color = light_color
|
|
if enabled then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
-- sweep icon
|
|
emu.drawLine(x, y, x+6, y+6, icon_color)
|
|
emu.drawLine(x+3, y+4, x+5, y+6, icon_color)
|
|
emu.drawLine(x+3, y+5, x+4, y+6, icon_color)
|
|
emu.drawLine(x+4, y+3, x+6, y+5, icon_color)
|
|
emu.drawLine(x+7, y+4, x+7, y+5, icon_color)
|
|
emu.drawPixel(x+9, y+4, icon_color)
|
|
emu.drawPixel(x+8, y+2, icon_color)
|
|
|
|
-- bar graph indicators
|
|
emu.drawPixel(x+21, y, icon_color)
|
|
emu.drawPixel(x+22, y+1, icon_color)
|
|
emu.drawPixel(x+21, y+2, icon_color)
|
|
emu.drawPixel(x+24, y, icon_color)
|
|
emu.drawPixel(x+25, y+1, icon_color)
|
|
emu.drawPixel(x+24, y+2, icon_color)
|
|
|
|
emu.drawPixel(x+21, y+5, icon_color)
|
|
emu.drawLine(x+22, y+4, x+22, y+6, icon_color)
|
|
emu.drawLine(x+24, y+4, x+24, y+6, icon_color)
|
|
emu.drawPixel(x+25, y+5, icon_color)
|
|
|
|
-- indicator outlines
|
|
emu.drawRectangle(x+12, y+1, 7, 7, shadow_color)
|
|
emu.drawRectangle(x+11, y, 7, 7, box_color, true)
|
|
|
|
emu.drawRectangle(x+28, y+1, 9, 7, shadow_color)
|
|
emu.drawRectangle(x+27, y, 9, 7, box_color, true)
|
|
|
|
if enabled then
|
|
emu.drawRectangle(x+12, y+1, 5, 5, selected_dark_color, true)
|
|
emu.drawLine(x+13, y+3, x+15, y+3, selected_light_color)
|
|
if negate then
|
|
emu.drawPixel(x+14, y+2, selected_light_color)
|
|
emu.drawLine(x+12, y+4, x+16, y+4, selected_light_color)
|
|
else
|
|
emu.drawPixel(x+14, y+4, selected_light_color)
|
|
emu.drawLine(x+12, y+2, x+16, y+2, selected_light_color)
|
|
end
|
|
emu.drawRectangle(x+28, y+1, 7, 2, selected_dark_color)
|
|
emu.drawRectangle(x+28, y+4, 7, 2, selected_dark_color)
|
|
emu.drawRectangle(x+28, y+1, shift, 2, selected_light_color)
|
|
emu.drawRectangle(x+28, y+4, period, 2, selected_light_color)
|
|
else
|
|
-- simply blank out the indicators and draw nothing
|
|
emu.drawRectangle(x+12, y+1, 5, 5, dark_color, true)
|
|
emu.drawRectangle(x+28, y+1, 7, 2, dark_color)
|
|
emu.drawRectangle(x+28, y+4, 7, 2, dark_color)
|
|
end
|
|
end
|
|
|
|
function draw_volume_envelope_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, volume_byte)
|
|
local constant_volume = ((volume_byte & 0x10) ~= 0)
|
|
|
|
local icon_color = light_color
|
|
if not constant_volume then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
-- volume icon
|
|
emu.drawLine(x, y+2, x, y+4, icon_color)
|
|
emu.drawPixel(x+1, y+2, icon_color)
|
|
emu.drawPixel(x+1, y+4, icon_color)
|
|
emu.drawLine(x+2, y+1, x+2, y+5, icon_color)
|
|
emu.drawLine(x+3, y, x+3, y+1, icon_color)
|
|
emu.drawLine(x+3, y+5, x+3, y+6, icon_color)
|
|
emu.drawPixel(x+4, y, icon_color)
|
|
emu.drawPixel(x+4, y+6, icon_color)
|
|
emu.drawLine(x+5, y, x+5, y+6, icon_color)
|
|
emu.drawLine(x+7, y+2, x+7, y+4, icon_color)
|
|
emu.drawLine(x+7, y, x+8, y, icon_color)
|
|
emu.drawLine(x+7, y+6, x+8, y+6, icon_color)
|
|
emu.drawLine(x+9, y+1, x+9, y+5, icon_color)
|
|
|
|
-- box backgrounds and scaffolding
|
|
emu.drawRectangle(x+12, y+1, 13, 7, shadow_color)
|
|
emu.drawRectangle(x+11, y, 13, 7, box_color, true)
|
|
|
|
emu.drawLine(x+25, y+4, x+32, y+4, shadow_color)
|
|
emu.drawLine(x+24, y+3, x+31, y+3, box_color)
|
|
|
|
emu.drawRectangle(x+32, y+1, 5, 7, shadow_color)
|
|
emu.drawRectangle(x+31, y, 5, 7, box_color, true)
|
|
|
|
if constant_volume then
|
|
-- draw un-highlighted icons
|
|
emu.drawRectangle(x+12, y+1, 5, 5, dark_color, true)
|
|
emu.drawRectangle(x+12, y+1, 2, 5, light_color, true)
|
|
emu.drawRectangle(x+14, y+2, 2, 3, light_color, true)
|
|
emu.drawPixel(x+16, y+3, light_color)
|
|
|
|
emu.drawRectangle(x+18, y+1, 5, 5, dark_color, true)
|
|
emu.drawPixel(x+19, y+2, light_color)
|
|
emu.drawPixel(x+19, y+4, light_color)
|
|
emu.drawLine(x+21, y+1, x+21, y+5, light_color)
|
|
|
|
-- do not draw envelope period, but blank the cell
|
|
emu.drawRectangle(x+32, y+1, 3, 5, dark_color, true)
|
|
else
|
|
-- draw uhighlighted icons
|
|
emu.drawRectangle(x+12, y+1, 5, 5, selected_dark_color, true)
|
|
emu.drawRectangle(x+12, y+1, 2, 5, selected_light_color, true)
|
|
emu.drawRectangle(x+14, y+2, 2, 3, selected_light_color, true)
|
|
emu.drawPixel(x+16, y+3, selected_light_color)
|
|
|
|
local loop = (volume_byte & 0x30) ~= 0
|
|
if loop then
|
|
emu.drawRectangle(x+18, y+1, 5, 5, selected_dark_color, true)
|
|
emu.drawPixel(x+19, y+2, selected_light_color)
|
|
emu.drawPixel(x+19, y+4, selected_light_color)
|
|
emu.drawLine(x+21, y+1, x+21, y+5, selected_light_color)
|
|
else
|
|
emu.drawRectangle(x+18, y+1, 5, 5, dark_color, true)
|
|
emu.drawPixel(x+19, y+2, light_color)
|
|
emu.drawPixel(x+19, y+4, light_color)
|
|
emu.drawLine(x+21, y+1, x+21, y+5, light_color)
|
|
end
|
|
|
|
-- populate the envelope period
|
|
local period = (volume_byte & 0xF)
|
|
emu.drawRectangle(x+32, y+1, 3, 5, selected_dark_color, true)
|
|
tiny_hex(x+32, y+1, period, selected_light_color, 1)
|
|
end
|
|
end
|
|
|
|
function draw_volume_bar(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, volume_byte, current_volume)
|
|
emu.drawRectangle(x+1, y+1, 36, 7, shadow_color)
|
|
emu.drawRectangle(x, y, 36, 7, box_color, true)
|
|
|
|
-- first, handle the constant volume indicator
|
|
local constant_volume = ((volume_byte & 0x10) ~= 0)
|
|
if constant_volume then
|
|
emu.drawRectangle(x+1, y+1, 3, 5, selected_dark_color, true)
|
|
tiny_hex(x+1, y+1, current_volume, selected_light_color, 1)
|
|
else
|
|
emu.drawRectangle(x+1, y+1, 3, 5, dark_color, true)
|
|
end
|
|
|
|
-- then, based on the current playing volume, update the bar. Note this is the output volume, NOT the
|
|
-- value written to the register. It should follow the active envelope.
|
|
for i = 1, 15 do
|
|
local dx = x+5 + ((i-1) * 2)
|
|
local dy = y+1
|
|
if current_volume >= i then
|
|
emu.drawLine(dx, dy, dx, dy+4, selected_dark_color)
|
|
emu.drawLine(dx+1, dy, dx+1, dy+4, selected_light_color)
|
|
else
|
|
emu.drawLine(dx, dy, dx, dy+4, dark_color)
|
|
emu.drawLine(dx+1, dy, dx+1, dy+4, light_color)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_triangle_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, triangle_playing)
|
|
local icon_color = light_color
|
|
if triangle_playing then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
emu.drawLine(x, y+5, x+4, y+1, icon_color)
|
|
emu.drawLine(x+5, y+1, x+9, y+5, icon_color)
|
|
|
|
emu.drawRectangle(x+12, y+1, 25, 7, shadow_color)
|
|
emu.drawRectangle(x+11, y, 25, 7, box_color, true)
|
|
|
|
if triangle_playing then
|
|
emu.drawRectangle(x+12, y+1, 23, 5, selected_dark_color, true)
|
|
emu.drawRectangle(x+21, y+1, 2, 5, selected_light_color)
|
|
emu.drawRectangle(x+23, y+2, 2, 3, selected_light_color)
|
|
emu.drawLine(x+25, y+3, x+26, y+3, selected_light_color)
|
|
else
|
|
emu.drawRectangle(x+12, y+1, 23, 5, dark_color, true)
|
|
emu.drawRectangle(x+21, y+1, 2, 5, light_color)
|
|
emu.drawRectangle(x+23, y+2, 2, 3, light_color)
|
|
emu.drawLine(x+25, y+3, x+26, y+3, light_color)
|
|
end
|
|
end
|
|
|
|
function draw_mode_0(x, y, color)
|
|
emu.drawPixel(x, y+2, color)
|
|
emu.drawPixel(x+1, y, color)
|
|
emu.drawPixel(x+2, y+3, color)
|
|
emu.drawPixel(x+3, y+4, color)
|
|
emu.drawPixel(x+4, y+2, color)
|
|
emu.drawPixel(x+5, y, color)
|
|
emu.drawPixel(x+6, y+2, color)
|
|
emu.drawPixel(x+7, y+3, color)
|
|
emu.drawPixel(x+8, y+1, color)
|
|
emu.drawPixel(x+9, y+4, color)
|
|
emu.drawPixel(x+10, y, color)
|
|
end
|
|
|
|
function draw_mode_1(x, y, color)
|
|
emu.drawPixel(x, y+2, color)
|
|
emu.drawLine(x+1, y+1, x+1, y+2, color)
|
|
emu.drawPixel(x+2, y, color)
|
|
emu.drawPixel(x+3, y+4, color)
|
|
emu.drawPixel(x+4, y+3, color)
|
|
emu.drawLine(x+5, y+2, x+5, y+3, color)
|
|
emu.drawPixel(x+6, y+1, color)
|
|
emu.drawPixel(x+7, y, color)
|
|
emu.drawLine(x+8, y+3, x+8, y+4, color)
|
|
emu.drawPixel(x+9, y+2, color)
|
|
emu.drawPixel(x+10, y+1, color)
|
|
end
|
|
|
|
local mode_functions = {}
|
|
mode_functions[0] = draw_mode_0
|
|
mode_functions[1] = draw_mode_1
|
|
|
|
function draw_noise_mode(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, noise_byte, playing)
|
|
local icon_color = light_color
|
|
if playing then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
emu.drawPixel(x, y+3, icon_color)
|
|
emu.drawPixel(x+1, y+2, icon_color)
|
|
emu.drawLine(x+2, y+3, x+2, y+5, icon_color)
|
|
emu.drawLine(x+3, y, x+3, y+2, icon_color)
|
|
emu.drawLine(x+4, y+3, x+4, y+4, icon_color)
|
|
emu.drawPixel(x+5, y+2, icon_color)
|
|
emu.drawLine(x+6, y+3, x+6, y+6, icon_color)
|
|
emu.drawLine(x+7, y+1, x+7, y+2, icon_color)
|
|
emu.drawLine(x+8, y+3, x+9, y+3, icon_color)
|
|
|
|
emu.drawRectangle(x+12, y+1, 25, 7, shadow_color)
|
|
emu.drawRectangle(x+11, y, 25, 7, box_color, true)
|
|
|
|
local noise_mode = ((noise_byte & 0x80) >> 7)
|
|
for i = 0, 1 do
|
|
if i == noise_mode then
|
|
emu.drawRectangle(x+12 + (i*12), y+1, 11, 5, selected_dark_color, true)
|
|
mode_functions[i](x+12 + (i*12), y+1, selected_light_color)
|
|
else
|
|
emu.drawRectangle(x+12 + (i*12), y+1, 11, 5, dark_color, true)
|
|
mode_functions[i](x+12 + (i*12), y+1, light_color)
|
|
end
|
|
end
|
|
end
|
|
|
|
function draw_dpcm_sample_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, frequency_byte, sample_address_byte, dpcm_active)
|
|
local icon_color = light_color
|
|
if dpcm_active then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
emu.drawLine(x, y+3, x+9, y+3, icon_color)
|
|
emu.drawLine(x+1, y+2, x+1, y+4, icon_color)
|
|
emu.drawLine(x+2, y+1, x+2, y+5, icon_color)
|
|
emu.drawLine(x+4, y+2, x+4, y+4, icon_color)
|
|
emu.drawLine(x+6, y+1, x+6, y+5, icon_color)
|
|
emu.drawLine(x+7, y, x+7, y+6, icon_color)
|
|
emu.drawLine(x+8, y+2, x+8, y+4, icon_color)
|
|
|
|
emu.drawRectangle(x+13, y+1, 5, 7, shadow_color)
|
|
emu.drawRectangle(x+12, y, 5, 7, box_color, true)
|
|
|
|
emu.drawLine(x+18, y+4, x+19, y+4, shadow_color)
|
|
emu.drawLine(x+17, y+3, x+18, y+3, box_color)
|
|
|
|
emu.drawRectangle(x+20, y+1, 17, 7, shadow_color)
|
|
emu.drawRectangle(x+19, y, 17, 7, box_color, true)
|
|
|
|
local frequency = frequency_byte & 0xF
|
|
local address = 0xC000 + (sample_address_byte << 6)
|
|
|
|
if dpcm_active then
|
|
emu.drawRectangle(x+13, y+1, 3, 5, selected_dark_color, true)
|
|
emu.drawRectangle(x+20, y+1, 15, 5, selected_dark_color, true)
|
|
tiny_hex(x+13, y+1, frequency, selected_light_color, 1)
|
|
tiny_hex(x+20, y+1, address, selected_light_color, 4)
|
|
else
|
|
emu.drawRectangle(x+13, y+1, 3, 5, dark_color, true)
|
|
emu.drawRectangle(x+20, y+1, 15, 5, dark_color, true)
|
|
tiny_hex(x+13, y+1, frequency, light_color, 1)
|
|
tiny_hex(x+20, y+1, address, light_color, 4)
|
|
end
|
|
end
|
|
|
|
function draw_dpcm_length_indicator(x, y, icon_color, box_color, shadow_color, light_color, dark_color, selected_light_color, selected_dark_color, control_byte, length_byte, dpcm_active)
|
|
local icon_color = light_color
|
|
if dpcm_active then
|
|
icon_color = selected_light_color
|
|
end
|
|
|
|
emu.drawLine(x+3, y, x+5, y, icon_color)
|
|
emu.drawLine(x+7, y+2, x+7, y+4, icon_color)
|
|
emu.drawLine(x+3, y+6, x+5, y+6, icon_color)
|
|
emu.drawLine(x+1, y+2, x+1, y+4, icon_color)
|
|
emu.drawPixel(x+2,y+1, icon_color)
|
|
emu.drawPixel(x+6,y+1, icon_color)
|
|
emu.drawPixel(x+2,y+5, icon_color)
|
|
emu.drawPixel(x+6,y+5, icon_color)
|
|
emu.drawLine(x+4, y+1, x+4, y+3, icon_color)
|
|
emu.drawLine(x+5, y+3, x+6, y+3, icon_color)
|
|
|
|
emu.drawRectangle(x+18, y+1, 19, 7, shadow_color)
|
|
emu.drawRectangle(x+17, y, 19, 7, box_color, true)
|
|
|
|
local looping = ((control_byte & 0x40) ~= 0)
|
|
local sample_length = (length_byte * 16) + 1
|
|
|
|
if dpcm_active then
|
|
emu.drawRectangle(x+18,y+1,11, 5, selected_dark_color, true)
|
|
emu.drawRectangle(x+30,y+1,5, 5, selected_dark_color, true)
|
|
tiny_hex(x+18,y+1,sample_length, selected_light_color, 3)
|
|
emu.drawPixel(x+31, y+2, selected_light_color)
|
|
emu.drawPixel(x+31, y+4, selected_light_color)
|
|
emu.drawLine(x+33, y+1, x+33, y+5, selected_light_color)
|
|
else
|
|
emu.drawRectangle(x+18,y+1,11, 5, dark_color, true)
|
|
emu.drawRectangle(x+30,y+1,5, 5, dark_color, true)
|
|
tiny_hex(x+18,y+1,sample_length, light_color, 3)
|
|
emu.drawPixel(x+31, y+2, light_color)
|
|
emu.drawPixel(x+31, y+4, light_color)
|
|
emu.drawLine(x+33, y+1, x+33, y+5, light_color)
|
|
end
|
|
end
|
|
|
|
local ICON_COLOR = 0x808080
|
|
local SHADOW_COLOR = 0x80000000
|
|
local BOX_OUTLINE_COLOR = 0x000000
|
|
local UNSELECTED_DARK_COLOR = 0x404040
|
|
local UNSELECTED_LIGHT_COLOR = 0x808080
|
|
|
|
function draw_apu_registers()
|
|
emu.drawRectangle(0, 0, 39, 240, 0x40202020, true)
|
|
|
|
local square1_duty = (shadow_apu[0x4000] & 0xC0) >> 6
|
|
local square1_selected_light = SQUARE1_COLORS[square1_duty + 1]
|
|
local square1_selected_dark = square1_selected_light + 0xB0000000
|
|
|
|
tiny_string(1, 1, "Pulse 1", 0xFFFFFF)
|
|
draw_raw_registers(1, 7, BOX_OUTLINE_COLOR, SHADOW_COLOR, UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR,
|
|
{shadow_apu[0x4000],shadow_apu[0x4001],shadow_apu[0x4002],shadow_apu[0x4003]})
|
|
draw_duty_indicator(1, 16,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square1_selected_light, square1_selected_dark, -- icon color when highlighted
|
|
(shadow_apu[0x4000] & 0xC0) >> 6, square1_roll[#square1_roll].enabled)
|
|
|
|
draw_sweep_indicator(1, 25,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square1_selected_light, square1_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4001])
|
|
|
|
draw_volume_envelope_indicator(1, 34,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square1_selected_light, square1_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4000])
|
|
|
|
draw_volume_bar(1, 43,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square1_selected_light, square1_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4000],
|
|
square1_roll[#square1_roll].volume)
|
|
|
|
local square2_duty = (shadow_apu[0x4004] & 0xC0) >> 6
|
|
local square2_selected_light = SQUARE2_COLORS[square2_duty + 1]
|
|
local square2_selected_dark = square2_selected_light + 0xB0000000
|
|
|
|
tiny_string(1, 60, "Pulse 2", 0xFFFFFF)
|
|
draw_raw_registers(1, 66, BOX_OUTLINE_COLOR, SHADOW_COLOR, UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR,
|
|
{shadow_apu[0x4004],shadow_apu[0x4005],shadow_apu[0x4006],shadow_apu[0x4007]})
|
|
draw_duty_indicator(1, 75,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square2_selected_light, square2_selected_dark, -- icon color when highlighted
|
|
(shadow_apu[0x4004] & 0xC0) >> 6, square2_roll[#square2_roll].enabled)
|
|
|
|
draw_sweep_indicator(1, 84,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square2_selected_light, square2_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4005])
|
|
|
|
draw_volume_envelope_indicator(1, 93,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square2_selected_light, square2_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4004])
|
|
|
|
draw_volume_bar(1, 102,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
square2_selected_light, square2_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4004],
|
|
square2_roll[#square2_roll].volume)
|
|
|
|
local triangle_selected_light = TRIANGLE_COLORS[1]
|
|
local triangle_selected_dark = triangle_selected_light + 0xB0000000
|
|
|
|
tiny_string(1, 119, "Triangle", 0xFFFFFF)
|
|
|
|
draw_raw_registers(1, 126, BOX_OUTLINE_COLOR, SHADOW_COLOR, UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR,
|
|
{shadow_apu[0x4008],nil,shadow_apu[0x400A],shadow_apu[0x400B]})
|
|
|
|
draw_triangle_indicator(1, 135,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
triangle_selected_light, triangle_selected_dark, -- icon color when highlighted
|
|
triangle_roll[#triangle_roll].enabled)
|
|
|
|
local noise_mode = ((shadow_apu[0x400E] & 0x80) >> 7)
|
|
local noise_selected_light = NOISE_COLORS[noise_mode+1]
|
|
local noise_selected_dark = noise_selected_light + 0xB0000000
|
|
|
|
tiny_string(1, 195, "Noise", 0xFFFFFF)
|
|
|
|
draw_raw_registers(1, 202, BOX_OUTLINE_COLOR, SHADOW_COLOR, UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR,
|
|
{shadow_apu[0x400C],nil,shadow_apu[0x400E],shadow_apu[0x400F]})
|
|
draw_noise_mode(1, 211,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
noise_selected_light, noise_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x400E], noise_roll[#noise_roll].enabled)
|
|
|
|
|
|
draw_volume_envelope_indicator(1, 220,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
noise_selected_light, noise_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x400C])
|
|
|
|
draw_volume_bar(1, 229,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
noise_selected_light, noise_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x400C],
|
|
noise_roll[#noise_roll].volume)
|
|
|
|
local dpcm_selected_light = DMC_PLAYING_COLOR
|
|
local dpcm_selected_dark = dpcm_selected_light + 0xB0000000
|
|
|
|
tiny_string(1, 159, "DPCM", 0xFFFFFF)
|
|
|
|
draw_raw_registers(1, 166, BOX_OUTLINE_COLOR, SHADOW_COLOR, UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR,
|
|
{shadow_apu[0x4010],shadow_apu[0x4011],shadow_apu[0x4012],shadow_apu[0x4013]})
|
|
|
|
draw_dpcm_sample_indicator(1, 175,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
dpcm_selected_light, dpcm_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4010], shadow_apu[0x4012], dmc_roll[#dmc_roll].playing)
|
|
|
|
draw_dpcm_length_indicator(1, 184,
|
|
ICON_COLOR, --line color
|
|
BOX_OUTLINE_COLOR, SHADOW_COLOR, -- box outline and shadow
|
|
UNSELECTED_LIGHT_COLOR, UNSELECTED_DARK_COLOR, -- icon color when darkened
|
|
dpcm_selected_light, dpcm_selected_dark, -- icon color when highlighted
|
|
shadow_apu[0x4010], shadow_apu[0x4013], dmc_roll[#dmc_roll].playing)
|
|
end
|
|
|
|
function mesen_draw()
|
|
local state = emu.getState()
|
|
local clockRate = state["clockRate"]
|
|
-- x y str fore: argb back: argb
|
|
--emu.drawString(10, 10, "Hello Mesen", 0x80ff0000, 0x80FFFFFF)
|
|
--emu.drawString(10, 20, "P1: "..apu.square1.period, 0xff0000, 0xFFFFFF)
|
|
|
|
local apu = {
|
|
square1 = {
|
|
frequency = clockRate / 16 / (state["apu.square1.realPeriod"] + 1),
|
|
envelope = { volume = state["apu.square1.envelope.volume"] },
|
|
lengthCounter = { counter = state["apu.square1.envelope.lengthCounter.counter"] },
|
|
duty = state["apu.square1.duty"]
|
|
},
|
|
square2 = {
|
|
frequency = clockRate / 16 / (state["apu.square2.realPeriod"] + 1),
|
|
envelope = { volume = state["apu.square2.envelope.volume"] },
|
|
lengthCounter = { counter = state["apu.square2.envelope.lengthCounter.counter"] },
|
|
duty = state["apu.square2.duty"]
|
|
},
|
|
triangle = {
|
|
frequency = clockRate / 32 / (state["apu.triangle.timer.period"] + 1),
|
|
lengthCounter = { counter = state["apu.triangle.lengthCounter.counter"] },
|
|
period = state["apu.triangle.timer.period"],
|
|
enabled = state["apu.triangle.lengthCounter.enabled"]
|
|
},
|
|
noise = {
|
|
period = state["apu.noise.timer.period"],
|
|
mode = state["apu.noise.modeFlag"],
|
|
envelope = {
|
|
constantVolume = state["apu.noise.envelope.constantVolume"],
|
|
volume = state["apu.noise.envelope.volume"],
|
|
counter = state["apu.noise.envelope.counter"]
|
|
},
|
|
lengthCounter = { counter = state["apu.noise.envelope.lengthCounter.counter"] }
|
|
},
|
|
dmc = {
|
|
bytesRemaining = state["apu.dmc.bytesRemaining"],
|
|
outputVolume = state["apu.dmc.timer.lastOutput"],
|
|
period = state["apu.dmc.timer.period"],
|
|
sampleAddr = state["apu.dmc.sampleAddr"],
|
|
}
|
|
}
|
|
|
|
update_piano_roll(apu.square1, square1_roll)
|
|
update_piano_roll(apu.square2, square2_roll)
|
|
update_piano_roll(apu.triangle, triangle_roll)
|
|
update_noise_roll(apu.noise, noise_roll)
|
|
update_dmc_roll(apu.dmc, dmc_roll)
|
|
|
|
draw_piano_background()
|
|
draw_piano_strings()
|
|
draw_piano_keys()
|
|
draw_noise_strings()
|
|
draw_noise_pads(noise_roll[#noise_roll], NOISE_COLORS)
|
|
|
|
draw_piano_roll(emu, square1_roll, SQUARE1_COLORS)
|
|
draw_piano_roll(emu, square2_roll, SQUARE2_COLORS)
|
|
draw_piano_roll(emu, triangle_roll, TRIANGLE_COLORS)
|
|
draw_noise_roll(emu, noise_roll, NOISE_COLORS)
|
|
draw_dmc_roll(emu, dmc_roll)
|
|
draw_key_spot(square1_roll[#square1_roll], SQUARE1_COLORS)
|
|
draw_key_spot(square2_roll[#square2_roll], SQUARE2_COLORS)
|
|
draw_key_spot(triangle_roll[#square1_roll], TRIANGLE_COLORS)
|
|
draw_dmc_head(dmc_roll[#dmc_roll])
|
|
|
|
draw_apu_registers()
|
|
|
|
handle_input()
|
|
end
|
|
|
|
emu.addEventCallback(mesen_draw, emu.eventType.endFrame); |