ポケモン赤緑で今流れている曲を鍵盤に表示する その2

前回→ポケモン赤緑で今流れている曲を鍵盤に表示する - 理科

ポケモン赤緑のなかよしバッヂを使った任意コード実行で今流れている曲を鍵盤に表示しました。

Aボタン入力で脱出できます。

白鍵と黒鍵のある鍵盤に表示するバージョンになっているほか、前回のは表示がデタラメだった (なにせ音楽のROMバンクに切り替えるのを忘れていた!)ので、そこも修正しています。

アイスさんの動画を超参考にしました:

【初代ポケモン】ポケモンで作曲をする方法 バグ・任意コード実行 - YouTube

バイナリ (0xda00からスタート; 488バイト)

cd 67 01 21 00 88 11 0c db 1a 47 13 1a 4f 13 cd
9b da 7b fe 44 c2 09 da 21 3d 88 3e a9 22 77 cd
81 01 cd 92 db cd 9e db cd aa db cd 67 38 fa b3
ff cb 47 c0 11 a0 c3 3e 00 cd 4f da 11 dc c3 3e
01 cd 4f da 11 18 c4 3e 02 cd 4f da c3 22 da cd
a8 da 3e 00 c5 f5 81 fe 05 ca 61 da 3e 00 c3 6d
da 78 fe 0c da 6c da 3e 00 c3 6d da 3c 06 00 4f
81 81 17 4f 21 44 db 09 cd 91 da d5 7b c6 11 5f
7a ce 00 57 cd 91 da d1 f1 c1 3c fe 06 c8 c3 54
da 2a 12 13 2a 12 13 2a 12 13 c9 d5 16 08 78 22
79 22 15 c2 9e da d1 c9 e5 d5 16 00 5f 21 e2 db
7c b5 ca d2 da 19 19 fa db d2 ea 00 20 2a 4f 7e
47 cd d9 da cb 37 e6 0f 47 21 d6 c0 19 7e 4f d1
e1 c9 06 0f 0e 00 d1 e1 c9 d5 60 69 2a 47 fe dc
c2 e7 da 23 c3 dc da fe ed c2 f1 da 23 23 c3 dc
da e6 f0 fe e0 c2 fb da c3 dc da 78 fe fe c2 0a
db 23 2a 47 7e 67 68 c3 dc da d1 c9 99 99 a6 a6
66 66 89 89 22 22 44 44 99 f9 89 f9 81 99 99 9f
89 8f 98 99 26 a6 a6 e6 22 e2 a6 be 22 3e a0 a6
a6 a7 66 e6 22 23 44 c4 06 66 66 7e 44 7c 60 66
66 67 44 47 80 81 82 83 84 85 86 81 82 87 84 85
88 81 82 83 84 85 89 81 82 8a 84 85 8b 8c 82 83
84 85 80 8d 82 83 8e 85 80 8f 82 83 90 85 80 91
82 83 84 85 80 92 93 83 94 95 80 81 96 83 84 85
80 81 97 83 84 98 80 81 99 83 84 85 80 81 9a 83
84 9b 21 06 c0 11 dc db 01 e2 db c3 b3 db 21 08
c0 11 de db 01 e4 db c3 b3 db 21 0a c0 11 e0 db
01 e6 db e5 c5 d5 2a 4f 7e 47 62 6b 2a 5f 7e 57
78 aa 47 79 ab b0 d1 c1 ca d5 db 60 69 1a 47 22
13 1a 4f 77 1b e1 2a 12 13 7e 12 c9 00 00 00 00
00 00 00 00 00 00 00 00

ソースコード (https://github.com/ulrikdamm/Assemblerアセンブルできるものです)

PlaySound = 0x0e33
wTileMap = 0xc3a0
wChannelCommandPointers = 0xc006
wChannelOctaves = 0xc0d6
DisableLCD = 0x0167
EnableLCD = 0x0181
JoypadLowSensitivity = 0x3867
hJoyPressed = 0xffb3
vFont = 0x8800
DelayFrame = 0x0b31
DelayFrames = 0x376F
wMapMusicROMBank = 0xd2db
BankSwitch = 0x360e

SCREEN_WIDTH = 0x14

[org(0xda00)]
start:
    call DisableLCD
    # タイルの作成
    ld hl, vFont
    ld de, TileData
maketiles_loop:
    ld a, [de]
    ld b, a
    inc de
    ld a, [de]
    ld c, a
    inc de
    call CreateTile
    ld a, e
    cp TileDataEnd & 0xff
    jp nz, maketiles_loop

    ld hl, vFont + (0x10 * 3) + 0xd
    ld a, 0xa9
    ld [hl+], a
    ld [hl], a
    call EnableLCD


loop:
    call loadPlayingAddress_0
    call loadPlayingAddress_1
    call loadPlayingAddress_2
    call JoypadLowSensitivity
    ld a, [hJoyPressed]
    bit 0, a
    ret nz
    ld de, wTileMap
    ld a, 0
    call do
    ld de, wTileMap + SCREEN_WIDTH * 3
    ld a, 1
    call do
    ld de, wTileMap + SCREEN_WIDTH * 6
    ld a, 2
    call do
    jp loop

# 入力: a (チャンネル番号)、de (出力先アドレス)
do:
    call calculate_position
    ld a, 0

do_loop:
    push bc
    push af
    # 5 - オクターブ = a なら音階に沿った番号、そうでなければ番号0を格納する
    add a, c
    cp 5
    jp z, do_equal
    ld a, 0
    jp do_join
do_equal:
    ld a, b
    cp 0xc
    jp c, do_ok_note
    ld a, 0
    jp do_join
do_ok_note:
    inc a
do_join:
    ld b, 0
    # 6倍
    ld c, a
    add a, c
    add a, c
    rla
    ld c, a
    ld hl, TileNumbers
    add hl, bc
    call copy_3_times

    # deにSCREEN_WIDTH-3を足す
    push de
    ld a, e
    add a, SCREEN_WIDTH - 3
    ld e, a
    ld a, d
    adc a, 0
    ld d, a

    call copy_3_times
    pop de

    pop af
    pop bc
    inc a
    cp 6
    ret z
    jp do_loop


copy_3_times:
    ld a, [hl+]
    ld [de], a
    inc de
    ld a, [hl+]
    ld [de], a
    inc de
    ld a, [hl+]
    ld [de], a
    inc de
    ret

CreateTile:
    push de
    ld d, 8
CreateTile_loop:
    ld a, b
    ld [hl+], a
    ld a, c
    ld [hl+], a
    dec d
    jp nz, CreateTile_loop
    pop de
    ret

# 入力: a (チャンネルの番号 0〜3)
# 出力: b (音階)、c (オクターブ)
calculate_position:
    push hl
    push de
    ld d, 0
    ld e, a
    # ld hl, wChannelCommandPointers
    ld hl, PlayingAddress
    ld a, h
    or l
    jp z, ifnullptr
    add hl, de
    add hl, de
    
    # 音楽のバンクにスイッチ
    ld a, [wMapMusicROMBank]
    ld [0x2000], a
    #ld b, a
    #push de
    #push hl
    #call BankSwitch
    #pop hl
    #pop de

    ld a, [hl+]
    ld c, a
    ld a, [hl]
    ld b, a

    call ReadNotes
    swap a
    and 0xf
    ld b, a
    ld hl, wChannelOctaves
    add hl, de
    ld a, [hl]
    ld c, a
    pop de
    pop hl
    ret
ifnullptr:
    ld b, 0xf
    ld c, 0x0
    pop de
    pop hl
    ret

# 入力: bc (アドレス)
ReadNotes:
    push de
    ld h, b
    ld l, c
ReadNotes_:
    ld a, [hl+]
    ld b, a
    cp 0xdc
    jp nz, non_dc
    inc hl
    jp ReadNotes_
non_dc:
    cp 0xed
    jp nz, non_ed
    inc hl
    inc hl
    jp ReadNotes_
non_ed:
    and 0xf0
    cp 0xe0
    jp nz, non_e
    jp ReadNotes_
non_e:
    ld a, b
    cp 0xfe
    jp nz, non_fe
    inc hl
    ld a, [hl+]
    ld b, a
    ld a, [hl]
    ld h, a
    ld l, b
    jp ReadNotes_
non_fe:
    pop de
    ret

TileData:
    db 0x99, 0x99, 0xa6, 0xa6, 0x66, 0x66, 0x89, 0x89, 0x22, 0x22, 0x44, 0x44
    db 0x99, 0xf9, 0x89, 0xf9, 0x81, 0x99, 0x99, 0x9f, 0x89, 0x8f, 0x98, 0x99
    db 0x26, 0xa6, 0xa6, 0xe6, 0x22, 0xe2, 0xa6, 0xbe, 0x22, 0x3e, 0xa0, 0xa6
    db 0xa6, 0xa7, 0x66, 0xe6, 0x22, 0x23, 0x44, 0xc4, 0x06, 0x66, 0x66, 0x7e
    db 0x44, 0x7c, 0x60, 0x66, 0x66, 0x67, 0x44, 0x47
TileDataEnd:

TileNumbers:
    db 0x80, 0x81, 0x82, 0x83, 0x84, 0x85 # 0
    db 0x86, 0x81, 0x82, 0x87, 0x84, 0x85 # 1
    db 0x88, 0x81, 0x82, 0x83, 0x84, 0x85 # 2
    db 0x89, 0x81, 0x82, 0x8a, 0x84, 0x85 # 3
    db 0x8b, 0x8c, 0x82, 0x83, 0x84, 0x85 # 4
    db 0x80, 0x8d, 0x82, 0x83, 0x8e, 0x85 # 5
    db 0x80, 0x8f, 0x82, 0x83, 0x90, 0x85 # 6
    db 0x80, 0x91, 0x82, 0x83, 0x84, 0x85 # 7
    db 0x80, 0x92, 0x93, 0x83, 0x94, 0x95 # 8
    db 0x80, 0x81, 0x96, 0x83, 0x84, 0x85 # 9
    db 0x80, 0x81, 0x97, 0x83, 0x84, 0x98 # 10
    db 0x80, 0x81, 0x99, 0x83, 0x84, 0x85 # 11
    db 0x80, 0x81, 0x9a, 0x83, 0x84, 0x9b # 12

loadPlayingAddress_0:
    ld hl, wChannelCommandPointers
    ld de, PrevAddress
    ld bc, PlayingAddress
    jp loadPlayingAddressCommon
loadPlayingAddress_1:
    ld hl, wChannelCommandPointers + 2
    ld de, PrevAddress + 2
    ld bc, PlayingAddress + 2
    jp loadPlayingAddressCommon
loadPlayingAddress_2:
    ld hl, wChannelCommandPointers + 4
    ld de, PrevAddress + 4
    ld bc, PlayingAddress + 4

loadPlayingAddressCommon:
    push hl
    push bc
    push de

    # bcにwChannelCommandPointersの中身を代入
    ld a, [hl+]
    ld c, a
    ld a, [hl]
    ld b, a
    
    # deにPrevAddressの中身を代入
    ld h, d
    ld l, e
    ld a, [hl+]
    ld e, a
    ld a, [hl]
    ld d, a

    ld a, b
    xor d
    ld b, a
    ld a, c
    xor e
    or b
    pop de
    pop bc
    jp z, nochange
    
    # 変更ありの場合、PrevAddressをPlayingAddressにコピー
    ld h, b
    ld l, c
    ld a, [de]
    ld b, a
    ld [hl+], a
    inc de
    ld a, [de]
    ld c, a
    ld [hl], a
    dec de
nochange:
    # 変更あるなしに関わらず、wChannelCommandPointersをPrevAddressにコピー
    pop hl
    ld a, [hl+]
    ld [de], a
    inc de
    ld a, [hl]
    ld [de], a
    ret
PrevAddress:
    nop
    nop
    nop
    nop
    nop
    nop
PlayingAddress:
    nop
    nop
    nop
    nop
    nop
    nop