--[[
Necessary table-of-tables to tell Splisch which data in the ROM can be
overwritten. The workspace table has other implications as well
(See documentation for more details)
--]]
workspace =
{
["maindata"] = {["offset"] = 0x34782, ["size"] = 0x2B4D3, ["flags"] = "score,brr,clear"},
["score_ptr"] = {["offset"] = 0x33D39, ["pitch"] = 3, ["size"] = 0xC0},
["brr_ptr"] = {["offset"] = 0x33DF9, ["pitch"] = 3, ["size"] = 0x63},
["brr_loop"] = {["offset"] = 0x33E5C, ["pitch"] = 2, ["size"] = 0x42},
["inst_freq"] = {["offset"] = 0x33E9E, ["pitch"] = 2, ["size"] = 0x42},
["inst_adsr"] = {["offset"] = 0x33EE0, ["pitch"] = 2, ["size"] = 0x42},
["inst_assign"] = {["offset"] = 0x33F22, ["pitch"] = 0x20, ["size"] = 0x800},
}
--[[
Necessary functions to tell Splisch how many songs and instruments
appear in this game
You can hard-code values here, but I use calculations based
on the above constants so that this is more dynamic
--]]
-- return the number of songs in this game
function desc_song_count()
return math.min(
workspace["score_ptr"].count,
workspace["inst_assign"].count )
end
-- return the number of available instruments in this game
function desc_inst_count()
return math.min(
workspace["brr_ptr"].count,
workspace["brr_loop"].count,
workspace["inst_freq"].count,
workspace["inst_adsr"].count )
end
-- return the number of instruments that are available for any 1 song
function desc_max_inst_per_song()
return 0x10 -- this isn't very dynamic....
end
--[[
Optional functions to tell Splisch other configuration details
--]]
function desc_score_max_size(song_id) -- if omitted, defaults to nil (no maximum)
return 0x1200
end
function desc_brr_max_size(song_id) -- if omitted, defaults to nil (no maximum)
return 0x7C0F
end
function desc_maindata_max_size(song_id)-- if omitted, defaults to nil (no maximum)
return nil
end
--[[
Necessary function called to load all the game-specific data. This mostly
involves loading instruments, but might also involve some other things that
applies to every song in the game.
Should call schload_set_inst_xxxx functions for each instrument available.
--]]
function desc_load_game()
-- load up instrument pool
for i=0, desc_inst_count()-1, 1 do
-- get the pointer to the start of the brr data
local start = workspace["brr_ptr"].read(i) + 2
start = bit32.band(start,0x3FFFFF)
-- and to the loop point for the brr data
local loop = start + workspace["brr_loop"].read(i)
-- give that to Splisch
schload_set_instrument_brr_ptr(i, start, loop)
-- instruments in this game also have an ADSR value associated with them
schload_set_instrument_adsr(i,
bit32.bor( 0x80, workspace["inst_adsr"].read(i,1,0) ),
workspace["inst_adsr"].read(i,1,1)
)
-- AND, they also have pitch correction
-- TODO -- do some kind of translation so this is more generic
-- ie... define what this value actually is
schload_set_instrument_pitch_adj( i, workspace["inst_freq"].read(i) )
end
-- Also, set the default echo and volume settings.
-- These are probably configurable in the ROM somewhere, but I didn't find them.
-- Not all of them are really "editable" fields anyway.
schload_set_echo_length( 0x06 )
schload_set_echo_feedback( 0x68 )
schload_set_echo_fir( 0x7F,0,0,0,0,0,0,0 )
schload_set_master_vol( 0x7F, 0x7F )
schload_set_echo_vol( 0x20, 0x20 )
end
--[[
Helper function to translate pointers for this game.
Uses global glb_score_start and glb_score_bank
--]]
glb_score_start = 0
glb_score_bank = 0
function translate_score_ptr(ptr)
ptr = ptr + glb_score_bank
if ptr < glb_score_start then
ptr = ptr + 0x10000
end
return ptr
end
--[[
Necessary function called to load the details for a given song
--]]
function desc_load_song(song_id)
-- The song has certain instruments assigned to it. Assign those now
for i=0, desc_max_inst_per_song()-1, 1 do
schload_set_instrument_select( i, workspace["inst_assign"].read(song_id,2,i*2) )
end
-- Songs in this game have 8 channels. Load them up by telling Splisch where the
-- score data starts.
glb_score_start = workspace["score_ptr"].read(song_id) + 2
glb_score_start = bit32.band(glb_score_start,0x3FFFFF)
glb_score_bank = bit32.band(glb_score_start,0x3F0000)
for i=0, 7, 1 do
local ptr = sch_rom_read( glb_score_start + (i*2), 2 )
schload_set_score_data_ptr( i, translate_score_ptr(ptr) )
end
end
--[[
These are called before/after to desc_load_score so that any
per channel initialization/destruction can take place.
They are optional and can be omitted if you don't need them
--]]
function desc_load_channel_start( song_id, chan_id )
end
function desc_load_channel_end( song_id, chan_id )
end
--[[
Processing score bytes! This is called repeatedly for each
command in the score for this song. The command byte(s) should be read
through sch_rom_read, and the appropriate schload_score_xxx function should
be called.
Afterwards, the size in bytes of this command should be returned
--]]
-- global list to keep track of octaves
glb_octave = { [0]=0,0,0,0,0,0,0,0 }
-- global list for lengths -- note this should be editable!!!!!!
glb_lengths = { [0]=0xC0,0x90,0x60,0x40,0x48,0x30,0x20,0x24,0x18,0x10,0x0C,0x08,0x06,0x04,0x03 }
function desc_load_score( song_id, chan_id, offset )
local op = sch_rom_read(offset)
if op < 0xB4 then
-- normal tone
local tone = math.floor(op / 15) + glb_octave[chan_id]
local len = op % 15
schload_score_tone( tone, glb_lengths[len] )
return 1
elseif op < 0xC3 then
-- sustain
schload_score_sustain( op % 15 )
return 1
elseif op < 0xD2 then
-- rest
schload_score_rest( op % 15 )
return 1
elseif op == 0xD2 then
schload_score_setvol( sch_rom_read(offset+1) )
return 2
elseif op == 0xD3 then
schload_score_setvolfade( sch_rom_read(offset+2), sch_rom_read(offset+1) )
return 3
elseif op == 0xD4 then
local pan = sch_rom_read(offset+1)
if bit32.band(pan,0x80) then
pan = -bit32.band(pand,0x7F)
end
schload_score_setpan( pan / 0x7F )
return 2
elseif op == 0xD5 then
local pan = sch_rom_read(offset+2)
if bit32.band(pan,0x80) then
pan = -bit32.band(pand,0x7F)
end
schload_score_setpanfade( sch_rom_read(offset+2), pan / 0x7F )
return 3
elseif op == 0xD6 then -- really don't know. Tempo?
schload_score_unknown(2)
return 3
elseif op == 0xD7 then -- actually vibrato
schload_score_unknown(3)
return 4
elseif op == 0xD8 then -- actually vibrato stop
schload_score_unknown()
return 1
elseif op == 0xD9 then -- actually tremolo
schload_score_unknown(3)
return 4
elseif op == 0xDA then -- actually tremolo stop
schload_score_unknown()
return 1
elseif op == 0xDB then -- really don't know.
schload_score_unknown(2)
return 3
elseif op == 0xDC then -- really don't know.
schload_score_unknown()
return 1
elseif op == 0xDD then
schload_score_noisefreq( sch_rom_read(offset+1) )
return 2
elseif op == 0xDE then
schload_score_enablenoise( true )
return 1
elseif op == 0xDF then
schload_score_enablenoise( false )
return 1
elseif op == 0xE0 then
schload_score_enablemod( true )
return 1
elseif op == 0xE1 then
schload_score_enablemod( false )
return 1
elseif op == 0xE2 then
schload_score_enableecho( true )
return 1
elseif op == 0xE3 then
schload_score_enableecho( false )
return 1
elseif op == 0xE4 then
glb_octave[chan_id] = sch_rom_read(offset+1)
return 2
elseif op == 0xE5 then
glb_octave[chan_id] = glb_octave[chan_id] + 1
return 1
elseif op == 0xE6 then
glb_octave[chan_id] = glb_octave[chan_id] - 1
return 1
elseif op == 0xE7 then -- really set key change
schload_score_unknown(1)
return 2
elseif op == 0xE8 then -- really offset key change
schload_score_unknown(1)
return 2
elseif op == 0xE9 then -- really don't know
schload_score_unknown(1)
return 2
elseif op == 0xEA then
schload_score_setinst( sch_rom_read(offset+1) )
return 2
elseif op == 0xEB then -- really set attack
schload_score_unknown(1)
return 2
elseif op == 0xEC then -- really set decay
schload_score_unknown(1)
return 2
elseif op == 0xED then -- really set sustain level
schload_score_unknown(1)
return 2
elseif op == 0xEE then -- really set sustain rate
schload_score_unknown(1)
return 2
elseif op == 0xEF then -- really set adsr back to inst defaults
schload_score_unknown()
return 1
elseif op == 0xF0 then -- really don't know
schload_score_unknown(1)
return 2
elseif op == 0xF1 then -- really don't know
schload_score_unknown()
return 1
elseif op == 0xF2 then -- really don't know (end song?)
schload_score_unknown()
return 1
elseif op == 0xF3 then -- really don't know
schload_score_unknown(1)
return 2
elseif op == 0xF4 then -- really don't know
schload_score_unknown(2)
return 3
elseif op == 0xF5 then -- nop
return 2
elseif op == 0xF6 then -- nop
return 3
elseif op == 0xF7 then -- nop
return 3
elseif op == 0xF8 then -- really music master vol
schload_score_unknown(1)
return 2
elseif op == 0xF9 then -- really conditional jump (loop counter crap)
schload_score_unknown(3)
return 4
elseif op == 0xFA then
schload_score_jump( translate_score_ptr( sch_rom_read(offset+1,2) ) )
return 3
elseif op == 0xFB then -- really conditional jump (1 time?)
schload_score_unknown(2)
return 3
elseif op == 0xFC then -- really zero's the loop counter
schload_score_unknown()
return 1
elseif op == 0xFD then -- really sets special instrument
schload_score_unknown(1)
return 2
else -- FE and FF ... end song?
schload_score_unknown()
return 1
end
end