So this thread I intend on including information regarding Mario Paint and its music maker portion as sort of a scratch pad and general realm of research.
The community
Battle of the Bits has a history of using Mario Paint as a sequencer for music competitions.
First off, two members from our community (Strobe and setrodox) created a program to extract the sequencer data from ZST savestates. That data was incorporated into a *.SHO file and played with a CLI utility called ShroomPlayer. A few year later, rainwarrior made a Mario Paint (music maker) clone for PC called
Mariopants.
I began poking around in SNES ARAM to discover a few different things regarding the behavior of the music maker. I intend to elaborate as much as possible within the following threads until it becomes coherent and wiki-able somewhere.
*.SHO and *.SHI file formats:
Code:
SHO file notes:
offset # of bytes Function
----------------------------
$000 4 STRING 's','h','r','o', (denotes a SHO "ShroomPlayer" file)
$004 1 BYTE Version number (See "Version Notes")
$005 2 WORD Reserved
$007 32 STRING Song Title
$027 32 STRING Author Name
$047 32 STRING SHI (sample pack) filename. (Default: "default.shi")
$067 576 STRING (base) Song Data (See "Song Data Format")
$067 2 WORD (mariopantse) Song Length Value (Little endian $6100 min. $400B max.)
$069 1 BYTE (mariopantse) Song Loop ($00 = on $01 = off)
$06A 1 BYTE (mariopantse) Time Signature ($00 = 3/4 $01 = 4/4)
$06B 1 BYTE (mariopantse) Tempo ($00 = Slowest $9F Fastest)
$06C nnn STRING (mariopantse) Song Data (See "Song Data Format")
$2A7 1 BYTE (base) Tempo ($00 = Slowest $9F Fastest)
$2A8 1 BYTE (mariopants) Song Length ($01 = Shortest $60 = Longest)
$2A9 1 BYTE (mariopants) Song Loop ($00 = on $01 = off)
$2AA 1 BYTE (mariopants) Time Signature ($00 = 3/4 $01 = 4/4)
SHO Version Notes:
$01 = ShroomPlayer
Base version. ShroomPlayer ignores "MarioPants" features.
$02 = MarioPants
Adds features noted above.
$03 = MarioPantsE
Adds even more features noted above. Not compatible with "ShroomPlayer" or "MarioPants".
SHI file notes:
offset # of bytes Function
----------------------------
$000 4 STRING 's','h','r','i', (denotes a SHI "ShroomPlayer" sample pack file)
$004 1 BYTE Version number ($01)
$005 2 WORD Reserved
$007 32 STRING Sample Pack Name
$027 32 STRING Sample Pack Author
$047 9 STRING Reserved
$050 nnn STRING Sample Data
The *.SHI file was intended for playing custom sample packs using ShroomPlayer. The *.SHI file is disregarded within Mariopants, but default.shi needs to be a part of the file header for standard operation.
Mariopants does not currently export SRAM format. Mario Paint's SRAM is compressed. HertzDevil discovered that Mario Paint's SRAM is encoded with combined LZ77 and huffman algorithms.
Here is the LUA script for SRAM decompression:
Code:
#!/usr/bin/env lua5.3
if #arg < 2 then
print "Usage: lua5.3 mp_unpack.lua <srm> <output>"
os.exit()
end
local f = io.open(arg[1], "rb")
f:seek("set", 0x7FE)
local datasize = ("<I2"):unpack(f:read(2))
local maptable = {}
for i = 1, 0x400 do
maptable[i] = ("<I2"):unpack(f:read(2))
end
local bin = {}
for i = 1, datasize / 2 - 0x400 do
bin[i] = ("<I2"):unpack(f:read(2))
end
local lz = {}
local huff_ptr = 0
for i, v in ipairs(bin) do
for n = 15, 0, -1 do
huff_ptr = maptable[huff_ptr / 2 + (v & (1 << n) ~= 0 and 2 or 1)]
if maptable[huff_ptr / 2 + 1] == 0 then
table.insert(lz, maptable[huff_ptr / 2 + 2])
huff_ptr = 0
end
end
end
local out = {}
local lz_ptr = 1
local lz_size = #lz
while lz_ptr < lz_size do
local lo, hi = lz[lz_ptr], lz[lz_ptr + 1]
lz_ptr = lz_ptr + 2
if hi >= 0x80 then
for i = 1, hi - 0x80 do
out[#out + 1] = out[#out + 1 - lo]
end
else
for i = 1, hi * 0x100 + lo do
out[#out + 1], lz_ptr = lz[lz_ptr], lz_ptr + 1
end
end
end
local outfile = io.open(arg[2], "wb")
outfile:write(string.char(table.unpack(out)))
outfile:close()
f:close()
There is currently no script for recompression yet.
RAM address locations of interest:
Song data locations:
$7E09E4-$7E0C23 ("Main" song data)
$7E0C3C-$7E0E7B ("Undo" song data)
Song properties information; left = "main" right = "undo":
$7E0C24-$7E0C25/$7E0E7C-$7E0E7D (Song Scrolling End Position) (Little Endian) $0000= Song Scrolling Irrelevant $0001= Shortest End $FFFF= Longest End
$7E0C26-$7E0C27/$7E0E7E-$7E0E7F (Loop): (Little Endian) $0000=No Nonzero=Yes
$7E0C28/$7E0E80 (Tempo Slider Position (to the right)) (VISUAL ONLY)
$7E0C29/$7E0E81 (Tempo Slider Position additional multiplier) (VISUAL ONLY)
$7E0C2A/$7E0E82 (???)
$7E0C2B/$7E0E83 (???)
$7E0C2C/$7E0E84 (???)
$7E0C2D/$7E0E85 (Tempo) 01=Slowest FF=Fastest 00=Pause
$7E0C2E/$7E0E86 (???)
$7E0C2F/$7E0E87 (???)
$7E0C30/$7E0E88 (???)
$7E0C31/$7E0E89 (???)
$7E0C32/$7E0E8A (Time Signature ($00 = 3/4 $01 = 4/4))
$7E0C33/$7E0E8B (???)
$7E0C34/$7E0E8C (???)
$7E0C35/$7E0E8D (???)
$7E0C36/$7E0E8E (???)
$7E0C37/$7E0E8F (???)
$7E0C38/$7E0E90 (???)
$7E0C39/$7E0E91 (???)
$7E0C3A/$7E0E92 (???)
$7E0C3B/$7E0E93 (???)
ARAM address locations of interest:
(Information provided from HertzDevil)
$254C - $2569: SPC sample indices.
$256A - $2587: Instrument volumes, FF is maximum.
$2588 - $25A5: Instrument panning. The 6 lower bytes determine the pan direction from 0 (right) to 20 (left); bit 6/7 inverts right/left output respectively. (The N-SPC driver, including its early version in Super Mario World, also does the same thing.)
$25A6 - $25C3: Relative offsets into the following note table.
$25C4 - $2686: 15 N-SPC note tables, the lowest and highest notes are 80 and D3 respectively.
$2687 - $26A4: Fine pitch, FF denotes an upward semitone. There is no downward detune.
$26A5 - $26C2: maximum note duration in number of ticks.
Song Data Format (for RAM):
6 byte song data stream offsets:
$00 = Channel 1 note
$01 = Channel 1 instrument
$02 = Channel 2 note
$03 = Channel 2 instrument
$04 = Channel 3 note
$05 = Channel 3 instrument
... repeat up to 96 times "legally" for 576 bytes.
NOTES/FREQUENCIES: B1 ($01) lowest -> G3 ($0D) highest
Highest w/o sharps/flats (other values leak into other notes/instruments and change relative icon vertical positioning in strange fashion)
INSTRUMENTS:
(Standard Instruments; all samples are monaural unless otherwise noted.)
Mario ($00) Xylophone
Toadstool ($01) Tom drum (sample is stereo; left-oriented.)
Yoshi ($02) Yoshi noise
Star ($03) Musicbox tine
Flower ($04) Trumpet
Gameboy ($05) Pulsewave
Dog ($06)
Cat ($07)
Pig ($08)
Swan ($09) Orchestra hit
Baby ($0A)
Plane ($0B) Cello
Boat ($0C) Conga drum ($01-$06 notes D2, F2, G2, A2, A#3, C3) Cymbals ($07-$0D C2, F2, B2, F3, A3, C4, F4) (samples are stereo; right-oriented.)
Car ($0D) Organ
Heart ($0E) Doublebass
(Unused Instruments)
Blank ($0F) SFX ($00 null, $01 crash (low), $02 click (high), $03 cuica, $04 groan, $05 squeak (low), $06-$0A clicks, $0B squeak (high), $0C crash (high), $0D click (need more research to note frequencies.))
Mario Hand ($10) Xylophone
Green Hand ($11) Tom drum
Yellow Point Hand ($12) Yoshi
No Passing Signs ($13) Musicbox tine
No Passing Signs ($14) Trumpet
Oval Pointer ($15) Pulsewave
Oval Pointer/No Passing ($16) Dog
No Passing ($17) Cat
Song End (Yellow) Icon ($18) Pig
Song End (Orange) Icon ($19) Orchestra Hit
Rockets ($1A) Baby
Rockets ($1B) Cello
Rockets ($1C) "Boat" Percussion
Rockets ($1D) Organ
Rockets ($1E) Doublebass
Rockets ($1F) SFX
($20-$7F are repeats of $00-$1F)
Sustain/No Instrument ($80-$FF) (Frequency settings ignored)
Summary: "Positive" values are instruments; and "negative" values are sustain/null.
Other notes:
Two instances of sequence data and song properties data for Undo Dog.
Display and function values are separate.
576 bytes standard sequence data (Mario Paint)
24 bytes of song properties data (Mario Paint)
Mario Paint SRAM file is compressed.
Extended song data starts to crash the player at around $7E26EE.
ZSNES (current public version) does not save SRAM files properly.
BS Mario Paint versions use the control pad instead of the mouse.
Instrument tuning details:
(Information according to Jangler)
each instrument has 16 possible pitches—the B1 through G3 (in b00daw's terminology) that you can normally place, as well as placeholders for A1, A3, and B3. normally these placeholders are a G2, B2, and C3 respectively, but a few instruments have notes there which are not ordinarily accessible:
mushroom: B3 is between C3 and D3 (nonlinear)
yoshi: A1 is C1
star: A3 is A♯0, B3 is B0
cat: A1 is D4, B3 is B3
baby: A1 is G4, A3 is B3, B3 is D♯1
boat: A3 is very high, B3 is between E3 and F3 (nonlinear)
heart: A1 is C1
and while i'm thinking about it, here are the pitches of the "non-melodic" instruments, ascending from B1 to G3. i'm going to use flats and sharps fairly arbitrarily here.
the mushroom ascends in increasing intervals:
F G♭ A♭ B♭ D♭ F A♭ B E♭ G♭ D♭ G♭ G♭
the pig is tuned a minor third higher than the rest of the instruments:
D E♭ F G A♭ B♭ C D E♭ G A♭ B♭
edit: today i think it sounds more like a whole step.
C♯ D E F♯ G A B C♯ D E F♯ G A
the baby instrument plays two notes, the first of which is tuned a minor second lower than the other instruments:
A♯ B C♯ D♯ E F♯ G♯ A♯ B C♯ D♯ E F♯
the second note is a major sixth above the first:
G A♭ B♭ C D♭ E♭ F G A♭ B♭ C D♭ E♭
boat is wacky. the first couple of cymbals sound melodic to me but the rest don't and the rest also do:
D♯ F♯ G♯ A♯ B C♯ | C♯ F♯ C♯ E G♯ B D
(yoshi is tuned about right)
ARAM sample values:
$00 = Boat? (Drumkit)
$01 = Toad (Kick/Tom)
$02 = Cat (Meow)
$03 = Dog (Bark)
$04 = Star (Music Box)
$05 = Car(?) (Organ?)
$06 = Plane (String)
$07 = Pig
$08 = Game Boy (Pulsewave)
$09 = Swan (Orchestra)
$0A = Heart (Bass)
$0B = Synth?
$0C = Flower (Horn)
$0D = Mario (Xylophone)
$0E = Baby
$0F = Yoshi
$10 = Boat (Hat)
$11 = Synth?
$12 = Click
$13 = Undo Dog (Groan)
$14 = Synth?
$15 = Synth?
$16 = Eraser (Squeak)
$17 = Silence (Note cut)
$18 = Warble Horn
$19 = Distortion Overdrive
$1A = Warble Wind Instrument
$1B = Deturned "Asian" Sound
$1C = Baby (Quicker?)
$1D = Baby (Quicker/Softer?)
$1E = Baby (Quicker?)
$1F = Squeaky Percussion
$20 = Silence (Note cut)
$21 = Yoshi (Second half)
$22 = Silence (Note cut)
$23 = Silence (Note cut)
$24 = Silence (Note cut)
$25 = Boat (Woodblock)
$26 = Percussion (Clack)
$27 = Percussion (Clack)
$28 = Percussion (Clack)
$29 = Percussion (Clack)
$2A = Percussion (Tom) (Alt tuning)
$2B = Silence (Note cut)
$2C = Distortion Overdrive
$2D = Wind Percussion?
$2E = Silence (Note cut)
$2F = Silence (Note cut)
$30 = Percussion (Clack)
$31 = Percussion (Clack)
$32 = Percussion (Clack)
$33 = Percussion (Clack)
$34 = Percussion (Clack)
$35 = Silence (Note cut)
$36 = Silence (Note cut)
$37 = Silence (Note cut)
$38 = Silence (Note cut)
$39 = Silence (Note cut)
$3A = Silence (Note cut)
$3B = Percussion (Clack)
$3C = Percussion (Clack)
$3D = Percussion (Clack)
$3E = Percussion (Clack)
$3F = Percussion (Clack)
$40 = Silence (Note cut)
$41 = Silence (Note cut)
$42 = Silence (Note cut)
$43 = Silence (Note cut)
$44 = Silence (Note cut)
$45 = Percussion (Tom) (Alt tuning)
$46 = Percussion (Clack)
$47 = Percussion (Clack)
$48 = Percussion (Clack)
$49 = Percussion (Clack)
$4A = Silence (Note cut)
$4B = Silence (Note cut)
$4C = Silence (Note cut)
$4D = Silence (Note cut)
$4E = Silence (Note cut)
$4F = Silence (Note cut)
$50 = Percussion (Clack)
$51 = Percussion (Clack)
$52 = Percussion (Clack)
$53 = Percussion (Clack)
$54 = Percussion (Clack)
$55 = Silence (Note cut)
$56 = Silence (Note cut)
$57 = Percussion (Tom) (Alt tuning)
$58 = Percussion (Kit) (Alt tuning)
$59 = Silence (Note cut)
$5A = Click
$5B = Percussion (Kit) (Alt tuning)
$5C = Percussion (Tom) (Alt tuning)
$5D = Click (Alt tuning)
$5E = Silence (Note cut)
$5F = Percussion (Kit) (Alt tuning)
$60 = Cymbals (Alt tuning)
$61 = Cymbals (Alt tuning)
$62 = Bongos (Alt tuning)
$63 = Bongos (Quiet)
$64 = Silence (Note cut)
$65 = Silence (Note cut)
$66 = Percussion (Kit) (Alt tuning)
$67 = Silence (Note cut)
$68 = Silence (Note cut)
$69 = Percussion (Kit) (Alt tuning)
$6A = Semi-silent Glitchy High-pitched
$6B = Silence (Note cut)
$6C = Percussion (Kit) (Alt tuning)
$6D = Percussion (Kit) (Alt tuning)
$6E = Percussion (Bongo) (Alt tuning)
$6F = Clicks and Dropping Noise?
$70 = Percussion (Kit) (Alt tuning)
$71 = Cymbal Noisy?
$72 = Percussion (Kit) (Alt tuning)
$73 = Percussion (Bongo) (Alt tuning)
$74 = Percussion (Bongo) (Alt tuning)
$75 = Undo Dog (Groan)
$76 = Percussion (Bongo) (Alt tuning)
$77 = Silence (Note Cut)
$78 = Silence (Note Cut)
$79 = Goofy Squeak Percussion
$7A = Semi-silent percussion
$7B = Percussion (Bongo) (Alt tuning)
$7C = Undo Dog (Alt tuning)
$7D = Percussion (Kit) (Alt tuning)
$7E = Percussion (Kit) (Quiet)
$7F = Percussion (Kit) (Alt tuning)
$80 = Cymbals
$81 = Percussion (Kit) (Alt tuning)
$82 = Silence (Note cut)
$83 = Undo Dog (Alt tuning)
$84 = Silence (Note cut)
$85 = Percussion (Kit) (Alt tuning)
$86 = Goofy Percussion
$87 = Percussion (Kit) (Alt tuning)
$88 = Percussion (Kit) (Alt tuning)
$89 = Silence (Note cut)
$8A = Percussion (Kit) (Alt tuning)
$8B = Violin and Tuba
$8C = Silence (Note cut)
$8D = Silence (Note cut)
$8E = Percussion (Kit) (Alt tuning)
$8F = Glitchy Quiet Noisy
$90 = Silence (Note cut)
$91 = Percussion (Bongo) (Alt tuning)
$92 = Percussion (Kit) (Alt tuning)
$93 = Wineglass/Jug
$94 = Silence (Note cut)
$95 = Silence (Note cut)
$96 = Silence (Note cut)
$97 = Silence (Note cut)
$98 = Silence (Note cut)
$99 = Percussion (Bongo) (Alt tuning)
$9A = Backwards Creepy Sample
$9B = Silence (Note cut)
$9C = Silence (Note cut)
$9D = Silence (Note cut)
$9E = Silence (Note cut)
$9F = Silence (Note cut)
$A0 = Silence (Note cut)
$A1 = Cat (Meow)
$A2 = Percussion Kit
$A3 = Quiet Percussion
$A4 = Silence (Note cut)
$A5 = Silence (Note cut)
$A6 = Percussion Kit (etc)
$A7 = Percussino Kit (etc)
$A8 = Silence (Note cut)
$A9 = Percussion Kit (etc)
$AA = Silence (Note cut)
$AB = Percussions (Star tuning)
$AC = Silence (Note cut)
$AD = Silence (Note cut)
$AE = Silence (Note cut)
$AF = Percussion Kit (etc)
$B0 = Silence (Note cut)
$B1 = Cat (Quiet)
$B2 = Silence (Note cut)
$B3 = Percussion Kit (etc)
$B4 = Silence (Note cut)
$B5 = Silence (Note cut)
$B6 = Silence (Note cut)
$B7 = Silence (Note cut)
$B8 = Percussion Kit (etc)
$B9 = Silence (Note cut)
$BA = Percussion Kit (Clack) (Star tuning)
$BB = Percussion Kit (High Bongo) (Star tuning)
$BC = Cat (Star tuning)
$BD = Dog (Star tuning)
$BE = Star (Star tuning)
$BF = Glitchy car (Star tuning)
$C0 = Harpsicord/Guitar (Star tuning)
$C1 = Pig (Star tuning)
$C2 = Gameboy (alt?) (Star tuning)
$C3 = Swan (Star tuning)
$C4 = Heart (alt tuning)
$C5 = Car (Star tuning)
$C6 = Flower (Star tuning)
$C7 = Mario (Star tuning)
$C8 = Baby (Star tuning)
$C9 = High Yoshi (Star tuning)
$CA = Cymbals (Star tuning)
$CB = Car (Star tuning)
$CC = Click (Star tuning)
$CD = Undo Dog (Star tuning)
$CE = Car (Star tuning)
$CF = Car (Star tuning)
$D0 = Eraser (Star tuning)
$D1 = Silence (Note cut)
$D2 = Tuba (Star tuning)
$D3 = Distorted Overdrive (Star tuning)
$D4 = Warble Organ (Star tuning)
$D5 = Asian Bagpipes (Star tuning)
$D6 = Baby (Part 2) (Star tuning)
$D7 = Baby (Part 1) (Star tuning)
$D8 = Baby (Part 2) (Lower) (Star tuning)
$D9 = Squeaky Percussion (Star tuning)
$DA = Silence (Note cut)
$DB = Yoshi (Part 1 fast?) (Star tuning)
$DC = Silence (Note cut)
$DD = Silence (Note cut)
$DE = Silence (Note cut)
$DF = Bongos (Alt tuning)
$E0 = Clacks (Alt tuning)
$E1 = Clacks (Alt tuning)
$E2 = Clacks (Alt tuning)
$E3 = Clacks (Alt tuning)
$E4 = Clacks (Star tuning)
$E5 = Silence (Note cut)
$E6 = White Noise Mess (Star tuning)
$E7 = Quiet Bongos (Alt tuning)
$E8 = Silence (Note cut)
$E9 = Silence (Note cut)
$EA = Clacks (Alt tuning)
$EB = Clacks (Alt tuning)
$EC = Clacks (Alt tuning)
$ED = Clacks (Alt tuning)
$EE = Clacks (Alt tuning)
$EF = Silence (Note cut)
$F0 = Silence (Note cut)
$F1 = Silence (Note cut)
$F2 = Silence (Note cut)
$F3 = Silence (Note cut)
$F4 = Silence (Note cut)
$F5 = Clacks (Alt tuning)
$F6 = Clacks (Alt tuning)
$F7 = Clacks (Alt tuning)
$F8 = Clacks (Alt tuning)
$F9 = Clacks (Alt tuning)
$FA = Silence (Note cut)
$FB = Silence (Note cut)
$FC = Silence (Note cut)
$FD = Silence (Note cut)
$FE = Silence (Note cut)
$FF = Bongos (Alt tuning)
$254C - $2569 in ARAM respectively goes LEFT to RIGHT of the Mario Paint sequencer instruments Mario > Heart; plus another 15 not currently understood. Will do more research.
Jangler has made an incomplete but working IT (tracker module) to SNES9x savestate python script for creation of songs given our collective research.
(For the record, he would not like to be contacted regarding this work, but you should be able to feel free to expand the project if you so choose.)