a lot of refactors, and waffling on audio engines.
This commit is contained in:
parent
35bb4dd60b
commit
f3a852edc3
@ -285,6 +285,8 @@ TheWorld:
|
||||
ld hl, MY_OAM
|
||||
; go through MY_OAM and, for any which aren't still visible, set their
|
||||
; y value to zero.
|
||||
; this could probably be rewritten as a simpler lookup table if we rewrote it
|
||||
; using jp hl and pointer math rather than explicitly listing all the possibilities
|
||||
.cleanUpLoop
|
||||
ld a, [hl] ; a is the y value and hl points to y
|
||||
: cp a, (2+1+5)*8
|
||||
|
21
Async.inc
21
Async.inc
@ -1,15 +1,13 @@
|
||||
; async variables somewhere in RAM
|
||||
def vAsyncAF equ ASYNC_VARS_START
|
||||
def vAsyncHL EQU vAsyncAF+2
|
||||
def vAsyncDE EQU vAsyncHL+2
|
||||
def vAsyncBC equ vAsyncDE+2
|
||||
def vAsyncPC equ vAsyncBC+2
|
||||
def vAsyncNext equ vAsyncPC+2
|
||||
def vAsyncAfter equ vAsyncNext+2
|
||||
def vAsyncProgress equ vAsyncAfter+2
|
||||
def vAsyncMainSP equ vAsyncProgress+2
|
||||
def vAsyncThreadSP equ vAsyncMainSP+2
|
||||
|
||||
PUSHS "Async Variables", WRAM0[ASYNC_VARS_START]
|
||||
vAsyncAF: dw
|
||||
vAsyncHL: dw
|
||||
vAsyncDE: dw
|
||||
vAsyncBC: dw
|
||||
vAsyncPC: dw
|
||||
vAsyncMainSP: dw
|
||||
vAsyncThreadSP: dw
|
||||
POPS
|
||||
; canonical ordering to push should be: AF, BC, DE, HL,
|
||||
|
||||
def ASYNC_STACK_TOP equ $ffc0
|
||||
@ -18,6 +16,7 @@ def ASYNC_STACK_TOP equ $ffc0
|
||||
; second value is the destination of the async call, at ffbc = ffbe-2 = ffc0-2-2
|
||||
def ASYNC_THREAD_CALL equ ASYNC_STACK_TOP - 2 - 2
|
||||
|
||||
; timing for async execution, in scanlines
|
||||
def SAFE_ASYNC_START EQU 148
|
||||
def SAFE_ASYNC_END EQU 153
|
||||
|
||||
|
853
Audio.inc
853
Audio.inc
@ -1,347 +1,534 @@
|
||||
PUSHS "Sound Variables", WRAM0[AUDIO_VARS_START]
|
||||
ordersStart: dw
|
||||
println "orders start is ", ordersStart
|
||||
ordersLength: db
|
||||
|
||||
|
||||
; audio player state
|
||||
currentOrderNumber: db
|
||||
currentRowNumber: db
|
||||
println "currentRowNumber is ", currentRowNumber
|
||||
currentTickNumber: db
|
||||
currentPattern: dw
|
||||
println "current pattern is ", currentPattern
|
||||
audioReadHead: dw
|
||||
|
||||
AUDIO_VARIABLES_BEGIN:
|
||||
|
||||
speed: db
|
||||
|
||||
macro channel ; macro to define all the channell data in parallel
|
||||
channel_\1_note: db
|
||||
channel_\1_duty: db
|
||||
channel_\1_volume: db
|
||||
channel_\1_slide: db
|
||||
channel_\1_arp: db
|
||||
channel_\1_pan: db
|
||||
channel_\1_vibrato: db
|
||||
channel_\1_trigger: db
|
||||
endm
|
||||
|
||||
channel 1
|
||||
channel 2
|
||||
channel 3
|
||||
channel 4
|
||||
|
||||
println "channel 1 note is ", channel_1_note
|
||||
AUDIO_VARIABLES_END:
|
||||
POPS
|
||||
|
||||
SoundSetup:
|
||||
ld a, LOW(gbtarottheme)
|
||||
ld [ordersStart], a
|
||||
ld a, HIGH(gbtarottheme)
|
||||
ld [ordersStart+1], a
|
||||
ld a, BANK(gbt_play)
|
||||
ld [rROMB0], a
|
||||
|
||||
ld a, 0
|
||||
ld [currentOrderNumber], a
|
||||
ld [currentRowNumber], a
|
||||
ld [currentTickNumber], a
|
||||
ld de,pythonrangetest
|
||||
ld bc,BANK(instr_test_data)
|
||||
ld a,$05
|
||||
call gbt_play ; Play song
|
||||
|
||||
ld a, $FF
|
||||
ld [currentRowNumber], a
|
||||
|
||||
ld a, [ordersStart]
|
||||
ld l, a
|
||||
ld a, [ordersStart+1]
|
||||
ld h, a
|
||||
inc hl
|
||||
|
||||
ld a, [hl+]
|
||||
ld [currentPattern], a
|
||||
ld [audioReadHead], a
|
||||
ld a, [hl+]
|
||||
ld [currentPattern+1], a
|
||||
ld [audioReadHead+1], a
|
||||
|
||||
ld hl, ZEROES
|
||||
ld de, AUDIO_VARIABLES_BEGIN
|
||||
ld bc, AUDIO_VARIABLES_END - AUDIO_VARIABLES_BEGIN
|
||||
call CopyRange
|
||||
|
||||
ld a, 6
|
||||
ld [speed], a
|
||||
|
||||
ld a, %1000_1111
|
||||
ld [rNR52], a
|
||||
ld a, $ff
|
||||
ld [rNR51], a
|
||||
ld a, $11
|
||||
ld [rNR50], a
|
||||
ld a, 1
|
||||
call gbt_loop
|
||||
|
||||
ld a, [cvCardBank]
|
||||
ld [rROMB0], a
|
||||
ret
|
||||
|
||||
SoundUpdate:
|
||||
ld a, [speed]
|
||||
ld b, a
|
||||
ld a, [currentTickNumber]
|
||||
inc a
|
||||
call ArrayClampLoopingB
|
||||
ld [currentTickNumber], a
|
||||
ld a, BANK(gbt_play)
|
||||
ld [rROMB0], a
|
||||
|
||||
cp a, 0
|
||||
jp nz, .doneAllPackets ; if we're not zero, then just update the things
|
||||
call gbt_update
|
||||
|
||||
ld b, 64
|
||||
ld a, [currentRowNumber]
|
||||
inc a
|
||||
call ArrayClampLoopingB
|
||||
ld [currentRowNumber], a
|
||||
|
||||
cp a, 0
|
||||
jp nz, :+ ; if the new row number is zero, then we go to the next pattern.
|
||||
ld a, AUDHIGH_RESTART
|
||||
ld [rNR14], a
|
||||
|
||||
|
||||
; TODO: update for song orders
|
||||
ld a, [currentPattern]
|
||||
ld [audioReadHead], a
|
||||
ld a, [currentPattern+1]
|
||||
ld [audioReadHead+1], a
|
||||
:
|
||||
ld a, [audioReadHead]
|
||||
ld l, a
|
||||
ld a, [audioReadHead+1]
|
||||
ld h, a
|
||||
|
||||
ld a, [currentRowNumber]
|
||||
ld b, a
|
||||
ld a, [hl+]
|
||||
and a, $F0
|
||||
cp a, 0
|
||||
ret nz
|
||||
ld a, [hl+]
|
||||
cp a, b
|
||||
jp nz, .doneAllPackets ; return if the current row doesn't equal the row we're looking at
|
||||
|
||||
; else we're looking at packets
|
||||
.packetExamine
|
||||
ld a, l
|
||||
ld [audioReadHead], a
|
||||
ld a, h
|
||||
ld [audioReadHead+1], a
|
||||
|
||||
ld d, h
|
||||
ld e, l
|
||||
|
||||
ld hl, channel_1_note
|
||||
|
||||
ld a, [de]
|
||||
and a, $0F
|
||||
cp a, 1
|
||||
jp nz, :+
|
||||
ld hl, channel_1_note
|
||||
: cp a, 2
|
||||
jp nz, :+
|
||||
ld hl, channel_2_note
|
||||
: cp a, 3
|
||||
jp nz, :+
|
||||
ld hl, channel_3_note
|
||||
: cp a, 4
|
||||
jp nz, :+
|
||||
ld hl, channel_4_note
|
||||
:
|
||||
|
||||
ld a, [de]
|
||||
and a, $F0 ; grab the top nibble of [hl], which holds the effect.
|
||||
|
||||
; if nibble is zero, then update our read head (already done) and return.
|
||||
cp a, $00
|
||||
jp z, .doneAllPackets
|
||||
|
||||
ld bc, channel_1_note - channel_1_note
|
||||
cp a, $10
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_volume - channel_1_note
|
||||
cp a, $20
|
||||
jp z, .updateVolume
|
||||
|
||||
ld bc, channel_1_duty - channel_1_note
|
||||
cp a, $30
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_pan - channel_1_note
|
||||
cp a, $40
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_arp - channel_1_note
|
||||
cp a, $50
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_vibrato - channel_1_note
|
||||
cp a, $60
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_slide - channel_1_note
|
||||
cp a, $70
|
||||
jp z, .updateValue
|
||||
|
||||
ld bc, channel_1_volume - channel_1_note
|
||||
cp a, $80
|
||||
jp z, .noteCut
|
||||
|
||||
cp a, $90
|
||||
jp z, .patternJump
|
||||
|
||||
cp a, $a0
|
||||
jp z, .breakSetStep
|
||||
|
||||
cp a, $b0
|
||||
jp z, .setSpeed
|
||||
|
||||
cp a, $c0
|
||||
jp z, .event
|
||||
; and now a bunch of code for handling all those cases!
|
||||
|
||||
.updateVolume:
|
||||
inc de
|
||||
add hl, bc
|
||||
ld a, 0
|
||||
ld [channel_1_trigger], a
|
||||
ld a, [hl]
|
||||
cp a, 0
|
||||
jp nz, :+
|
||||
; if the volume is zero to start with,
|
||||
; and the new volume is nonzero,
|
||||
ld a, [de]
|
||||
; set the trigger flag
|
||||
cp a, 0
|
||||
jp z, :+
|
||||
ld a, AUDHIGH_RESTART
|
||||
ld [channel_1_trigger], a
|
||||
:
|
||||
|
||||
ld a, [de]
|
||||
ld [hl], a
|
||||
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
|
||||
.updateValue:
|
||||
inc de
|
||||
|
||||
add hl, bc
|
||||
: ld a, [de]
|
||||
ld [hl], a
|
||||
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
|
||||
jp .packetExamine
|
||||
|
||||
.noteCut:
|
||||
inc de
|
||||
add hl, bc
|
||||
|
||||
ld [hl], 0
|
||||
|
||||
ld a, AUDHIGH_RESTART
|
||||
ld [channel_1_trigger], a
|
||||
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
.patternJump:
|
||||
; TODO
|
||||
inc de
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
.breakSetStep:
|
||||
; TODO
|
||||
inc de
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
.setSpeed:
|
||||
inc de
|
||||
ld a, [de]
|
||||
ld [speed], a
|
||||
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
.event:
|
||||
; TODO
|
||||
inc de
|
||||
inc de
|
||||
ld h, d
|
||||
ld l, e
|
||||
jp .packetExamine
|
||||
|
||||
|
||||
.doneAllPackets:
|
||||
call Channel_1_Update
|
||||
call Channel_2_Update
|
||||
call Channel_3_Update
|
||||
call Channel_4_Update
|
||||
ld a, [cvCardBank]
|
||||
ld [rROMB0], a
|
||||
ret
|
||||
|
||||
|
||||
Channel_1_Update:
|
||||
ld a, [channel_1_duty]
|
||||
or a, $0a
|
||||
ld [rNR11], a
|
||||
|
||||
ld a, [channel_1_volume]
|
||||
sla a
|
||||
sla a
|
||||
sla a
|
||||
sla a
|
||||
and a, $F0
|
||||
ld [rNR12], a
|
||||
|
||||
ld a, [channel_1_note]
|
||||
ld hl, note_periods
|
||||
ld b, 0
|
||||
ld c, a
|
||||
add hl, bc
|
||||
add hl, bc ; double width values
|
||||
|
||||
ld a, [hl+]
|
||||
ld [rNR13], a
|
||||
; File created by mod2gbt
|
||||
; s3m2gbt modified by shoofle to output rgbds-compatible asm files
|
||||
SECTION "pythonrangetest_0", ROMX
|
||||
pythonrangetest_0:
|
||||
db $BF,$00,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$01,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$02,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$03,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$04,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$05,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$06,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$07,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$08,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$09,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$10,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$11,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$12,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$13,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$14,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$15,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$16,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$17,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$18,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$19,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
SECTION "pythonrangetest_1", ROMX
|
||||
pythonrangetest_1:
|
||||
db $BF,$20,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$21,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$22,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$23,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$24,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$25,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$26,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$27,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$28,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$29,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$30,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$31,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$32,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$33,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$34,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$35,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$36,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$37,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$38,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$39,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
SECTION "pythonrangetest_2", ROMX
|
||||
pythonrangetest_2:
|
||||
db $BF,$40,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$41,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$42,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$43,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$44,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$45,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$46,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$47,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
pythonrangetest_init_state:
|
||||
db 0x01,0x06,0x02,0x11,0x22,0x44,0x88,0x00,
|
||||
|
||||
SECTION "pythonrangetest", ROMX
|
||||
pythonrangetest:
|
||||
db BANK(pythonrangetest_0)
|
||||
dw pythonrangetest_0
|
||||
|
||||
db BANK(pythonrangetest_1)
|
||||
dw pythonrangetest_1
|
||||
|
||||
db BANK(pythonrangetest_2)
|
||||
dw pythonrangetest_2
|
||||
|
||||
db $00
|
||||
dw $0000
|
||||
|
||||
|
||||
SECTION "instr_test_0", ROMX
|
||||
instr_test_0:
|
||||
DB $98, $1F, $20, $20, $4A, $07
|
||||
DB $2F, $00, $00, $20
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $98, $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $98, $3F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $98, $0F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $2F, $00, $00, $00
|
||||
DB $20, $00, $98, $10, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $11, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $12, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $13, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
|
||||
SECTION "instr_test_1", ROMX
|
||||
instr_test_1:
|
||||
DB $00, $00, $98, $14, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $15, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $16, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $98, $17, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $21, $00
|
||||
DB $00, $00, $20, $80, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $81, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $82, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $83, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
|
||||
SECTION "instr_test_2", ROMX
|
||||
instr_test_2:
|
||||
DB $00, $00, $00, $84, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $85, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $86, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $87, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $88, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $89, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $8A, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $8B, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
|
||||
SECTION "instr_test_3", ROMX
|
||||
instr_test_3:
|
||||
DB $00, $00, $00, $8C, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $8D, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $8E, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $8F, $0F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $2F
|
||||
DB $00, $00, $00, $20
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
DB $00, $00, $00, $00
|
||||
|
||||
SECTION "instr_test_data", ROM0
|
||||
instr_test_data::
|
||||
DB BANK(instr_test_0)
|
||||
DW instr_test_0
|
||||
DB BANK(instr_test_1)
|
||||
DW instr_test_1
|
||||
DB BANK(instr_test_2)
|
||||
DW instr_test_2
|
||||
DB BANK(instr_test_3)
|
||||
DW instr_test_3
|
||||
DB $00
|
||||
DW $0000
|
||||
|
||||
|
||||
ld a, [channel_1_trigger]
|
||||
or a, [hl]
|
||||
or a, AUDHIGH_LENGTH_OFF
|
||||
ld [rNR14], a
|
||||
|
||||
ld a, 0
|
||||
ld [channel_1_trigger], a
|
||||
ret
|
||||
|
||||
Channel_2_Update:
|
||||
Channel_3_Update:
|
||||
Channel_4_Update:
|
||||
ret
|
||||
|
||||
note_periods:
|
||||
dw 44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986, ; C3 to B3
|
||||
dw 1046,1102,1155,1205,1253,1297,1339,1379,1417,1452,1486,1517, ; C4 to B4
|
||||
dw 1546,1575,1602,1627,1650,1673,1694,1714,1732,1750,1767,1783, ; C5 to B5
|
||||
dw 1798,1812,1825,1837,1849,1860,1871,1881,1890,1899,1907,1915, ; C6 to B6
|
||||
dw 1923,1930,1936,1943,1949,1954,1959,1964,1969,1974,1978,1982, ; C7 to B7
|
||||
dw 1985,1988,1992,1995,1998,2001,2004,2006,2009,2011,2013,2015 ; C8 to B8
|
||||
|
||||
INCLUDE "theme.inc"
|
||||
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
; CARD_HELPER_VARS_START defines the beginning of the $100 bytes set aside for system usage
|
||||
def cvCardBank equ 0
|
||||
def cvCardAddress equ 1 ; location of the current card's struct
|
||||
PUSHS "Card Helper Vars", WRAM0[CARD_HELPER_VARS_START]
|
||||
cvCardBank: db
|
||||
cvCardAddress: dw
|
||||
POPS
|
||||
|
||||
LoadCardData:
|
||||
LoadCardDataAsync:
|
||||
@ -33,14 +35,14 @@ LoadCardDataAsync:
|
||||
add hl, bc ; triple add bc entries are bank, addr, addr
|
||||
|
||||
ld a, [hl+]
|
||||
ld [CARD_HELPER_VARS_START + cvCardBank], a
|
||||
ld [cvCardBank], a
|
||||
ld [rROMB0], a ; select the specified bank
|
||||
; follow the pointer we're looking at, and write it to cvCardAddress
|
||||
ld a, [hl+]
|
||||
ld [CARD_HELPER_VARS_START + cvCardAddress], a
|
||||
ld [cvCardAddress], a
|
||||
ld c, a
|
||||
ld a, [hl+]
|
||||
ld [CARD_HELPER_VARS_START + cvCardAddress + 1], a
|
||||
ld [cvCardAddress + 1], a
|
||||
ld b, a
|
||||
|
||||
ld h, b
|
||||
@ -82,9 +84,9 @@ LoadCardDataAsync:
|
||||
|
||||
call CopyTilesToMap
|
||||
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
|
||||
ld a, [cvCardAddress]
|
||||
ld l, a
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
|
||||
ld a, [cvCardAddress + 1]
|
||||
ld h, a ; hl now contains the address of the card data.
|
||||
|
||||
ld b, 0
|
||||
@ -110,9 +112,9 @@ LoadCardDataAsync:
|
||||
call CardInit
|
||||
|
||||
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
|
||||
ld a, [cvCardAddress]
|
||||
ld l, a
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
|
||||
ld a, [cvCardAddress + 1]
|
||||
ld h, a ; hl now contains the address of the card data.
|
||||
|
||||
ld b, 0
|
||||
@ -135,9 +137,9 @@ LoadCardDataAsync:
|
||||
call CopyRange
|
||||
|
||||
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
|
||||
ld a, [cvCardAddress]
|
||||
ld l, a
|
||||
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
|
||||
ld a, [cvCardAddress + 1]
|
||||
ld h, a ; hl now contains the address of the card data.
|
||||
|
||||
ld b, 0
|
||||
|
@ -1,18 +1,3 @@
|
||||
; variables for safe transfer async function
|
||||
DEF vSafeCopySource EQU $ff80
|
||||
DEF vSafeCopyDest EQU vSafeCopySource + 2
|
||||
DEF vSafeCopyCount EQU vSafeCopyDest + 2 ; check this for safe transfer being complete
|
||||
DEF vSafeCopyOriginalCount EQU vSafeCopyCount + 2
|
||||
; stash previous interrupt state before using the interrupts
|
||||
DEF vSafeCopyLYC EQU vSafeCopyOriginalCount + 2 ; stashes $FF45, the LYC register
|
||||
DEF vSafeCopySTAT EQU vSafeCopyLYC + 1 ; stashes $FF41, the STAT register
|
||||
DEF vSafeCopyInterrupt EQU vSafeCopySTAT + 1 ; stashes the previous LCD interrupt
|
||||
DEF vSafeCopyInterruptEnable EQU vSafeCopyInterrupt + 2 ; stashes $FFFF, which interrupts are enabled
|
||||
|
||||
DEF SAFE_TRANSFER_START EQU 145
|
||||
DEF SAFE_TRANSFER_END EQU 153
|
||||
|
||||
|
||||
CopyRange:
|
||||
CopyRangeUnsafe:
|
||||
; hl is source
|
@ -102,7 +102,6 @@ RandomUnderD: ; takes d as limit (inclusive)
|
||||
ret c
|
||||
jr .inOne
|
||||
|
||||
|
||||
SwapCards: ; takes hl as array, c and e as indices to swap (uses b and d)
|
||||
inc hl ; first element of array
|
||||
push hl ; save it for later
|
||||
@ -122,10 +121,3 @@ SwapCards: ; takes hl as array, c and e as indices to swap (uses b and d)
|
||||
add hl, bc
|
||||
ld [hl], d ; put old [hl+0e] in [hl+0c]
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
; screen variables shared with screencardread
|
||||
;DEF vPreviousCardIndex EQU VARIABLES_START
|
||||
|
||||
ScreenCardBrowse:
|
||||
dw CardBrowseSetup
|
||||
|
@ -1,5 +1,7 @@
|
||||
; screen variables
|
||||
DEF vPreviousCardIndex EQU SCREEN_VARS_START+16
|
||||
PUSHS UNION "Screen Variables", WRAM0[SCREEN_VARS_START]
|
||||
ds 16 ; why are we putting this so far in?
|
||||
vPreviousCardIndex: db
|
||||
POPS
|
||||
|
||||
ScreenCardRead:
|
||||
dw CardReadSetup
|
||||
|
@ -1,20 +1,22 @@
|
||||
; global variables at the start of hram
|
||||
DEF vCurrentSpread EQU GLOBAL_VARS_START ; 16bit address of current spread, ff90
|
||||
DEF vSelectedSpreadIndex equ vCurrentSpread + 2 ; ff92
|
||||
def vSelectedSpreadCard equ vSelectedSpreadIndex + 1 ; ff93
|
||||
def vSelectedCardIndex equ vSelectedSpreadCard+1 ; ff94
|
||||
DEF vFrameCountSquares EQU vSelectedCardIndex+1 ; ff95
|
||||
DEF vTime EQU vFrameCountSquares+1 ; 16bit ; ff96
|
||||
def vBlocked EQU vTime+2
|
||||
PUSHS UNION "Global Variables", WRAM0[GLOBAL_VARS_START]
|
||||
vCurrentSpread: dw
|
||||
vSelectedSpreadIndex: db
|
||||
vSelectedSpreadCard: db
|
||||
vSelectedCardIndex: db
|
||||
vFrameCountSquares: db
|
||||
vTime: dw
|
||||
vBlocked: db
|
||||
println "vBlocked is ", vBlocked ;
|
||||
|
||||
POPS
|
||||
|
||||
; screen-specific variables
|
||||
DEF vFrameCount1 EQU SCREEN_VARS_START
|
||||
DEF vFrameCount2 equ vFrameCount1+1
|
||||
DEF vFrameCount3 EQU vFrameCount2+1
|
||||
DEF vMenuIndex equ vFrameCount3+1
|
||||
DEF vMenuIndexPrevious equ vMenuIndex + 1
|
||||
PUSHS UNION "Screen Variables", WRAM0[SCREEN_VARS_START]
|
||||
vFrameCount1: db
|
||||
vFrameCount2: db
|
||||
vFrameCount3: db
|
||||
vMenuIndex: db
|
||||
vMenuIndexPrevious: db
|
||||
POPS
|
||||
|
||||
ScreenMainMenu:
|
||||
dw MainMenuSetup
|
||||
|
@ -1,11 +1,10 @@
|
||||
; screen variables already ddefined in screencardread
|
||||
;DEF vPreviousCardIndex EQU VARIABLES_START
|
||||
;def vBlocked equ vPreviousCardIndex + 1
|
||||
def vAnimationFrame EQU SCREEN_VARS_START
|
||||
def vState EQU vAnimationFrame+1
|
||||
def vCurrentAnimation EQU vState+1 ; 2 bytes
|
||||
def vShuffleIndex equ vCurrentAnimation+2
|
||||
def vShuffleTime equ vShuffleIndex+1 ; 2 bytes
|
||||
PUSHS UNION "Screen Variables", WRAM0[SCREEN_VARS_START]
|
||||
vAnimationFrame: db ;def vAnimationFrame EQU SCREEN_VARS_START
|
||||
vState: db ;def vState EQU vAnimationFrame+1
|
||||
vCurrentAnimation: dw ;def vCurrentAnimation EQU vState+1 ; 2 bytes
|
||||
vShuffleIndex: db ;def vShuffleIndex equ vCurrentAnimation+2
|
||||
vShuffleTime: dw ;def vShuffleTime equ vShuffleIndex+1 ; 2 bytes
|
||||
POPS
|
||||
|
||||
def S_Center = 0
|
||||
def S_RightOut = 1
|
||||
|
@ -1,5 +1,7 @@
|
||||
DEF vPreviousSpreadIndex EQU SCREEN_VARS_START
|
||||
def vPreviousSpreadCard equ vPreviousSpreadIndex + 1
|
||||
PUSHS UNION "Screen Variables", WRAM0[SCREEN_VARS_START]
|
||||
vPreviousSpreadIndex: db ; EQU SCREEN_VARS_START
|
||||
vPreviousSpreadCard: db ; equ vPreviousSpreadIndex + 1
|
||||
POPS
|
||||
|
||||
ScreenSpreadSelect:
|
||||
dw SpreadSelectSetup
|
||||
|
BIN
carillon.sav
Normal file
BIN
carillon.sav
Normal file
Binary file not shown.
BIN
gb_tarot_theme_2.mod
Normal file
BIN
gb_tarot_theme_2.mod
Normal file
Binary file not shown.
BIN
gb_tarot_theme_2.mod~
Normal file
BIN
gb_tarot_theme_2.mod~
Normal file
Binary file not shown.
BIN
gb_tarot_theme_2.s3m
Normal file
BIN
gb_tarot_theme_2.s3m
Normal file
Binary file not shown.
643
gbt_player.inc
Normal file
643
gbt_player.inc
Normal file
@ -0,0 +1,643 @@
|
||||
;###############################################################################
|
||||
;
|
||||
; GBT Player v3.1.0
|
||||
;
|
||||
; SPDX-License-Identifier: MIT
|
||||
;
|
||||
; Copyright (c) 2009-2021, Antonio Niño Díaz <antonio_nd@outlook.com>
|
||||
;
|
||||
;###############################################################################
|
||||
|
||||
INCLUDE "hardware.inc"
|
||||
;###############################################################################
|
||||
;
|
||||
; GBT Player v3.1.0
|
||||
;
|
||||
; SPDX-License-Identifier: MIT
|
||||
;
|
||||
; Copyright (c) 2009-2020, Antonio Niño Díaz <antonio_nd@outlook.com>
|
||||
;
|
||||
;###############################################################################
|
||||
|
||||
IF !DEF(GBT_PLAYER_INC)
|
||||
DEF GBT_PLAYER_INC = 1
|
||||
|
||||
;###############################################################################
|
||||
|
||||
EXPORT gbt_play ; Starts playing a song.
|
||||
; de = pointer to song data
|
||||
; a = default speed. Careful, 0 = 256!
|
||||
; bc = data bank (b ignored if ROM with < 256 banks)
|
||||
; THIS WILL CHANGE ROM BANK!!!
|
||||
|
||||
EXPORT gbt_pause ; Pauses or unpauses the song.
|
||||
; a = 0 to pause, anything else to unpause.
|
||||
|
||||
EXPORT gbt_loop ; Enables/disables looping at the end of the song.
|
||||
; a = 0 to stop at the end, anything else to loop
|
||||
|
||||
EXPORT gbt_stop ; Stops the song.
|
||||
|
||||
EXPORT gbt_enable_channels ; Enables given channels.
|
||||
; a = channel flags ORed:
|
||||
; channel 1 = 1
|
||||
; channel 2 = 2
|
||||
; channel 3 = 4
|
||||
; channel 4 = 8
|
||||
|
||||
EXPORT gbt_update ; Updates the player, must be called each VBL.
|
||||
; Note: This will change the active ROM bank!
|
||||
|
||||
; - If the following value is uncomented, the total of banks allowed is 512
|
||||
; (or more), but it's a bit slower. MBC5 ONLY, DOESN'T WORK WITH OTHERS!!!
|
||||
; YOU MUST USE THE -512-banks OPTION WHEN CONVERTING A SONG WITH mod2gbt!!!
|
||||
; - If it's commented, only 256 banks are allowed, it's a little bit faster
|
||||
; and saves a few bytes. MBC1, MBC3 and MBC5 (and others).
|
||||
|
||||
; DEF GBT_USE_MBC5_512BANKS = 1
|
||||
|
||||
;###############################################################################
|
||||
|
||||
ENDC ; GBT_PLAYER_INC
|
||||
|
||||
;###############################################################################
|
||||
|
||||
|
||||
;###############################################################################
|
||||
|
||||
SECTION "GBT_VAR_1",WRAMX[$d800]
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_playing: DS 1
|
||||
|
||||
; pointer to the pattern pointer array
|
||||
gbt_pattern_array_ptr: DS 2 ; LSB first
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
gbt_pattern_array_bank: DS 2 ; LSB first
|
||||
ELSE
|
||||
gbt_pattern_array_bank: DS 1
|
||||
ENDC
|
||||
|
||||
; playing speed
|
||||
gbt_speed:: DS 1
|
||||
|
||||
; Up to 12 bytes per step are copied here to be handled in functions in bank 1
|
||||
gbt_temp_play_data:: DS 12
|
||||
|
||||
gbt_loop_enabled: DS 1
|
||||
gbt_ticks_elapsed:: DS 1
|
||||
gbt_current_step:: DS 1
|
||||
gbt_current_pattern:: DS 1
|
||||
gbt_current_step_data_ptr:: DS 2 ; pointer to next step data - LSB first
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
gbt_current_step_data_bank:: DS 2 ; bank of current pattern data - LSB first
|
||||
ELSE
|
||||
gbt_current_step_data_bank:: DS 1 ; bank of current pattern data
|
||||
ENDC
|
||||
|
||||
gbt_channels_enabled:: DS 1
|
||||
|
||||
gbt_pan:: DS 4*1 ; Ch 1-4
|
||||
gbt_vol:: DS 4*1 ; Ch 1-4
|
||||
gbt_instr:: DS 4*1 ; Ch 1-4
|
||||
gbt_freq:: DS 3*2 ; Ch 1-3
|
||||
|
||||
gbt_channel3_loaded_instrument:: DS 1 ; current loaded instrument ($FF if none)
|
||||
|
||||
; Arpeggio -> Ch 1-3
|
||||
gbt_arpeggio_freq_index:: DS 3*3 ; {base index, base index+x, base index+y} * 3
|
||||
gbt_arpeggio_enabled:: DS 3*1 ; if 0, disabled
|
||||
gbt_arpeggio_tick:: DS 3*1
|
||||
|
||||
; Cut note
|
||||
gbt_cut_note_tick:: DS 4*1 ; If tick == gbt_cut_note_tick, stop note.
|
||||
|
||||
; Last step of last pattern this is set to 1
|
||||
gbt_have_to_stop_next_step:: DS 1
|
||||
|
||||
gbt_update_pattern_pointers:: DS 1 ; set to 1 by jump effects
|
||||
|
||||
;###############################################################################
|
||||
|
||||
SECTION "GBT_BANK0",ROM0
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_get_pattern_ptr:: ; a = pattern number
|
||||
|
||||
; loads a pointer to pattern a into gbt_current_step_data_ptr and
|
||||
; gbt_current_step_data_bank
|
||||
|
||||
ld e,a
|
||||
ld d,0
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
ld a,[gbt_pattern_array_bank+0]
|
||||
ld [rROMB0],a ; MBC5 - Set bank
|
||||
ld a,[gbt_pattern_array_bank+1]
|
||||
ld [rROMB1],a ; MBC5 - Set bank
|
||||
ELSE
|
||||
ld a,[gbt_pattern_array_bank]
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank
|
||||
ENDC
|
||||
|
||||
ld hl,gbt_pattern_array_ptr
|
||||
ld a,[hl+]
|
||||
ld h,[hl]
|
||||
ld l,a
|
||||
|
||||
; hl = pointer to list of pointers
|
||||
; de = pattern number
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
add hl,de
|
||||
ENDC
|
||||
add hl,de
|
||||
add hl,de
|
||||
add hl,de
|
||||
|
||||
; hl = pointer to pattern bank
|
||||
|
||||
ld a,[hl+]
|
||||
ld [gbt_current_step_data_bank+0],a
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
ld a,[hl+]
|
||||
ld [gbt_current_step_data_bank+1],a
|
||||
ENDC
|
||||
|
||||
; hl = pointer to pattern data
|
||||
|
||||
ld a,[hl+]
|
||||
ld h,[hl]
|
||||
ld l,a
|
||||
|
||||
ld a,l
|
||||
ld [gbt_current_step_data_ptr],a
|
||||
ld a,h
|
||||
ld [gbt_current_step_data_ptr+1],a
|
||||
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_get_pattern_ptr_banked:: ; a = pattern number
|
||||
|
||||
push de
|
||||
call gbt_get_pattern_ptr
|
||||
pop de
|
||||
|
||||
ld hl,gbt_current_step_data_ptr
|
||||
ld a,[hl+]
|
||||
ld b,a
|
||||
ld a,[hl]
|
||||
or a,b
|
||||
jr nz,.dont_loop
|
||||
xor a,a
|
||||
ld [gbt_current_pattern], a
|
||||
.dont_loop:
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
xor a,a
|
||||
ld [rROMB1],a
|
||||
ENDC
|
||||
ld a,$01
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank 1
|
||||
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_play:: ; de = data, bc = bank, a = speed
|
||||
|
||||
ld hl,gbt_pattern_array_ptr
|
||||
ld [hl],e
|
||||
inc hl
|
||||
ld [hl],d
|
||||
|
||||
ld [gbt_speed],a
|
||||
|
||||
ld a,c
|
||||
ld [gbt_pattern_array_bank+0],a
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
ld a,b
|
||||
ld [gbt_pattern_array_bank+1],a
|
||||
ENDC
|
||||
|
||||
ld a,0
|
||||
call gbt_get_pattern_ptr
|
||||
|
||||
xor a,a
|
||||
ld [gbt_current_step],a
|
||||
ld [gbt_current_pattern],a
|
||||
ld [gbt_ticks_elapsed],a
|
||||
ld [gbt_loop_enabled],a
|
||||
ld [gbt_have_to_stop_next_step],a
|
||||
ld [gbt_update_pattern_pointers],a
|
||||
|
||||
ld a,$FF
|
||||
ld [gbt_channel3_loaded_instrument],a
|
||||
|
||||
ld a,$0F
|
||||
ld [gbt_channels_enabled],a
|
||||
|
||||
ld hl,gbt_pan
|
||||
ld a,$11 ; L and R
|
||||
ld [hl+],a
|
||||
add a,a
|
||||
ld [hl+],a
|
||||
add a,a
|
||||
ld [hl+],a
|
||||
add a,a
|
||||
ld [hl],a
|
||||
|
||||
ld hl,gbt_vol
|
||||
ld a,$F0 ; 100%
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld a,$20 ; 100%
|
||||
ld [hl+],a
|
||||
ld a,$F0 ; 100%
|
||||
ld [hl+],a
|
||||
|
||||
ld a,0
|
||||
|
||||
ld hl,gbt_instr
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
|
||||
ld hl,gbt_freq
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
|
||||
ld [gbt_arpeggio_enabled+0],a
|
||||
ld [gbt_arpeggio_enabled+1],a
|
||||
ld [gbt_arpeggio_enabled+2],a
|
||||
|
||||
ld a,$FF
|
||||
ld [gbt_cut_note_tick+0],a
|
||||
ld [gbt_cut_note_tick+1],a
|
||||
ld [gbt_cut_note_tick+2],a
|
||||
ld [gbt_cut_note_tick+3],a
|
||||
|
||||
ld a,$80
|
||||
ld [rNR52],a
|
||||
ld a,$00
|
||||
ld [rNR51],a
|
||||
ld a,$00 ; 0%
|
||||
ld [rNR50],a
|
||||
|
||||
xor a,a
|
||||
ld [rNR10],a
|
||||
ld [rNR11],a
|
||||
ld [rNR12],a
|
||||
ld [rNR13],a
|
||||
ld [rNR14],a
|
||||
ld [rNR21],a
|
||||
ld [rNR22],a
|
||||
ld [rNR23],a
|
||||
ld [rNR24],a
|
||||
ld [rNR30],a
|
||||
ld [rNR31],a
|
||||
ld [rNR32],a
|
||||
ld [rNR33],a
|
||||
ld [rNR34],a
|
||||
ld [rNR41],a
|
||||
ld [rNR42],a
|
||||
ld [rNR43],a
|
||||
ld [rNR44],a
|
||||
|
||||
ld a,$77 ; 100%
|
||||
ld [rNR50],a
|
||||
|
||||
ld a,$01
|
||||
ld [gbt_playing],a
|
||||
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_pause:: ; a = pause/unpause
|
||||
ld [gbt_playing],a
|
||||
or a,a
|
||||
jr nz,.gbt_pause_unmute
|
||||
|
||||
; Silence all channels
|
||||
xor a,a
|
||||
ld [rNR51],a
|
||||
|
||||
ret
|
||||
|
||||
.gbt_pause_unmute: ; Unmute sound if playback is resumed
|
||||
|
||||
; Restore panning status
|
||||
ld hl,gbt_pan
|
||||
ld a,[hl+]
|
||||
or a,[hl]
|
||||
inc hl
|
||||
or a,[hl]
|
||||
inc hl
|
||||
or a,[hl]
|
||||
ld [rNR51],a
|
||||
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_loop:: ; a = loop/don't loop
|
||||
ld [gbt_loop_enabled],a
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_stop::
|
||||
xor a,a
|
||||
ld [gbt_playing],a
|
||||
ld [rNR50],a
|
||||
ld [rNR51],a
|
||||
ld [rNR52],a
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
gbt_enable_channels:: ; a = channel flags (channel flag = (1<<(channel_num-1)))
|
||||
ld [gbt_channels_enabled],a
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
EXPORT gbt_update_bank1
|
||||
|
||||
gbt_update::
|
||||
|
||||
ld a,[gbt_playing]
|
||||
or a,a
|
||||
ret z ; If not playing, return
|
||||
|
||||
; Handle tick counter
|
||||
|
||||
ld hl,gbt_ticks_elapsed
|
||||
ld a,[gbt_speed] ; a = total ticks
|
||||
ld b,[hl] ; b = ticks elapsed
|
||||
inc b
|
||||
ld [hl],b
|
||||
cp a,b
|
||||
jr z,.dontexit
|
||||
|
||||
; Tick != Speed, update effects and exit
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
xor a,a
|
||||
ld [rROMB1],a
|
||||
ENDC
|
||||
ld a,$01
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank 1
|
||||
; Call update function in bank 1 (in gbt_player_bank1.s)
|
||||
call gbt_update_effects_bank1
|
||||
|
||||
ret
|
||||
|
||||
.dontexit:
|
||||
ld [hl],$00 ; reset tick counter
|
||||
|
||||
; Clear tick-based effects
|
||||
; ------------------------
|
||||
|
||||
xor a,a
|
||||
ld hl,gbt_arpeggio_enabled ; Disable arpeggio
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl],a
|
||||
dec a ; a = $FF
|
||||
ld hl,gbt_cut_note_tick ; Disable cut note
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl+],a
|
||||
ld [hl],a
|
||||
|
||||
; Update effects
|
||||
; --------------
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
xor a,a
|
||||
ld [rROMB1],a
|
||||
ENDC
|
||||
ld a,$01
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank 1
|
||||
; Call update function in bank 1 (in gbt_player_bank1.s)
|
||||
call gbt_update_effects_bank1
|
||||
|
||||
; Check if last step
|
||||
; ------------------
|
||||
|
||||
ld a,[gbt_have_to_stop_next_step]
|
||||
or a,a
|
||||
jr z,.dont_stop
|
||||
|
||||
call gbt_stop
|
||||
ld a,0
|
||||
ld [gbt_have_to_stop_next_step],a
|
||||
ret
|
||||
|
||||
.dont_stop:
|
||||
|
||||
; Get this step data
|
||||
; ------------------
|
||||
|
||||
; Change to bank with song data
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
ld a,[gbt_current_step_data_bank+0]
|
||||
ld [rROMB0],a ; MBC5 - Set bank
|
||||
ld a,[gbt_current_step_data_bank+1]
|
||||
ld [rROMB1],a ; MBC5 - Set bank
|
||||
ELSE
|
||||
ld a,[gbt_current_step_data_bank]
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank
|
||||
ENDC
|
||||
|
||||
; Get step data
|
||||
|
||||
ld a,[gbt_current_step_data_ptr]
|
||||
ld l,a
|
||||
ld a,[gbt_current_step_data_ptr+1]
|
||||
ld h,a ; hl = pointer to data
|
||||
|
||||
ld de,gbt_temp_play_data
|
||||
|
||||
ld b,4
|
||||
.copy_loop: ; copy as bytes as needed for this step
|
||||
|
||||
ld a,[hl+]
|
||||
ld [de],a
|
||||
inc de
|
||||
bit 7,a
|
||||
jr nz,.more_bytes
|
||||
bit 6,a
|
||||
jr z,.no_more_bytes_this_channel
|
||||
|
||||
jr .one_more_byte
|
||||
|
||||
.more_bytes:
|
||||
|
||||
ld a,[hl+]
|
||||
ld [de],a
|
||||
inc de
|
||||
bit 7,a
|
||||
jr z,.no_more_bytes_this_channel
|
||||
|
||||
.one_more_byte:
|
||||
|
||||
ld a,[hl+]
|
||||
ld [de],a
|
||||
inc de
|
||||
|
||||
.no_more_bytes_this_channel:
|
||||
dec b
|
||||
jr nz,.copy_loop
|
||||
|
||||
ld a,l
|
||||
ld [gbt_current_step_data_ptr],a
|
||||
ld a,h
|
||||
ld [gbt_current_step_data_ptr+1],a ; save pointer to data
|
||||
|
||||
; Increment step/pattern
|
||||
; ----------------------
|
||||
|
||||
; Increment step
|
||||
|
||||
ld a,[gbt_current_step]
|
||||
inc a
|
||||
ld [gbt_current_step],a
|
||||
cp a,64
|
||||
jr nz,.dont_increment_pattern
|
||||
|
||||
; Increment pattern
|
||||
|
||||
ld a,0
|
||||
ld [gbt_current_step],a ; Step 0
|
||||
|
||||
ld a,[gbt_current_pattern]
|
||||
inc a
|
||||
ld [gbt_current_pattern],a
|
||||
|
||||
call gbt_get_pattern_ptr
|
||||
|
||||
ld a,[gbt_current_step_data_ptr]
|
||||
ld b,a
|
||||
ld a,[gbt_current_step_data_ptr+1]
|
||||
or a,b
|
||||
jr nz,.not_ended ; if pointer is 0, song has ended
|
||||
|
||||
ld a,[gbt_loop_enabled]
|
||||
and a,a
|
||||
|
||||
jr z,.loop_disabled
|
||||
|
||||
; If loop is enabled, jump to pattern 0
|
||||
|
||||
ld a,0
|
||||
ld [gbt_current_pattern],a
|
||||
|
||||
call gbt_get_pattern_ptr
|
||||
|
||||
jr .end_handling_steps_pattern
|
||||
|
||||
.loop_disabled:
|
||||
|
||||
; If loop is disabled, stop song
|
||||
; Stop it next step, if not this step won't be played
|
||||
|
||||
ld a,1
|
||||
ld [gbt_have_to_stop_next_step],a
|
||||
|
||||
.not_ended:
|
||||
|
||||
.dont_increment_pattern:
|
||||
|
||||
.end_handling_steps_pattern:
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
xor a,a
|
||||
ld [rROMB1],a ; MBC5
|
||||
ENDC
|
||||
ld a,$01
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5 - Set bank 1
|
||||
; Call update function in bank 1 (in gbt_player_bank1.s)
|
||||
call gbt_update_bank1
|
||||
|
||||
; Check if any effect has changed the pattern or step
|
||||
|
||||
ld a,[gbt_update_pattern_pointers]
|
||||
and a,a
|
||||
ret z
|
||||
; if any effect has changed the pattern or step, update
|
||||
|
||||
xor a,a
|
||||
ld [gbt_update_pattern_pointers],a ; clear update flag
|
||||
|
||||
ld [gbt_have_to_stop_next_step],a ; clear stop flag
|
||||
|
||||
ld a,[gbt_current_pattern]
|
||||
call gbt_get_pattern_ptr ; set ptr to start of the pattern
|
||||
|
||||
; Search the step
|
||||
|
||||
; Change to bank with song data
|
||||
|
||||
IF DEF(GBT_USE_MBC5_512BANKS)
|
||||
ld a,[gbt_pattern_array_bank+1]
|
||||
ld [rROMB1],a ; MBC5
|
||||
ENDC
|
||||
ld a,[gbt_pattern_array_bank+0]
|
||||
ld [rROMB0],a ; MBC1, MBC3, MBC5
|
||||
|
||||
ld a,[gbt_current_step_data_ptr]
|
||||
ld l,a
|
||||
ld a,[gbt_current_step_data_ptr+1]
|
||||
ld h,a ; hl = pointer to data
|
||||
|
||||
ld a,[gbt_current_step]
|
||||
and a,a
|
||||
ret z ; if changing to step 0, exit
|
||||
|
||||
add a,a
|
||||
add a,a
|
||||
ld b,a ; b = iterations = step * 4 (number of channels)
|
||||
.next_channel:
|
||||
|
||||
ld a,[hl+]
|
||||
bit 7,a
|
||||
jr nz,.next_channel_more_bytes
|
||||
bit 6,a
|
||||
jr z,.next_channel_no_more_bytes_this_channel
|
||||
|
||||
jr .next_channel_one_more_byte
|
||||
|
||||
.next_channel_more_bytes:
|
||||
|
||||
ld a,[hl+]
|
||||
bit 7,a
|
||||
jr z,.next_channel_no_more_bytes_this_channel
|
||||
|
||||
.next_channel_one_more_byte:
|
||||
|
||||
ld a,[hl+]
|
||||
|
||||
.next_channel_no_more_bytes_this_channel:
|
||||
dec b
|
||||
jr nz,.next_channel
|
||||
|
||||
ld a,l
|
||||
ld [gbt_current_step_data_ptr],a
|
||||
ld a,h
|
||||
ld [gbt_current_step_data_ptr+1],a ; save pointer to data
|
||||
|
||||
ret
|
||||
|
||||
;###############################################################################
|
1389
gbt_player_bank1.inc
Normal file
1389
gbt_player_bank1.inc
Normal file
File diff suppressed because it is too large
Load Diff
101
justice.asm
101
justice.asm
@ -1,101 +0,0 @@
|
||||
; original export script by gabriel reis, modified by shoofle
|
||||
|
||||
|
||||
KeyArtTiles:
|
||||
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $00,$00,$00,$60,$20,$5c,$3c,$43,$3c,$43,$20,$5c,$00,$60,$00,$00
|
||||
db $3f,$40,$3f,$40,$3f,$40,$3f,$40,$3f,$40,$3f,$40,$3f,$40,$3f,$40
|
||||
db $ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00
|
||||
db $fc,$02,$fc,$02,$fc,$02,$fc,$02,$fc,$02,$fc,$02,$fc,$02,$fc,$02
|
||||
db $00,$00,$00,$06,$04,$3a,$3c,$c2,$3c,$c2,$04,$3a,$00,$06,$00,$00
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$03,$03
|
||||
db $1f,$20,$0f,$30,$07,$18,$03,$0c,$01,$06,$00,$03,$00,$01,$00,$00
|
||||
db $ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$7f,$80,$00,$ff
|
||||
db $ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$ff,$00,$fc,$03,$00,$ff
|
||||
db $f8,$04,$f0,$0c,$e0,$18,$c0,$30,$80,$60,$00,$c0,$00,$80,$00,$00
|
||||
db $04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04
|
||||
db $80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80
|
||||
db $00,$04,$00,$1c,$08,$74,$78,$84,$38,$44,$08,$34,$00,$0c,$00,$04
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$0f
|
||||
db $00,$00,$00,$18,$08,$14,$0c,$12,$1c,$22,$18,$27,$00,$38,$c1,$c1
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0f,$3f,$f8,$ff
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$03,$03,$fe,$ff,$03,$ff,$1c,$fc
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$f8,$f8,$18,$f8,$f8,$f8,$08,$08
|
||||
db $18,$1f,$33,$3c,$67,$78,$43,$7c,$4f,$71,$7f,$7f,$7f,$7f,$78,$7f
|
||||
db $67,$ef,$f3,$33,$f3,$13,$f3,$13,$f3,$f3,$f3,$f3,$f4,$f4,$f4,$34
|
||||
db $1f,$ff,$fa,$fb,$82,$83,$02,$03,$01,$01,$01,$01,$81,$81,$81,$81
|
||||
db $f0,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f0,$10,$f0
|
||||
db $14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$22,$22,$22,$22,$22,$22
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01
|
||||
db $7f,$60,$5f,$60,$38,$27,$2f,$30,$17,$18,$08,$0f,$00,$0f,$00,$ff
|
||||
db $f4,$14,$f4,$14,$78,$98,$d8,$38,$a8,$68,$48,$c8,$10,$d0,$1f,$ff
|
||||
db $81,$81,$80,$80,$40,$40,$40,$40,$40,$40,$40,$40,$20,$20,$e0,$e0
|
||||
db $10,$f0,$90,$f0,$90,$f0,$90,$f0,$50,$70,$50,$70,$48,$78,$48,$78
|
||||
db $22,$22,$21,$21,$41,$41,$41,$41,$7f,$7f,$41,$7f,$3e,$3e,$00,$00
|
||||
db $04,$04,$04,$04,$3c,$3c,$3f,$3f,$07,$07,$02,$1d,$0f,$30,$18,$27
|
||||
db $80,$80,$80,$80,$f0,$f0,$f0,$f0,$80,$80,$00,$c0,$00,$c0,$80,$40
|
||||
db $00,$07,$00,$04,$00,$08,$00,$08,$00,$18,$00,$10,$00,$10,$00,$30
|
||||
db $10,$1f,$0f,$0f,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $20,$f0,$c0,$dc,$00,$04,$00,$06,$00,$02,$00,$02,$00,$03,$00,$03
|
||||
db $48,$78,$28,$38,$28,$38,$28,$38,$28,$38,$24,$3c,$14,$1c,$14,$1c
|
||||
db $1f,$20,$18,$27,$1f,$20,$18,$27,$0f,$10,$00,$0f,$07,$07,$07,$07
|
||||
db $80,$40,$80,$40,$00,$e3,$00,$ff,$70,$8f,$fc,$83,$ff,$80,$ff,$80
|
||||
db $00,$20,$00,$40,$00,$c1,$00,$81,$00,$e1,$c0,$21,$c0,$21,$c0,$31
|
||||
db $00,$01,$00,$21,$00,$21,$00,$21,$00,$21,$00,$23,$01,$22,$01,$22
|
||||
db $14,$1c,$14,$9c,$14,$9c,$12,$9e,$0a,$de,$00,$ff,$8f,$70,$c1,$3e
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$80,$00,$c0
|
||||
db $7f,$80,$3f,$c0,$3f,$c0,$3f,$c0,$0f,$f0,$00,$ff,$00,$7f,$00,$7f
|
||||
db $e0,$11,$e0,$11,$e0,$11,$e0,$11,$c0,$31,$00,$f1,$00,$f1,$00,$f2
|
||||
db $01,$22,$01,$22,$01,$22,$01,$22,$01,$22,$00,$23,$00,$23,$00,$23
|
||||
db $9f,$60,$83,$7c,$bf,$40,$c2,$3d,$de,$23,$0a,$fe,$0a,$fe,$0a,$fe
|
||||
db $80,$40,$80,$40,$00,$c0,$00,$80,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $00,$7f,$00,$7f,$00,$7f,$00,$7f,$00,$7f,$00,$3f,$00,$3f,$00,$3f
|
||||
db $00,$f2,$00,$e2,$00,$e6,$00,$ec,$00,$dc,$00,$f4,$00,$e4,$00,$c4
|
||||
db $00,$33,$00,$31,$00,$39,$00,$2d,$00,$25,$00,$27,$00,$23,$00,$23
|
||||
db $0a,$fe,$0a,$fe,$0a,$fe,$0a,$fe,$09,$ff,$09,$ff,$09,$ff,$09,$ff
|
||||
db $00,$04,$00,$04,$00,$04,$00,$04,$00,$04,$00,$0c,$00,$08,$00,$08
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$60,$00,$30
|
||||
db $00,$21,$00,$20,$00,$31,$00,$11,$00,$10,$00,$10,$00,$10,$00,$10
|
||||
db $09,$ff,$09,$ff,$09,$ff,$09,$8f,$0f,$0f,$00,$06,$00,$00,$00,$00
|
||||
db $00,$08,$00,$08,$00,$08,$00,$08,$00,$18,$00,$10,$00,$10,$00,$10
|
||||
db $00,$1c,$00,$06,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $00,$00,$00,$00,$00,$80,$00,$c0,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $00,$08,$00,$08,$00,$08,$00,$0c,$00,$04,$00,$06,$00,$0e,$00,$1a
|
||||
db $00,$10,$00,$10,$00,$30,$00,$38,$00,$24,$00,$22,$00,$21,$00,$21
|
||||
db $00,$00,$00,$00,$00,$01,$00,$07,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
db $00,$32,$00,$c2,$00,$82,$00,$03,$00,$01,$00,$01,$00,$00,$00,$00
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$80,$00,$80,$00,$c0
|
||||
db $00,$21,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$40,$00,$40
|
||||
db $00,$80,$00,$80,$00,$40,$00,$60,$00,$30,$00,$18,$00,$07,$00,$00
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$c0,$00,$00
|
||||
db $00,$80,$00,$80,$00,$80,$00,$40,$00,$40,$00,$40,$00,$60,$00,$20
|
||||
db $00,$40,$00,$40,$00,$40,$00,$40,$00,$60,$00,$3c,$00,$3f,$00,$39
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$c0,$00,$ff
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$00,$01
|
||||
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$07,$00,$fc,$00,$bf
|
||||
db $00,$20,$00,$10,$00,$10,$00,$10,$00,$f0,$00,$b0,$00,$30,$00,$f0
|
||||
db $00,$00,$00,$7f,$00,$30,$00,$18,$00,$0c,$00,$06,$00,$03,$00,$03
|
||||
db $00,$00,$00,$ff,$00,$1a,$00,$32,$00,$62,$00,$c2,$00,$82,$00,$82
|
||||
db $00,$03,$00,$06,$00,$0c,$00,$18,$00,$30,$00,$20,$00,$7f,$00,$00
|
||||
db $00,$82,$00,$c2,$00,$62,$00,$32,$00,$12,$00,$1a,$00,$ff,$00,$00
|
||||
|
||||
|
||||
|
||||
BackgroundCopy: ; tiles start at 27
|
||||
db $1b, $1c, $1d, $1e, $1e, $1f, $20, $1b
|
||||
db $21, $1b, $22, $23, $24, $25, $1b, $1b
|
||||
db $26, $27, $28, $29, $2a, $2b, $2c, $2d
|
||||
db $26, $27, $1b, $2e, $2f, $30, $31, $32
|
||||
db $26, $27, $33, $34, $35, $36, $37, $38
|
||||
db $39, $3a, $3b, $1b, $3c, $3d, $3e, $1b
|
||||
db $3f, $40, $41, $1b, $1b, $42, $43, $44
|
||||
db $1b, $45, $46, $1b, $1b, $47, $48, $49
|
||||
db $1b, $4a, $4b, $1b, $1b, $4c, $4d, $1b
|
||||
db $1b, $1b, $4e, $4f, $1b, $50, $51, $1b
|
||||
db $1b, $1b, $52, $53, $54, $55, $1b, $1b
|
||||
db $1b, $1b, $56, $1b, $57, $58, $59, $1b
|
||||
db $1b, $1b, $5a, $5b, $5c, $1b, $5d, $1b
|
||||
db $1b, $1b, $5e, $5f, $60, $61, $62, $1b
|
||||
db $1b, $1b, $1b, $63, $64, $1b, $1b, $1b
|
||||
db $1b, $1b, $1b, $65, $66, $1b, $1b, $1b
|
19
main.asm
19
main.asm
@ -42,16 +42,20 @@ def ZEROES equ $D000
|
||||
def ONES equ $D200
|
||||
|
||||
; allocating $8 spaces for system variables, currently only using $4 bytes
|
||||
DEF rMYBTN EQU SYSTEM_VARS_START
|
||||
DEF rMYBTNP EQU rMYBTN + 1
|
||||
DEF rDELTAT EQU rMYBTNP + 1 ; delta_t where $1000 = 1 second
|
||||
def rLFSR equ rDELTAT + 1 ; 16 bit
|
||||
PUSHS "System Variables", WRAM0[SYSTEM_VARS_START]
|
||||
rMYBTN: db ; EQU SYSTEM_VARS_START
|
||||
rMYBTNP: db ;EQU rMYBTN + 1
|
||||
rDELTAT: db ; EQU rMYBTNP + 1 ; delta_t where $1000 = 1 second
|
||||
rLFSR: dw ; equ rDELTAT + 1 ; 16 bit
|
||||
POPS
|
||||
|
||||
|
||||
|
||||
def SAFE_DMA_LOCATION equ $ffc0
|
||||
|
||||
def VARIABLE_TILES_START equ 26
|
||||
def VARIABLE_TILES_START equ 26 ; where in VRAM the variable tiles start
|
||||
; (i.e. we allocate VARIABLE_TILES_START-1 slots out of that block of 128
|
||||
; for ever-present ui tiles)
|
||||
|
||||
|
||||
|
||||
@ -558,8 +562,8 @@ LetterTiles:
|
||||
INCLUDE "Async.inc"
|
||||
INCLUDE "Audio.inc"
|
||||
INCLUDE "Random.inc"
|
||||
INCLUDE "CopyRangeSafe.inc"
|
||||
INCLUDE "CopyTilesSafe.inc"
|
||||
INCLUDE "CopyRange.inc"
|
||||
INCLUDE "CopyTiles.inc"
|
||||
INCLUDE "ScreenMainMenu.inc"
|
||||
INCLUDE "ScreenSpreadSelect.inc"
|
||||
INCLUDE "CardHelpers.inc"
|
||||
@ -569,3 +573,4 @@ INCLUDE "ScreenShuffle.inc"
|
||||
|
||||
INCLUDE "CardLibrary.inc"
|
||||
|
||||
include "gbt_player_bank1.inc"
|
217
pythonrangetest.c
Normal file
217
pythonrangetest.c
Normal file
@ -0,0 +1,217 @@
|
||||
; s3m2gbt modified by shoofle to output rgbds-compatible asm filespythonrangetest_0:
|
||||
db 0xBF,0x00,0x30,0x10,0x10,0x10,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x01,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x02,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x03,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x04,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x05,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x06,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x07,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x08,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x09,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0A,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0B,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0C,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0D,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0E,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x0F,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x10,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x11,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x12,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x13,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x14,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x15,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x16,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x17,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x18,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x19,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1A,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1B,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1C,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1D,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1E,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x1F,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
|
||||
|
||||
pythonrangetest_1:
|
||||
db 0xBF,0x20,0x30,0x10,0x10,0x10,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x21,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x22,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x23,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x24,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x25,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x26,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x27,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x28,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x29,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2A,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2B,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2C,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2D,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2E,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x2F,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x30,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x31,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x32,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x33,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x34,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x35,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x36,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x37,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x38,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x39,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3A,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3B,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3C,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3D,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3E,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x3F,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
|
||||
|
||||
pythonrangetest_2:
|
||||
db 0xBF,0x40,0x30,0x10,0x10,0x10,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x41,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x42,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x43,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x44,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x45,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x46,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0xBF,0x47,0x30,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
db 0x00,0x00,0x00,0x00,
|
||||
|
||||
|
||||
pythonrangetest_init_state:
|
||||
db 0x01,0x06,0x02,0x11,0x22,0x44,0x88,0x00,
|
||||
|
||||
pythonrangetest:
|
||||
db BANK(pythonrangetest_0)
|
||||
dw pythonrangetest_0
|
||||
|
||||
db BANK(pythonrangetest_1)
|
||||
dw pythonrangetest_1
|
||||
|
||||
db BANK(pythonrangetest_2)
|
||||
dw pythonrangetest_2
|
||||
|
||||
db $00
|
||||
dw $0000
|
||||
|
222
pythonrangetest.inc
Normal file
222
pythonrangetest.inc
Normal file
@ -0,0 +1,222 @@
|
||||
; s3m2gbt modified by shoofle to output rgbds-compatible asm files
|
||||
SECTION "pythonrangetest_0", ROMX
|
||||
pythonrangetest_0:
|
||||
db $BF,$00,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$01,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$02,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$03,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$04,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$05,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$06,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$07,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$08,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$09,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$0F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$10,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$11,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$12,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$13,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$14,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$15,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$16,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$17,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$18,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$19,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$1F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
SECTION "pythonrangetest_1", ROMX
|
||||
pythonrangetest_1:
|
||||
db $BF,$20,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$21,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$22,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$23,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$24,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$25,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$26,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$27,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$28,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$29,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$2F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$30,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$31,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$32,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$33,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$34,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$35,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$36,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$37,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$38,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$39,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3A,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3B,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3C,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3D,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3E,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$3F,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
SECTION "pythonrangetest_2", ROMX
|
||||
pythonrangetest_2:
|
||||
db $BF,$40,$30,$10,$10,$10,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$41,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$42,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$43,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$44,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$45,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$46,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $BF,$47,$30,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
db $00,$00,$00,$00,
|
||||
|
||||
|
||||
pythonrangetest_init_state:
|
||||
db 0x01,0x06,0x02,0x11,0x22,0x44,0x88,0x00,
|
||||
|
||||
SECTION "pythonrangetest", ROMX
|
||||
pythonrangetest:
|
||||
db BANK(pythonrangetest_0)
|
||||
dw pythonrangetest_0
|
||||
|
||||
db BANK(pythonrangetest_1)
|
||||
dw pythonrangetest_1
|
||||
|
||||
db BANK(pythonrangetest_2)
|
||||
dw pythonrangetest_2
|
||||
|
||||
db $00
|
||||
dw $0000
|
||||
|
BIN
range_test.s3m
Normal file
BIN
range_test.s3m
Normal file
Binary file not shown.
BIN
rangetest.mod
Normal file
BIN
rangetest.mod
Normal file
Binary file not shown.
BIN
rangetest.s3m
Normal file
BIN
rangetest.s3m
Normal file
Binary file not shown.
371
s3m2gbt.py
Normal file → Executable file
371
s3m2gbt.py
Normal file → Executable file
@ -1,39 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# i (shoofle) have heavily modified this script to output a totally different format
|
||||
# in order to use it with my tarot project. much credit to the original author,
|
||||
# whose intro title/copyright block is preserved below.
|
||||
# sourced this from https://github.com/AntonioND/gbt-player/tree/master/gba/s3m2gbt
|
||||
# in april of 2025
|
||||
|
||||
# s3m2gbt v4.4.1 (Part of GBT Player)
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2022 Antonio Niño Díaz <antonio_nd@outlook.com>
|
||||
|
||||
"""
|
||||
SAMPLE PERIOD LUT - MOD values
|
||||
C C# D D# E F F# G G# A A# B
|
||||
Octave 0:1712,1616,1525,1440,1357,1281,1209,1141,1077,1017, 961, 907 // C3 to B3
|
||||
Octave 1: 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453 // C4 to B4
|
||||
Octave 2: 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226 // C5 to B5
|
||||
Octave 3: 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113 // C6 to B6
|
||||
Octave 4: 107, 101, 95, 90, 85, 80, 76, 71, 67, 64, 60, 57 // C7 to B7
|
||||
Octave 5: 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 // C8 to B8
|
||||
|
||||
//From C3 to B8 | A5 = 1750 = 440.00Hz | C5 = 1546
|
||||
const UWORD GB_frequencies[] = {
|
||||
44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986, // C3 to B3
|
||||
1046,1102,1155,1205,1253,1297,1339,1379,1417,1452,1486,1517, // C4 to B4
|
||||
1546,1575,1602,1627,1650,1673,1694,1714,1732,1750,1767,1783, // C5 to B5
|
||||
1798,1812,1825,1837,1849,1860,1871,1881,1890,1899,1907,1915, // C6 to B6
|
||||
1923,1930,1936,1943,1949,1954,1959,1964,1969,1974,1978,1982, // C7 to B7
|
||||
1985,1988,1992,1995,1998,2001,2004,2006,2009,2011,2013,2015 // C8 to B8
|
||||
};
|
||||
|
||||
"""
|
||||
|
||||
class RowConversionError(Exception):
|
||||
def __init__(self, message, pattern = -1, row = -1, channel = -1):
|
||||
self.pattern = pattern
|
||||
@ -313,13 +285,8 @@ def s3m_note_to_gb(note):
|
||||
# Note cut with ^^
|
||||
if note == 0xFE:
|
||||
return 0xFE
|
||||
if note == 0xFF:
|
||||
return 0xFF
|
||||
|
||||
# Note off and ^^ note cut should be handled before reaching this point
|
||||
#note = note & 0x7F
|
||||
if note > 0x7F:
|
||||
print(note)
|
||||
assert note <= 0x7F
|
||||
|
||||
note -= 32
|
||||
@ -351,16 +318,15 @@ def s3m_pan_to_gb(pan, channel):
|
||||
|
||||
return val
|
||||
|
||||
# masks for how to define an effect
|
||||
EFFECT_PAN = 0x40
|
||||
EFFECT_ARPEGGIO = 0x50
|
||||
EFFECT_VIBRATO = 0x60
|
||||
EFFECT_VOLUME_SLIDE = 0x70
|
||||
EFFECT_NOTE_CUT = 0x80
|
||||
EFFECT_PATTERN_JUMP = 0x90
|
||||
EFFECT_BREAK_SET_STEP = 0xA0
|
||||
EFFECT_SPEED = 0xB0
|
||||
EFFECT_EVENT = 0xC0
|
||||
EFFECT_PAN = 0
|
||||
EFFECT_ARPEGGIO = 1
|
||||
EFFECT_NOTE_CUT = 2
|
||||
EFFECT_VIBRATO = 3
|
||||
EFFECT_VOLUME_SLIDE = 4
|
||||
EFFECT_PATTERN_JUMP = 8
|
||||
EFFECT_BREAK_SET_STEP = 9
|
||||
EFFECT_SPEED = 10
|
||||
EFFECT_EVENT = 15
|
||||
|
||||
# Returns (converted_num, converted_params) if there was a valid effect. If
|
||||
# there is none, it returns (None, None). Note that it is needed to pass the
|
||||
@ -443,31 +409,229 @@ def effect_s3m_to_gb(channel, effectnum, effectparams):
|
||||
|
||||
raise RowConversionError(f"Unsupported effect: {effectnum}{effectparams:02X}")
|
||||
|
||||
def convert_channel(channel, note_index, samplenum, volume, effectnum, effectparams):
|
||||
commands = []
|
||||
HAS_VOLUME = 1 << 4
|
||||
HAS_INSTRUMENT = 1 << 5
|
||||
HAS_EFFECT = 1 << 6
|
||||
HAS_NOTE = 1 << 7
|
||||
HAS_KIT = 1 << 7
|
||||
|
||||
def convert_channel1(note_index, samplenum, volume, effectnum, effectparams):
|
||||
command = [ 0, 0, 0, 0 ] # NOP
|
||||
command_ptr = 1
|
||||
|
||||
# Check if it's needed to add a note
|
||||
if note_index != -1 and note_index != 0xFF and note_index != 0xFE:
|
||||
if note_index != -1:
|
||||
note_index = s3m_note_to_gb(note_index)
|
||||
commands.append([0x10 | channel, note_index])
|
||||
if note_index == 0xFF or note_index == 0xFE:
|
||||
commands.append([0x80 | channel, note_index])
|
||||
|
||||
if volume > -1:
|
||||
commands.append([0x20 | channel, s3m_volume_to_gb(volume) & 0x0F])
|
||||
command[0] |= HAS_NOTE
|
||||
command[command_ptr] = note_index
|
||||
command_ptr = command_ptr + 1
|
||||
|
||||
# Check if there is a sample defined
|
||||
if samplenum > 0:
|
||||
instrument = samplenum & 3
|
||||
commands.append([0x30 | channel, instrument << 6])
|
||||
|
||||
command[0] |= HAS_INSTRUMENT
|
||||
command[command_ptr] = (instrument << 4) & 0x30
|
||||
|
||||
if effectnum is not None:
|
||||
[num, params] = effect_s3m_to_gb(1, effectnum, effectparams)
|
||||
|
||||
if num is not None:
|
||||
commands.append([num | channel, params])
|
||||
command[0] |= HAS_EFFECT
|
||||
command[command_ptr] |= num & 0x0F
|
||||
command_ptr += 1
|
||||
command[command_ptr] = params & 0xFF
|
||||
|
||||
return commands
|
||||
# Check if it's needed to add a volume
|
||||
if volume > -1:
|
||||
command[0] |= HAS_VOLUME
|
||||
command[0] |= s3m_volume_to_gb(volume) & 0x0F
|
||||
|
||||
# Note: The volume bit doesn't affect the final size.
|
||||
sizes = [ 1, 2, 3, 3, 2, 3, 4, 4 ]
|
||||
command_size = sizes[command[0] >> 5]
|
||||
|
||||
return command[:command_size]
|
||||
|
||||
def convert_channel2(note_index, samplenum, volume, effectnum, effectparams):
|
||||
command = [ 0, 0, 0, 0 ] # NOP
|
||||
command_ptr = 1
|
||||
|
||||
# Check if it's needed to add a note
|
||||
if note_index != -1:
|
||||
note_index = s3m_note_to_gb(note_index)
|
||||
command[0] |= HAS_NOTE
|
||||
command[command_ptr] = note_index
|
||||
command_ptr = command_ptr + 1
|
||||
|
||||
# Check if there is a sample defined
|
||||
if samplenum > 0:
|
||||
instrument = samplenum & 3
|
||||
|
||||
command[0] |= HAS_INSTRUMENT
|
||||
command[command_ptr] = (instrument << 4) & 0x30
|
||||
|
||||
if effectnum is not None:
|
||||
[num, params] = effect_s3m_to_gb(2, effectnum, effectparams)
|
||||
|
||||
if num is not None:
|
||||
command[0] |= HAS_EFFECT
|
||||
command[command_ptr] |= num & 0x0F
|
||||
command_ptr += 1
|
||||
command[command_ptr] = params & 0xFF
|
||||
|
||||
# Check if it's needed to add a volume
|
||||
if volume > -1:
|
||||
command[0] |= HAS_VOLUME
|
||||
command[0] |= s3m_volume_to_gb(volume) & 0x0F
|
||||
|
||||
# Note: The volume bit doesn't affect the final size.
|
||||
sizes = [ 1, 2, 3, 3, 2, 3, 4, 4 ]
|
||||
command_size = sizes[command[0] >> 5]
|
||||
|
||||
return command[:command_size]
|
||||
|
||||
def convert_channel3(note_index, samplenum, volume, effectnum, effectparams):
|
||||
command = [ 0, 0, 0, 0 ] # NOP
|
||||
command_ptr = 1
|
||||
|
||||
# Check if it's needed to add a note
|
||||
if note_index != -1:
|
||||
note_index = s3m_note_to_gb(note_index)
|
||||
command[0] |= HAS_NOTE
|
||||
command[command_ptr] = note_index
|
||||
command_ptr = command_ptr + 1
|
||||
|
||||
# Check if there is a sample defined
|
||||
if samplenum > 0:
|
||||
instrument = samplenum & 7
|
||||
|
||||
command[0] |= HAS_INSTRUMENT
|
||||
command[command_ptr] = (instrument << 4) & 0xF0
|
||||
|
||||
if effectnum is not None:
|
||||
[num, params] = effect_s3m_to_gb(3, effectnum, effectparams)
|
||||
|
||||
if num is not None:
|
||||
command[0] |= HAS_EFFECT
|
||||
command[command_ptr] |= num & 0x0F
|
||||
command_ptr += 1
|
||||
command[command_ptr] = params & 0xFF
|
||||
|
||||
# Check if it's needed to add a volume
|
||||
if volume > -1:
|
||||
command[0] |= HAS_VOLUME
|
||||
command[0] |= s3m_volume_to_gb_ch3(volume) & 0x0F
|
||||
|
||||
# Note: The volume bit doesn't affect the final size.
|
||||
sizes = [ 1, 2, 3, 3, 2, 3, 4, 4 ]
|
||||
command_size = sizes[command[0] >> 5]
|
||||
|
||||
return command[:command_size]
|
||||
|
||||
def convert_channel4(note_index, samplenum, volume, effectnum, effectparams):
|
||||
command = [ 0, 0, 0, 0 ] # NOP
|
||||
command_ptr = 1
|
||||
|
||||
# Note cut using ^^ as note
|
||||
if note_index == 0xFE:
|
||||
if samplenum > 0:
|
||||
# This limitation is only for channel 4. It should never happen in a
|
||||
# regular song.
|
||||
raise("Note cut + Sample in same row: Not supported in channel 4")
|
||||
samplenum = 0xFE
|
||||
|
||||
# Check if there is a sample defined
|
||||
if samplenum > 0:
|
||||
if samplenum == 0xFE:
|
||||
kit = 0xFE;
|
||||
else:
|
||||
kit = samplenum & 0xF;
|
||||
command[0] |= HAS_KIT
|
||||
command[command_ptr] = kit
|
||||
command_ptr += 1
|
||||
|
||||
if effectnum is not None:
|
||||
[num, params] = effect_s3m_to_gb(4, effectnum, effectparams)
|
||||
|
||||
if num is not None:
|
||||
command[0] |= HAS_EFFECT
|
||||
command[command_ptr] |= num & 0x0F
|
||||
command_ptr += 1
|
||||
command[command_ptr] = params & 0xFF
|
||||
|
||||
# Check if it's needed to add a volume
|
||||
if volume > -1:
|
||||
command[0] |= HAS_VOLUME
|
||||
command[0] |= s3m_volume_to_gb(volume) & 0x0F
|
||||
|
||||
# Note: The volume bit doesn't affect the final size.
|
||||
sizes = [ 1, 2, 3, 3, 2, 3, 4, 4 ]
|
||||
command_size = sizes[command[0] >> 5]
|
||||
|
||||
return command[:command_size]
|
||||
|
||||
STARTUP_CMD_DONE = 0
|
||||
STARTUP_CMD_SPEED = 1
|
||||
STARTUP_CMD_PANING = 2
|
||||
STARTUP_CMD_CHANNEL3_INSTRUMENT = 3
|
||||
|
||||
SAMPLE_64_ENTRIES = 1 << 7
|
||||
|
||||
def initial_state_array(speed, panning_array, instruments):
|
||||
array = []
|
||||
|
||||
# Initial speed
|
||||
# -------------
|
||||
|
||||
array.extend([STARTUP_CMD_SPEED, speed])
|
||||
|
||||
# Initial panning
|
||||
# ---------------
|
||||
|
||||
array.extend([STARTUP_CMD_PANING])
|
||||
array.extend(panning_array)
|
||||
|
||||
# Channel 3 instruments
|
||||
# ---------------------
|
||||
|
||||
if instruments is not None:
|
||||
print("Exporting instruments...")
|
||||
count = 0
|
||||
for inst in instruments:
|
||||
# In the tracker, instruments start at index 1, but they start at
|
||||
# index 0 in the S3M file.
|
||||
count += 1
|
||||
|
||||
# Only handle instruments assigned to channel 3
|
||||
if count < 8 or count > 15:
|
||||
continue
|
||||
|
||||
name = inst.sample_name
|
||||
|
||||
size = inst.length
|
||||
if size != 32 and size != 64:
|
||||
raise S3MFormatError(f"Sample '{name}': Invalid sample length: {size}")
|
||||
else:
|
||||
flags = count - 8 # The low bits are the instrument index
|
||||
if size == 64:
|
||||
flags |= SAMPLE_64_ENTRIES
|
||||
|
||||
array.extend([STARTUP_CMD_CHANNEL3_INSTRUMENT, flags])
|
||||
|
||||
# Convert from 8 bit to 4 bit
|
||||
for i in range(0, size, 2):
|
||||
sample_hi = inst.sample_data[i + 0] >> 4
|
||||
sample_lo = inst.sample_data[i + 1] >> 4
|
||||
value = (sample_hi << 4) | sample_lo
|
||||
array.extend([value])
|
||||
|
||||
# End commands
|
||||
# ------------
|
||||
|
||||
array.extend([STARTUP_CMD_DONE])
|
||||
|
||||
return array
|
||||
|
||||
def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
|
||||
@ -481,7 +645,7 @@ def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
|
||||
with open(output_path, "w") as fileout:
|
||||
|
||||
fileout.write("; File created by shoofle's s3m2gbt edit\n\n")
|
||||
fileout.write("; s3m2gbt modified by shoofle to output rgbds-compatible asm files\n")
|
||||
|
||||
# Export patterns
|
||||
# ---------------
|
||||
@ -498,15 +662,18 @@ def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
print(f"Pattern {pattern} not exported: Not in the order list")
|
||||
continue
|
||||
|
||||
fileout.write(f"SECTION \"{song_name}_{pattern}\", ROMX\n")
|
||||
fileout.write(f"{song_name}_{pattern}:\n")
|
||||
|
||||
row = 0
|
||||
|
||||
commands = [[0x00, 0x00]]
|
||||
cmd1 = [0]
|
||||
cmd2 = [0]
|
||||
cmd3 = [0]
|
||||
cmd4 = [0]
|
||||
|
||||
for c in p.cells:
|
||||
|
||||
|
||||
# If an end of row marker is reached, print the previous row.
|
||||
# Trust that the S3M file is generated in a valid way and it
|
||||
# doesn't have markers at weird positions, and that there is one
|
||||
@ -514,19 +681,21 @@ def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
if c.empty:
|
||||
|
||||
# Write row
|
||||
fileout.write(" ")
|
||||
fileout.write(" db ")
|
||||
|
||||
for cmd in commands:
|
||||
fileout.write("db ")
|
||||
cmd = cmd1 + cmd2 + cmd3 + cmd4
|
||||
for b in cmd:
|
||||
fileout.write(f"${b:02X}, ")
|
||||
fileout.write("\n")
|
||||
fileout.write(f"${b:02X},")
|
||||
|
||||
fileout.write("\n")
|
||||
|
||||
row = row + 1
|
||||
|
||||
commands = [[0x0F, row & 0xFF]]
|
||||
# Clear commands
|
||||
cmd1 = [0]
|
||||
cmd2 = [0]
|
||||
cmd3 = [0]
|
||||
cmd4 = [0]
|
||||
|
||||
# Next iteration
|
||||
continue
|
||||
@ -557,11 +726,19 @@ def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
channel = c.channel + 1
|
||||
|
||||
try:
|
||||
commands.extend(convert_channel(channel,
|
||||
note, instrument, volume,
|
||||
effectnum, effectparams))
|
||||
|
||||
if channel > 4:
|
||||
if channel == 1:
|
||||
cmd1 = convert_channel1(note, instrument, volume,
|
||||
effectnum, effectparams)
|
||||
elif channel == 2:
|
||||
cmd2 = convert_channel2(note, instrument, volume,
|
||||
effectnum, effectparams)
|
||||
elif channel == 3:
|
||||
cmd3 = convert_channel3(note, instrument, volume,
|
||||
effectnum, effectparams)
|
||||
elif channel == 4:
|
||||
cmd4 = convert_channel4(note, instrument, volume,
|
||||
effectnum, effectparams)
|
||||
else:
|
||||
raise S3MFormatError(f"Too many channels: {channel}")
|
||||
except RowConversionError as e:
|
||||
e.row = row
|
||||
@ -569,27 +746,77 @@ def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
e.channel = channel
|
||||
raise e
|
||||
|
||||
fileout.write("\n")
|
||||
fileout.write("\n")
|
||||
|
||||
# Export initial state
|
||||
# --------------------
|
||||
|
||||
print(f"Exporting initial state... or not...")
|
||||
print(f"Exporting initial state...")
|
||||
|
||||
fileout.write(f"{song_name}_init_state:\n")
|
||||
|
||||
default_pan = [8, 8, 8, 8]
|
||||
for i in range(0, 4):
|
||||
default_pan[i] = s3m.channel_pan[i]
|
||||
|
||||
gb_default_pan = [
|
||||
s3m_pan_to_gb(default_pan[0], 1),
|
||||
s3m_pan_to_gb(default_pan[1], 2),
|
||||
s3m_pan_to_gb(default_pan[2], 3),
|
||||
s3m_pan_to_gb(default_pan[3], 4)
|
||||
]
|
||||
|
||||
instr = None
|
||||
if export_instruments:
|
||||
instr = s3m.instruments
|
||||
|
||||
state_array = initial_state_array(s3m.initial_speed, gb_default_pan, instr)
|
||||
|
||||
# Write rows of 8 bytes until the end of the array
|
||||
while True:
|
||||
left = len(state_array)
|
||||
|
||||
write = []
|
||||
if left == 0:
|
||||
break
|
||||
elif left <= 8:
|
||||
write = state_array
|
||||
state_array = []
|
||||
else:
|
||||
write = state_array[0:8]
|
||||
state_array = state_array[8:]
|
||||
|
||||
fileout.write(" db ")
|
||||
for s in write:
|
||||
fileout.write(f"0x{s:02X},")
|
||||
fileout.write("\n")
|
||||
|
||||
fileout.write("\n")
|
||||
|
||||
# Export orders
|
||||
# -------------
|
||||
|
||||
print(f"Exporting orders...")
|
||||
|
||||
fileout.write(f"SECTION \"{song_name}\", ROMX\n")
|
||||
fileout.write(f"{song_name}:\n")
|
||||
|
||||
fileout.write(f"\tdb {len(s3m.song_orders)}\n")
|
||||
#fileout.write(f" {song_name}_init_state,")
|
||||
#fileout.write("\n")
|
||||
|
||||
for o in s3m.song_orders:
|
||||
pattern = int(o)
|
||||
if pattern >= s3m.num_patterns:
|
||||
# TODO: Warn if the pattern goes over the limit?
|
||||
continue
|
||||
fileout.write(f"\tdw {song_name}_{pattern}\n")
|
||||
fileout.write(f" db BANK({song_name}_{pattern})\n")
|
||||
fileout.write(f" dw {song_name}_{pattern}\n")
|
||||
fileout.write("\n")
|
||||
|
||||
fileout.write(" db $00\n")
|
||||
fileout.write(" dw $0000\n")
|
||||
fileout.write("\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
627
s3m2shoofmt.py
Normal file
627
s3m2shoofmt.py
Normal file
@ -0,0 +1,627 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# i (shoofle) have heavily modified this script to output a totally different format
|
||||
# in order to use it with my tarot project. much credit to the original author,
|
||||
# whose intro title/copyright block is preserved below.
|
||||
# sourced this from https://github.com/AntonioND/gbt-player/tree/master/gba/s3m2gbt
|
||||
# in april of 2025
|
||||
|
||||
# s3m2gbt v4.4.1 (Part of GBT Player)
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2022 Antonio Niño Díaz <antonio_nd@outlook.com>
|
||||
|
||||
"""
|
||||
SAMPLE PERIOD LUT - MOD values
|
||||
C C# D D# E F F# G G# A A# B
|
||||
Octave 0:1712,1616,1525,1440,1357,1281,1209,1141,1077,1017, 961, 907 // C3 to B3
|
||||
Octave 1: 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453 // C4 to B4
|
||||
Octave 2: 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226 // C5 to B5
|
||||
Octave 3: 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113 // C6 to B6
|
||||
Octave 4: 107, 101, 95, 90, 85, 80, 76, 71, 67, 64, 60, 57 // C7 to B7
|
||||
Octave 5: 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 // C8 to B8
|
||||
|
||||
//From C3 to B8 | A5 = 1750 = 440.00Hz | C5 = 1546
|
||||
const UWORD GB_frequencies[] = {
|
||||
44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986, // C3 to B3
|
||||
1046,1102,1155,1205,1253,1297,1339,1379,1417,1452,1486,1517, // C4 to B4
|
||||
1546,1575,1602,1627,1650,1673,1694,1714,1732,1750,1767,1783, // C5 to B5
|
||||
1798,1812,1825,1837,1849,1860,1871,1881,1890,1899,1907,1915, // C6 to B6
|
||||
1923,1930,1936,1943,1949,1954,1959,1964,1969,1974,1978,1982, // C7 to B7
|
||||
1985,1988,1992,1995,1998,2001,2004,2006,2009,2011,2013,2015 // C8 to B8
|
||||
};
|
||||
|
||||
"""
|
||||
|
||||
class RowConversionError(Exception):
|
||||
def __init__(self, message, pattern = -1, row = -1, channel = -1):
|
||||
self.pattern = pattern
|
||||
self.row = row
|
||||
self.channel = channel + 1
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return f"Pattern {self.pattern} | Row {self.row} | Channel {self.channel} | {self.message}"
|
||||
|
||||
class S3MFormatError(Exception):
|
||||
pass
|
||||
|
||||
class S3MFormatReader:
|
||||
|
||||
def read_u8(self):
|
||||
offset = self.read_ptr
|
||||
self.read_ptr += 1
|
||||
return int(self.data[offset])
|
||||
|
||||
def read_u16(self):
|
||||
offset = self.read_ptr
|
||||
self.read_ptr += 2
|
||||
return int((self.data[offset + 1] << 8) | self.data[offset])
|
||||
|
||||
def read_memseg(self):
|
||||
offset = self.read_ptr
|
||||
self.read_ptr += 3
|
||||
part1 = self.data[offset + 0]
|
||||
part2 = self.data[offset + 1]
|
||||
part3 = self.data[offset + 2]
|
||||
return int((part1 << 16) | (part3 << 8) | part2)
|
||||
|
||||
def read_string(self, size):
|
||||
offset = self.read_ptr
|
||||
self.read_ptr += size
|
||||
return self.data[offset:offset+size]
|
||||
|
||||
class S3MFileInstrument(S3MFormatReader):
|
||||
|
||||
def __init__(self, data, offset):
|
||||
self.data = data
|
||||
self.read_ptr = offset
|
||||
|
||||
instrument_type = self.read_u8()
|
||||
if instrument_type != 1:
|
||||
self.exists = False
|
||||
return
|
||||
self.exists = True
|
||||
|
||||
self.dos_filename = self.read_string(12).decode("utf-8")
|
||||
|
||||
self.sample_data_offset = self.read_memseg() * 16
|
||||
|
||||
self.length = self.read_u16()
|
||||
self.length |= self.read_u16() << 16
|
||||
|
||||
self.read_ptr += 4 + 4 # Skip loop begin and loop end
|
||||
|
||||
self.default_volume = self.read_u8()
|
||||
|
||||
self.read_ptr = offset + 0x30
|
||||
|
||||
self.sample_name = self.read_string(28).decode("utf-8")
|
||||
|
||||
if self.read_string(4) != b'SCRS':
|
||||
raise S3MFormatError("Invalid magic string in instrument")
|
||||
|
||||
start = self.sample_data_offset
|
||||
end = start + self.length
|
||||
self.sample_data = self.data[start:end]
|
||||
|
||||
class S3MFilePatternCell():
|
||||
|
||||
def __init__(self, header, channel, note, instrument, volume,
|
||||
effect, effect_args):
|
||||
|
||||
if header == 0:
|
||||
self.empty = True
|
||||
return
|
||||
|
||||
self.empty = False
|
||||
|
||||
self.channel = channel
|
||||
|
||||
if (note != None) or (instrument != None):
|
||||
self.has_note_and_instrument = True
|
||||
self.note = note
|
||||
self.instrument = instrument
|
||||
else:
|
||||
self.has_note_and_instrument = False
|
||||
|
||||
if volume != None:
|
||||
self.has_volume = True
|
||||
self.volume = volume
|
||||
else:
|
||||
self.has_volume = False
|
||||
|
||||
if (effect != None) or (effect_args != None):
|
||||
self.has_effect = True
|
||||
self.effect = effect
|
||||
self.effect_args = effect_args
|
||||
else:
|
||||
self.has_effect = False
|
||||
|
||||
class S3MFilePattern(S3MFormatReader):
|
||||
|
||||
def __init__(self, data, offset):
|
||||
|
||||
# Check if we have asked to generate an empty pattern
|
||||
if data == None:
|
||||
cell = S3MFilePatternCell(0, 0, 0, 0, 0, 0, 0)
|
||||
self.cells = []
|
||||
for i in range(0, 64):
|
||||
self.cells.append(cell)
|
||||
return
|
||||
|
||||
self.data = data
|
||||
self.read_ptr = offset
|
||||
|
||||
length = self.read_u16() - 2
|
||||
|
||||
self.cells = []
|
||||
|
||||
while length > 0:
|
||||
header = self.read_u8()
|
||||
length -= 1
|
||||
|
||||
channel = header & 31
|
||||
|
||||
note = None
|
||||
instrument = None
|
||||
volume = None
|
||||
effect = None
|
||||
effect_args = None
|
||||
|
||||
if (header & (1 << 5)) != 0: # Has note and instrument
|
||||
note = self.read_u8()
|
||||
instrument = self.read_u8()
|
||||
length -= 2
|
||||
|
||||
if (header & (1 << 6)) != 0: # Has volume
|
||||
volume = self.read_u8()
|
||||
length -= 1
|
||||
|
||||
if (header & (1 << 7)) != 0: # Has effect
|
||||
effect = self.read_u8()
|
||||
effect_args = self.read_u8()
|
||||
length -= 2
|
||||
|
||||
cell = S3MFilePatternCell(header, channel, note, instrument, volume,
|
||||
effect, effect_args)
|
||||
self.cells.append(cell)
|
||||
|
||||
class S3MFile(S3MFormatReader):
|
||||
|
||||
def __init__(self, data):
|
||||
|
||||
# Save data for now
|
||||
|
||||
self.data = data
|
||||
self.read_ptr = 0
|
||||
|
||||
self.name = self.read_string(28).decode("utf-8")
|
||||
print(f"Song Name: '{self.name}'")
|
||||
|
||||
self.read_ptr += 1 + 1 + 2 # Ignore fields
|
||||
|
||||
self.song_length = self.read_u16()
|
||||
print(f"Song Length: {self.song_length}")
|
||||
|
||||
self.num_instruments = self.read_u16()
|
||||
self.num_patterns = self.read_u16()
|
||||
|
||||
self.read_ptr += 6 # Ignore fields
|
||||
|
||||
if self.read_string(4) != b'SCRM':
|
||||
raise S3MFormatError("Invalid magic string in file")
|
||||
|
||||
self.read_ptr += 1 # Ignore global volume
|
||||
|
||||
self.initial_speed = self.read_u8()
|
||||
|
||||
if self.read_u8() != 150:
|
||||
raise S3MFormatError("Invalid tempo: It must be 150")
|
||||
|
||||
self.read_ptr += 2 # Ignore master volume and ultraclick removal
|
||||
|
||||
# Save this for later
|
||||
has_custom_pan = False
|
||||
if self.read_u8() == 252:
|
||||
has_custom_pan = True
|
||||
|
||||
self.read_ptr = 0x40
|
||||
channel_settings = self.read_string(4)
|
||||
if channel_settings[0] >= 16 or channel_settings[1] >= 16 or \
|
||||
channel_settings[2] >= 16 or channel_settings[3] >= 16:
|
||||
raise S3MFormatError("Invalid channel settings: Channels 0-3 must be enabled")
|
||||
|
||||
# Read orders
|
||||
|
||||
self.read_ptr = 0x60
|
||||
|
||||
self.song_orders = self.read_string(self.song_length)
|
||||
if self.song_length % 2 == 1:
|
||||
self.read_ptr += 1 # Align to 2
|
||||
|
||||
# Read instrument parapointers
|
||||
|
||||
self.instrument_offsets = [None] * self.num_instruments
|
||||
for i in range(0, self.num_instruments):
|
||||
self.instrument_offsets[i] = self.read_u16() * 16
|
||||
|
||||
# Read pattern parapointers
|
||||
|
||||
self.pattern_offsets = [None] * self.num_patterns
|
||||
for i in range(0, self.num_patterns):
|
||||
self.pattern_offsets[i] = self.read_u16() * 16
|
||||
|
||||
# Read default panning
|
||||
|
||||
if has_custom_pan:
|
||||
self.channel_pan = [b & 0xF for b in self.read_string(4)]
|
||||
else:
|
||||
self.channel_pan = [8, 8, 8, 8]
|
||||
|
||||
# Load instruments
|
||||
|
||||
self.instruments = [None] * self.num_instruments
|
||||
for i in range(0, len(self.instrument_offsets)):
|
||||
offset = self.instrument_offsets[i]
|
||||
if offset != 0:
|
||||
instr = S3MFileInstrument(self.data, offset)
|
||||
if instr.exists:
|
||||
self.instruments[i] = instr
|
||||
|
||||
# Load patterns
|
||||
|
||||
self.patterns = [None] * self.num_patterns
|
||||
for i in range(0, len(self.pattern_offsets)):
|
||||
offset = self.pattern_offsets[i]
|
||||
if offset != 0:
|
||||
self.patterns[i] = S3MFilePattern(self.data, offset)
|
||||
else:
|
||||
# A NULL pointer means that the pattern is empty
|
||||
self.patterns[i] = S3MFilePattern(None, 0)
|
||||
|
||||
# The file data is no longer needed
|
||||
|
||||
self.data = []
|
||||
|
||||
# Channels 1, 2, 4
|
||||
def s3m_volume_to_gb(s3m_vol):
|
||||
if s3m_vol >= 64:
|
||||
return 15
|
||||
else:
|
||||
return s3m_vol >> 2;
|
||||
|
||||
# Channel 3
|
||||
def s3m_volume_to_gb_ch3(s3m_vol):
|
||||
vol = s3m_volume_to_gb(s3m_vol)
|
||||
|
||||
if vol >= 0 and vol <= 3:
|
||||
return 0 # 0%
|
||||
elif vol >= 4 and vol <= 6:
|
||||
return 3 # 25%
|
||||
elif vol >= 7 and vol <= 9:
|
||||
return 2 # 50%
|
||||
elif vol >= 10 and vol <= 12:
|
||||
return 4 # 75%
|
||||
elif vol >= 13 and vol <= 15:
|
||||
return 1 # 100%
|
||||
else:
|
||||
return 0
|
||||
|
||||
def s3m_note_to_gb(note):
|
||||
# Note cut with ^^
|
||||
if note == 0xFE:
|
||||
return 0xFE
|
||||
if note == 0xFF:
|
||||
return 0xFF
|
||||
|
||||
# Note off and ^^ note cut should be handled before reaching this point
|
||||
#note = note & 0x7F
|
||||
if note > 0x7F:
|
||||
print(note)
|
||||
assert note <= 0x7F
|
||||
|
||||
note -= 32
|
||||
if note < 0:
|
||||
raise RowConversionError("Note too low")
|
||||
elif note > 32 + 16 * 6:
|
||||
raise RowConversionError("Note too high")
|
||||
|
||||
note = (note & 0xF) + ((note & 0xF0) >> 4) * 12
|
||||
return note
|
||||
|
||||
def s3m_pan_to_gb(pan, channel):
|
||||
left = False
|
||||
right = False
|
||||
|
||||
if pan >= 0 and pan <= 3:
|
||||
left = True
|
||||
elif pan >= 4 and pan <= 11:
|
||||
left = True
|
||||
right = True
|
||||
elif pan >= 12 and pan <= 15:
|
||||
right = True
|
||||
|
||||
val = 0
|
||||
if left:
|
||||
val |= 1 << (3 + channel)
|
||||
if right:
|
||||
val |= 1 << (channel - 1)
|
||||
|
||||
return val
|
||||
|
||||
# masks for how to define an effect
|
||||
EFFECT_PAN = 0x40
|
||||
EFFECT_ARPEGGIO = 0x50
|
||||
EFFECT_VIBRATO = 0x60
|
||||
EFFECT_VOLUME_SLIDE = 0x70
|
||||
EFFECT_NOTE_CUT = 0x80
|
||||
EFFECT_PATTERN_JUMP = 0x90
|
||||
EFFECT_BREAK_SET_STEP = 0xA0
|
||||
EFFECT_SPEED = 0xB0
|
||||
EFFECT_EVENT = 0xC0
|
||||
|
||||
# Returns (converted_num, converted_params) if there was a valid effect. If
|
||||
# there is none, it returns (None, None). Note that it is needed to pass the
|
||||
# channel to this function because some effects behave differently depending on
|
||||
# the channel (like panning).
|
||||
def effect_s3m_to_gb(channel, effectnum, effectparams):
|
||||
|
||||
if effectnum == 'A': # Set Speed
|
||||
if effectparams == 0:
|
||||
raise RowConversionError("Speed must not be zero")
|
||||
|
||||
return (EFFECT_SPEED, effectparams)
|
||||
|
||||
if effectnum == 'B': # Pattern jump
|
||||
# TODO: Fail if this jumps out of bounds
|
||||
return (EFFECT_PATTERN_JUMP, effectparams)
|
||||
|
||||
elif effectnum == 'C': # Break + Set row
|
||||
# Effect value is BCD, convert to integer
|
||||
val = (((effectparams & 0xF0) >> 4) * 10) + (effectparams & 0x0F)
|
||||
return (EFFECT_BREAK_SET_STEP, val)
|
||||
|
||||
elif effectnum == 'D': # Volume Slide
|
||||
if channel == 3:
|
||||
raise RowConversionError("Volume slide not supported in channel 3")
|
||||
|
||||
if effectparams == 0:
|
||||
# Ignore volume slide commands that just continue the effect,
|
||||
# they are only needed for the S3M player.
|
||||
return (None, None)
|
||||
|
||||
upper = (effectparams >> 4) & 0xF
|
||||
lower = effectparams & 0xF
|
||||
|
||||
if upper == 0xF or lower == 0xF:
|
||||
raise RowConversionError("Fine volume slide not supported")
|
||||
|
||||
elif lower == 0: # Volume goes up
|
||||
params = 1 << 3 # Increase
|
||||
delay = 7 - upper + 1
|
||||
if delay <= 0:
|
||||
raise RowConversionError("Volume slide too steep")
|
||||
params |= delay
|
||||
return (EFFECT_VOLUME_SLIDE, params)
|
||||
elif upper == 0: # Volume goes down
|
||||
params = 0 << 3 # Decrease
|
||||
delay = 7 - lower + 1
|
||||
if delay <= 0:
|
||||
raise RowConversionError("Volume slide too steep")
|
||||
params = delay
|
||||
return (EFFECT_VOLUME_SLIDE, params)
|
||||
else:
|
||||
raise RowConversionError("Invalid volume slide arguments")
|
||||
|
||||
return (EFFECT_VOLUME_SLIDE, effectparams)
|
||||
|
||||
elif effectnum == 'H': # Vibrato
|
||||
return (EFFECT_VIBRATO, effectparams)
|
||||
|
||||
elif effectnum == 'J': # Arpeggio
|
||||
return (EFFECT_ARPEGGIO, effectparams)
|
||||
|
||||
elif effectnum == 'S': # This effect is subdivided into many
|
||||
|
||||
subeffectnum = (effectparams & 0xF0) >> 4
|
||||
subeffectparams = effectparams & 0x0F
|
||||
|
||||
if subeffectnum == 0x8: # Pan position
|
||||
val = s3m_pan_to_gb(subeffectparams, channel)
|
||||
return (EFFECT_PAN, val)
|
||||
|
||||
elif subeffectnum == 0xC: # Notecut
|
||||
return (EFFECT_NOTE_CUT, subeffectparams)
|
||||
|
||||
elif subeffectnum == 0xF: # Funkrepeat? Set active macro?
|
||||
# This effect is either unused, or it's the "set active macro"
|
||||
# command, which doesn't have any effect if you don't use the macro
|
||||
# afterwards. It can safely be overloaded for event callbacks.
|
||||
return (EFFECT_EVENT, subeffectparams)
|
||||
|
||||
raise RowConversionError(f"Unsupported effect: {effectnum}{effectparams:02X}")
|
||||
|
||||
def convert_channel(channel, note_index, samplenum, volume, effectnum, effectparams):
|
||||
commands = []
|
||||
|
||||
# Check if it's needed to add a note
|
||||
if note_index != -1 and note_index != 0xFF and note_index != 0xFE:
|
||||
note_index = s3m_note_to_gb(note_index)
|
||||
commands.append([0x10 | channel, note_index])
|
||||
if note_index == 0xFF or note_index == 0xFE:
|
||||
commands.append([0x80 | channel, note_index])
|
||||
|
||||
if volume > -1:
|
||||
commands.append([0x20 | channel, s3m_volume_to_gb(volume) & 0x0F])
|
||||
|
||||
# Check if there is a sample defined
|
||||
if samplenum > 0:
|
||||
instrument = samplenum & 3
|
||||
commands.append([0x30 | channel, instrument << 6])
|
||||
|
||||
if effectnum is not None:
|
||||
[num, params] = effect_s3m_to_gb(1, effectnum, effectparams)
|
||||
|
||||
if num is not None:
|
||||
commands.append([num | channel, params])
|
||||
|
||||
return commands
|
||||
|
||||
def convert_file(module_path, song_name, output_path, export_instruments):
|
||||
|
||||
with open(module_path, "rb") as file:
|
||||
file_byte_array = bytearray(file.read())
|
||||
|
||||
s3m = S3MFile(file_byte_array)
|
||||
|
||||
if output_path == None:
|
||||
output_path = song_name + ".inc"
|
||||
|
||||
with open(output_path, "w") as fileout:
|
||||
|
||||
fileout.write("; File created by shoofle's s3m2gbt edit\n\n")
|
||||
|
||||
# Export patterns
|
||||
# ---------------
|
||||
|
||||
print(f"Exporting patterns...")
|
||||
|
||||
pattern = -1
|
||||
for p in s3m.patterns:
|
||||
pattern += 1
|
||||
|
||||
# Check if pattern is actually used in the order list. If it isn't
|
||||
# used, don't export it.
|
||||
if pattern not in s3m.song_orders:
|
||||
print(f"Pattern {pattern} not exported: Not in the order list")
|
||||
continue
|
||||
|
||||
fileout.write(f"{song_name}_{pattern}:\n")
|
||||
|
||||
row = 0
|
||||
|
||||
commands = [[0x00, 0x00]]
|
||||
|
||||
for c in p.cells:
|
||||
|
||||
|
||||
# If an end of row marker is reached, print the previous row.
|
||||
# Trust that the S3M file is generated in a valid way and it
|
||||
# doesn't have markers at weird positions, and that there is one
|
||||
# marker right at the end of each pattern.
|
||||
if c.empty:
|
||||
|
||||
# Write row
|
||||
fileout.write(" ")
|
||||
|
||||
for cmd in commands:
|
||||
fileout.write("db ")
|
||||
for b in cmd:
|
||||
fileout.write(f"${b:02X}, ")
|
||||
fileout.write("\n")
|
||||
|
||||
fileout.write("\n")
|
||||
|
||||
row = row + 1
|
||||
|
||||
commands = [[0x0F, row & 0xFF]]
|
||||
|
||||
# Next iteration
|
||||
continue
|
||||
|
||||
volume = -1
|
||||
if c.has_volume:
|
||||
volume = c.volume
|
||||
|
||||
note = -1
|
||||
instrument = 0
|
||||
if c.has_note_and_instrument:
|
||||
note = c.note
|
||||
instrument = c.instrument
|
||||
|
||||
# Rows with note and instrument but no volume use the
|
||||
# default volume of the sample.
|
||||
if instrument > 0 and volume == -1:
|
||||
this_instr = s3m.instruments[instrument - 1]
|
||||
volume = this_instr.default_volume
|
||||
|
||||
effectnum = None
|
||||
effectparams = None
|
||||
if c.has_effect:
|
||||
# Convert type to ASCII to match the documentation
|
||||
effectnum = chr(c.effect + ord('A') - 1)
|
||||
effectparams = c.effect_args
|
||||
|
||||
channel = c.channel + 1
|
||||
|
||||
try:
|
||||
commands.extend(convert_channel(channel,
|
||||
note, instrument, volume,
|
||||
effectnum, effectparams))
|
||||
|
||||
if channel > 4:
|
||||
raise S3MFormatError(f"Too many channels: {channel}")
|
||||
except RowConversionError as e:
|
||||
e.row = row
|
||||
e.pattern = pattern
|
||||
e.channel = channel
|
||||
raise e
|
||||
|
||||
|
||||
# Export initial state
|
||||
# --------------------
|
||||
|
||||
print(f"Exporting initial state... or not...")
|
||||
|
||||
|
||||
# Export orders
|
||||
# -------------
|
||||
|
||||
print(f"Exporting orders...")
|
||||
|
||||
fileout.write(f"{song_name}:\n")
|
||||
|
||||
fileout.write(f"\tdb {len(s3m.song_orders)}\n")
|
||||
for o in s3m.song_orders:
|
||||
pattern = int(o)
|
||||
if pattern >= s3m.num_patterns:
|
||||
# TODO: Warn if the pattern goes over the limit?
|
||||
continue
|
||||
fileout.write(f"\tdw {song_name}_{pattern}\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
print("s3m2gbt v4.4.1 (part of GBT Player)")
|
||||
print("Copyright (c) 2022 Antonio Niño Díaz <antonio_nd@outlook.com>")
|
||||
print("All rights reserved")
|
||||
print("")
|
||||
|
||||
parser = argparse.ArgumentParser(description='Convert S3M files into GBT format.')
|
||||
parser.add_argument("--input", default=None, required=True,
|
||||
help="input file")
|
||||
parser.add_argument("--name", default=None, required=True,
|
||||
help="output song name")
|
||||
parser.add_argument("--output", default=None, required=False,
|
||||
help="output file")
|
||||
parser.add_argument("--instruments", default=False, required=False,
|
||||
action='store_true', help="export channel 3 instruments")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
convert_file(args.input, args.name, args.output, args.instruments)
|
||||
except RowConversionError as e:
|
||||
print("ERROR: " + str(e))
|
||||
sys.exit(1)
|
||||
except S3MFormatError as e:
|
||||
print("ERROR: Invalid S3M file: " + str(e))
|
||||
sys.exit(1)
|
||||
|
||||
print("Done!")
|
||||
|
||||
sys.exit(0)
|
BIN
source.zip
BIN
source.zip
Binary file not shown.
Loading…
Reference in New Issue
Block a user