thinking outside the cartridge
jake "ferris" taylor
hello everyone
love your process
FIRST THINGS FIRST
what does a snes look like?
AUDIO
MAIN SYSTEM
VIDEO
CPU
128kb RAM
CPU
64kb RAM
DSP
PPU
64kb VRAM
512b CGRAM
544b OAM
CARTRIDGE
1-4MB ROM
AUDIO
MAIN SYSTEM
VIDEO
CPU
128kb RAM
CPU
64kb RAM
DSP
PPU
64kb VRAM
512b CGRAM
544b OAM
CARTRIDGE
1-4MB ROM
DMA!!
brief intro to oldschool coding
main() { printf("Hello World"); }
public void Render(int width, int height, Sync sync, double time)
{
GL.ClearColor(Color.FromArgb(0, 0, 68));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.LoadIdentity();
GL.Translate(0.0f, 0.0f, -25.0f);
var color = Color.FromArgb(113, 232, 81);
Helpers.Bar(color, 0.0f, -1.0f, 3.0f, 0.5f);
Helpers.Bar(color, 0.0f, 0.0f, 3.0f, 0.5f);
Helpers.Bar(color, 0.0f, 1.0f, 3.0f, 0.5f);
}
; x = voice data offset (trashes y)
ReadPatternByte:
mov a, VoiceState::CompType + x
bne +
; Uncompressed
call ReadNextByte
ret
; Rle (run length, symbol)
+: mov a, VoiceState::CompParam1 + x
bne +
; Start next run
call ReadNextByte
push a
call ReadNextByte
mov VoiceState::CompParam2 + x, a
pop a
+: ; Read next byte from run
dec a
mov VoiceState::CompParam1 + x, a
mov a, VoiceState::CompParam2 + x
ret
; x = voice data offset (trashes y)
ReadNextByte:
mov a, VoiceState::PatternAddrLow + x
mov CurrentByteAddrLow, a
clrc
adc a, #$01
mov VoiceState::PatternAddrLow + x, a
mov a, VoiceState::PatternAddrHigh + x
mov CurrentByteAddrHigh, a
adc a, #$00
mov VoiceState::PatternAddrHigh + x, a
mov y, #$00
mov a, [CurrentByteAddr] + y
ret
; a = note, x = voice data offset
SetNote:
asl a
mov y, a
mov a, !MusicData.PitchTable + y
mov VoiceState::PitchLow + x, a
inc y
mov a, !MusicData.PitchTable + y
mov VoiceState::PitchHigh + x, a
ret
; a = instrument number
LoadInstrumentDataAddr:
push x
dec a
asl a
mov x, a
mov a, !MusicData.InstrumentTable + x
mov CurrentInstrAddrLow, a
inc x
mov a, !MusicData.InstrumentTable + x
mov CurrentInstrAddrHigh, a
pop x
ret
EffectArpeggio:
pop x
mov y, #$00
mov a, VoiceState::EffectParam2 + x
cmp a, #$01
bne ++++
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
++++: cmp a, #$02
bne ++++
mov a, VoiceState::EffectParam1 + x
mov y, a
++++: mov a, y
and a, #$0f
clrc
adc a, VoiceState::Note + x ; TODO: Handle overflows
call SetNote
mov a, VoiceState::EffectParam2 + x
inc a
cmp a, #$03
bcc ++++
mov a, #$00
++++: mov VoiceState::EffectParam2 + x, a
jmp EffectEnd
EffectPitchUp:
pop x
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
and a, #$f0
clrc
adc a, VoiceState::PitchLow + x
mov VoiceState::PitchLow + x, a
mov a, y
and a, #$0f
adc a, VoiceState::PitchHigh + x
mov VoiceState::PitchHigh + x, a
jmp EffectEnd
EffectPitchDown:
pop x
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
and a, #$f0
mov FxWork1, a
mov a, VoiceState::PitchLow + x
setc
sbc a, FxWork1
mov VoiceState::PitchLow + x, a
mov a, y
and a, #$0f
mov FxWork1, a
mov a, VoiceState::PitchHigh + x
sbc a, FxWork1
mov VoiceState::PitchHigh + x, a
jmp EffectEnd
CHRONOLOGY
1991
childhood
yes i listened to the chrono trigger soundtrack on repeat while preparing this
~2000
~2004
~2008-2011
kickassembler
// Execute macro
:ClearScreen($0400,$20) // Since they are encapsulated in a scope
:ClearScreen($4400,$20) // the two resulting loop labels don’t
// interfere
// Define macro
.macro ClearScreen(screen,clearByte) {
lda #clearByte
ldx #0
Loop: // The loop label can’t be seen from the outside
sta screen,x
sta screen+$100,x
sta screen+$200,x
sta screen+$300,x
inx
bne Loop
}
~2008-2011
November 2011
gameboy demo workflow
demon blood
Assembler round 2
MUSIC
official tools
xmsnes
make my own!
be rad
how to do a demo in 3 weeks
video
video compression
image sequence
delta encoding
0 1 2 3 4 5 6 7
0 1 1 1 1 1 1 1
0 1
temporal delta encoding
representing video on snes
virtual machine
LoadPaletteData address length data LoadVramData address length data
EndOfFrame
EndOfTransmission
LoadPaletteData 0x00 0x16 [...] LoadVramData 0x2000 0x0800 [...] EndOfFrame
nu
- Heavily inspired by/ripped off of beeple's four.color.process series
refining the tech
then it hit me
cracking the code
full control
ideal snes coding environment
- I could program in F#
- Using pure, immutable data
- Composing with code and syncing with Ableton Live
then it hit me ...again
opcodes!!
any.
way.
i.
want.
smash it
conclusion
what's next
thinking outside the cartridge
thank you!
Thinking Outside the Cartridge
By yupferris
Thinking Outside the Cartridge
Modern Ideas Applied to Archaic Devices
- 1,532