yandagui 发表于 2023-7-23 20:06:50

[FC][音乐12 IN 1][nes + 源码]

本帖最后由 yandagui 于 2023-7-23 22:29 编辑

[音乐12 IN 1]
时间: 2023.07.23
作者: FlameCyclone

收录音乐内容:
1.Raf世界
2.最终任务
3.赤影战士
4.双截龙
5.双截龙2
6.双截龙3
7.洛克人
8.洛克人2
9.洛克人3
10.洛克人4
11.洛克人5
12.洛克人6

操作:
上键:         上一个专辑
下键:         下一个专辑
左键:         上一曲
右键:         下一曲
B/A键:      前10曲/后10曲
选择键:       下一页
开始键:       停止/播放

http://flamecyclone.ysepan.com/

http://2006.emu618.org:6180/data/attachment/album/202307/23/200601ozt0dsquupyhlptg.pnghttp://2006.emu618.org:6180/data/attachment/album/202307/23/200600rpf1glmta3bq13pz.png
http://2006.emu618.org:6180/data/attachment/album/202307/23/200559czmeytdaomzjxxjg.png

;[播放器模板]
;FlameCyclone 20230710

;文件头
;======================================================================
.INESPRG 16                                             ;16KB PRG 数量
.INESCHR 1                                             ;8KB CHR 数量
.INESMAP 4                                                   ;mapper 4
.INESMIR 1                                 ;命名表镜像 0水平 1垂直

;==================================================
SOUND_BAR_SHOW_ENABLE       = 1
;==================================================
BANK_DATA_MASK            = $1F
CHR_RAM_ENABLE            = 0
IRQ_SCANLINE                = 136
;==================================================
SOUND_DATA_BANK_00          = $00
SOUND_DATA_BANK_01          = $01
SOUND_DATA_BANK_02          = $02
SOUND_DATA_BANK_03          = $03
SOUND_DATA_BANK_04          = $04
SOUND_DATA_BANK_05          = $05
SOUND_DATA_BANK_06          = $06
SOUND_DATA_BANK_07          = $07
SOUND_DATA_BANK_08          = $08
SOUND_DATA_BANK_09          = $09
SOUND_DATA_BANK_0A          = $0A
SOUND_DATA_BANK_0B          = $0B
SOUND_DATA_BANK_0C          = $0C
SOUND_DATA_BANK_0D          = $0D
SOUND_DATA_BANK_0E          = $0E
SOUND_DATA_BANK_0F          = $0F

SOUND_DATA_BANK_10          = $10
SOUND_DATA_BANK_11          = $11
SOUND_DATA_BANK_12          = $12
SOUND_DATA_BANK_13          = $13
SOUND_DATA_BANK_14          = $14
SOUND_DATA_BANK_15          = $15
SOUND_DATA_BANK_16          = $16
SOUND_DATA_BANK_17          = $17
SOUND_DATA_BANK_18          = $18
SOUND_DATA_BANK_19          = $19
SOUND_DATA_BANK_1A          = $1A
SOUND_DATA_BANK_1B          = $1B
SOUND_DATA_BANK_1C          = $1C
SOUND_DATA_BANK_1D          = $1D

SOUND_DATA_BANK_C000      = $1E
SOUND_DATA_BANK_E000      = $1F
;-------------------------------------------------
CHR_DATA_BANK               = $20
CHR_DATA_ADDR               = $A000
;-------------------------------------------------
PROGRAM_BANK                = $00
PROGRAM_ADDR                = $8000
;-------------------------------------------------
RESET_BANK                  = $1F
RESET_ADDR                  = $FD00

;==================================================
ITEM_MAX_SIZE       = 12                     ;最大节目数
ITEM_MAX_INDEX      =ITEM_MAX_SIZE - 1    ;最大节目索引
PAGE_SIZE         = 5                     ;每页节目数

;==================================================
.IF ITEM_MAX_SIZE % PAGE_SIZE;不能整除
PAGE_TOTAL_SIZE= ITEM_MAX_SIZE/PAGE_SIZE + 1   ;页码总数
.ELSE
PAGE_TOTAL_SIZE= ITEM_MAX_SIZE/PAGE_SIZE       ;页码总数
.ENDIF

PAGE_MAX_INDEX= (PAGE_TOTAL_SIZE - 1) * PAGE_SIZE;最大页索引

;==================================================
ITEM_SHOW_POS       = $20A8         ;节目名位置
ARROW_X_OFFSET      = (((ITEM_SHOW_POS & $1F) - 1) << 3) - 2
ARROW_Y_OFFSET      = (((ITEM_SHOW_POS & $03FF) >> 5) << 3) - 1;
;==================================================
Caption_Text_Pos    = $204D ;标题文本位置
Author_Text_Pos   = $2324 ;作者文本位置
Date_Text_Pos       = $236B ;日期文本位置
;------------------------------
;------------------------------
.IF SOUND_BAR_SHOW_ENABLE

Play_Index_Pos      = $2273 ;当前曲目位置
Play_Time_Pos       = $22B3 ;播放时间位置
Play_State_Pos      = $22F3 ;播放状态位置

.ELSE

Play_Index_Pos      = $226C ;当前曲目位置
Play_Time_Pos       = $22AC ;播放时间位置
Play_State_Pos      = $22EC ;播放状态位置

.ENDIF
;------------------------------
Track_Name_Pos      = $222B ;曲目文本位置
;Track_Name_Pos      = $00 ;曲目文本位置
Sound_Track_Pos   = $2265 ;声道文本位置
Sound_Bar_Pos       = $2269 ;音乐条位置
;==================================================
Scroll_X = $00
Scroll_Y = $00
;==================================================
Sound_Ram_Addr_1       = $0100
Sound_Ram_Addr_1_Size= $80
Sound_Ram_Addr_2       = $0090
Sound_Ram_Addr_2_Size= $70
Sound_Ram_Addr_3       = $0700
Sound_Ram_Addr_3_Size= $00
Sound_Ram_Addr_4       = $0400
Sound_Ram_Addr_4_Size= $00
Sound_Ram_Addr_5       = $0500
Sound_Ram_Addr_5_Size= $40

OAM_TEMP_ADDR   = $0300

;==================================================
PPU_CTRL                =   $2000   ;PPU控制寄存器
PPU_MASK                =   $2001   ;PPU掩码寄存器
PPU_STATUS            =   $2002   ;PPU状态寄存器:读取后PPU_SCROLL和PPU_ADDRESS被复位,下一个写到PPU_SCROLL的数据是水平的,写到PPU_ADDRESS的数据是高位
PPU_OAM_ADDR            =   $2003   ;精灵RAM地址:用来设置通过PPU_OAM_DATA访问的256字节精灵RAM地址。每次访问PPU_OAM_DATA后该地址增加1
PPU_OAM_DATA            =   $2004   ;精灵RAM数据:用来读/写精灵内存。地址通过PPU_OAM_ADDR来设置,每次访问后地址增加1
PPU_SCROLL            =   $2005   ;屏幕滚动偏移:第一个写的值会进入垂直滚动寄存器(若>239,被忽略)。第二个值出现在水平滚动寄存器
PPU_ADDRESS             =   $2006   ;VRAM地址:设置PPU_DATA访问的VRAM地址。第一个写地址的高6位。第二个写低8位。每次访问PPU_DATA后地址增加
PPU_DATA                =   $2007   ;VRAM数据:用来访问VRAM数据,通过PPU_ADDRESS设置的地址在每次访问之后会增加1或32
OAM_DMA               =   $4014   ;DMA访问精灵RAM:通过写一个值xx到这个端口,引起CPU内存地址为$xx00-$xxFF的区域传送到精灵内存
APU_STATUS            =   $4015   ;声音通道切换
JOY1_FRAME            =   $4016   ;手柄1 + 选通
JOY2_FRAME            =   $4017   ;手柄2 + 选通
;==================================================
MMC3_BANK_CTRL          =   $8000
MMC3_BANK_DATA          =   $8001
MMC3_MIRRORING          =   $A000
MMC3_PRG_RAM_PROTECT    =   $A001
MMC3_IRQ_LATCH          =   $C000
MMC3_IRQ_RELOAD         =   $C001
MMC3_IRQ_DISABLE      =   $E000
MMC3_IRQ_ENABLE         =   $E001

;==================================================
PPU_Addr      = $0200
Palette_Addr    = $02C0
Sound_Bar       = PPU_Addr+$E0
;==================================================
Bkg_Palette_Update_Addr   = Palette_Addr+$0D
Sprite_Palette_Update_Addr= Palette_Addr+$11
PALETTE_UPDATE_MAX      = $2C
PALETTE_UPDATE_MIN      = $21
PALETTE_UPDATE_INTERVAL = 60
;==================================================
Sound_Bar_Cnt       = PPU_Addr+$F0
PPU_Cur             = Sound_Bar_Cnt+$02
PPU_Addr_H          = PPU_Cur+$03
PPU_Addr_L          = PPU_Addr_H+$04
Screen_Ctrl         = PPU_Addr_L+$01
Screen_State      = Screen_Ctrl+$01
;==================================================
Use_Ram_Begin       = $50
;==================================================
JSR_Addr_Op         = Use_Ram_Begin
JSR_Addr_L          = JSR_Addr_Op + $01
JSR_Addr_H          = JSR_Addr_L + $01
JSR_Addr_Rts      = JSR_Addr_H + $01
Data_L            = JSR_Addr_Rts + $01
Data_H            = Data_L + $01
Data_Cnt            = Data_H + $01
Data_Buf            = Data_Cnt + $01
Nmi_Time_Count      = Data_Buf + $01
Time_Wait_Cnt       = Nmi_Time_Count + $01
Palette_Wait_Cnt    = Time_Wait_Cnt + $01

;调色板刷新标志
Palette_Update_Flag = Palette_Wait_Cnt + $01

;当前帧文本写入禁用标志
Text_Disable_Flag   = Palette_Update_Flag + $01

;==================================================
;当前帧文本写入禁用标志, 防止缓冲过大导致画面跳动
TEXT_DISABLE_BAR    = %00000001         ;音乐条
TEXT_DISABLE_TIME   = %00000010         ;播放时间
TEXT_DISABLE_ITEM   = %00000100         ;播放时间
TEXT_DISABLE_RAM    = %00001000         ;播放时间
;==================================================
Key_Keep            = Text_Disable_Flag + 1
Key_Once            = Key_Keep + $01
Key_Kemp            = Key_Once + $01
Key_Temp            = Key_Kemp + $01
Key_Getv            = Key_Temp + $01
;==================================================
Music_Item_Cur      = Key_Getv + $01          ;当前音乐集
Music_Item_Last   = Music_Item_Cur + $01
Music_Total         = Music_Item_Last + $01          ;当前音乐集
Music_Cur         = Music_Total + $01;当前曲目
Music_Last          = Music_Cur + ITEM_MAX_SIZE         ;上一个曲目
Music_Stop_State    = Music_Last + $01         ;播放停止状态
;==================================================
HEX_Data            = Music_Stop_State + $01
DEC_H               = HEX_Data + $01
DEC_T               = DEC_H + $01
DEC_L               = DEC_T + $01
;==================================================
Time_S            = DEC_L + $01
Time_M            = Time_S + $01
Time_H            = Time_M + $02
Time_Cnt            = Time_H + $03

;==================================================
Music_Bank_8000   = Time_Cnt + 1
Music_Bank_A000   = Music_Bank_8000 + 1
;==================================================
Scroll_H            = Music_Bank_A000 + 1
Scroll_V            = Scroll_H + 1
IRQ_Process_Index   = Scroll_V + 1
;--------------------------------------------------
Page_Cur            = IRQ_Process_Index + $01
Page_Cur_Index      = Page_Cur + $01
Page_Cur_Cnt      = Page_Cur_Index + $01
Page_Last         = Page_Cur_Cnt + $01
Page_Last_Index   = Page_Last + $01
Page_Last_Cnt       = Page_Last_Index + $01
Use_Ram_End         = Page_Last_Cnt + $01
;======================================================================
;音乐数据块

.IF SOUND_BAR_SHOW_ENABLE

.BANK SOUND_DATA_BANK_00 & BANK_DATA_MASK
.ORG $9000
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_1_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_01 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_1_music_data_1.bank"

.BANK SOUND_DATA_BANK_02 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_2_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_03 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_2_music_data_1.bank"

.BANK SOUND_DATA_BANK_04 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_05 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_1.bank"

.BANK SOUND_DATA_BANK_06 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_2.bank"

.BANK SOUND_DATA_BANK_07 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_08 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_1.bank"

.BANK SOUND_DATA_BANK_09 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_2.bank"

.BANK SOUND_DATA_BANK_0A & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_0B & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_1.bank"

.BANK SOUND_DATA_BANK_0C & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_2.bank"

.BANK SOUND_DATA_BANK_0D & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_0E & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_1.bank"

.BANK SOUND_DATA_BANK_0F & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_2.bank"

.BANK SOUND_DATA_BANK_10 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_8000_bar.bank"

.BANK SOUND_DATA_BANK_11 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_A000.bank"

.BANK SOUND_DATA_BANK_12 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_8000_bar.bank"

.BANK SOUND_DATA_BANK_13 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_A000.bank"

.BANK SOUND_DATA_BANK_14 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_8000.bank"

.BANK SOUND_DATA_BANK_15 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_A000_bar.bank"

.BANK SOUND_DATA_BANK_16 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd1_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_17 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd1_music_data_1.bank"

.BANK SOUND_DATA_BANK_18 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd2_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_19 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd2_music_data_1.bank"

.BANK SOUND_DATA_BANK_1A & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd3_music_data_0_bar.bank"

.BANK SOUND_DATA_BANK_1B & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd3_music_data_1.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_C000_dmc.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.ORG $D400
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_C000_dmc.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.ORG $D800
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_E000_dmc.bank"


.ELSE

.BANK SOUND_DATA_BANK_00 & BANK_DATA_MASK
.ORG $9000
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_1_music_data_0.bank"

.BANK SOUND_DATA_BANK_01 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_1_music_data_1.bank"

.BANK SOUND_DATA_BANK_02 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_2_music_data_0.bank"

.BANK SOUND_DATA_BANK_03 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_2_music_data_1.bank"

.BANK SOUND_DATA_BANK_04 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_0.bank"

.BANK SOUND_DATA_BANK_05 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_1.bank"

.BANK SOUND_DATA_BANK_06 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_4_music_data_2.bank"

.BANK SOUND_DATA_BANK_07 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_0.bank"

.BANK SOUND_DATA_BANK_08 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_1.bank"

.BANK SOUND_DATA_BANK_09 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_5_music_data_2.bank"

.BANK SOUND_DATA_BANK_0A & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_0.bank"

.BANK SOUND_DATA_BANK_0B & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_1.bank"

.BANK SOUND_DATA_BANK_0C & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_6_music_data_2.bank"

.BANK SOUND_DATA_BANK_0D & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_0.bank"

.BANK SOUND_DATA_BANK_0E & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_1.bank"

.BANK SOUND_DATA_BANK_0F & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/rockman/rockman_3_music_data_2.bank"

.BANK SOUND_DATA_BANK_10 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_8000.bank"

.BANK SOUND_DATA_BANK_11 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_A000.bank"

.BANK SOUND_DATA_BANK_12 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_8000.bank"

.BANK SOUND_DATA_BANK_13 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_A000.bank"

.BANK SOUND_DATA_BANK_14 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_8000.bank"

.BANK SOUND_DATA_BANK_15 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_A000.bank"

.BANK SOUND_DATA_BANK_16 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd1_music_data_0.bank"

.BANK SOUND_DATA_BANK_17 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd1_music_data_1.bank"

.BANK SOUND_DATA_BANK_18 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd2_music_data_0.bank"

.BANK SOUND_DATA_BANK_19 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd2_music_data_1.bank"

.BANK SOUND_DATA_BANK_1A & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd3_music_data_0.bank"

.BANK SOUND_DATA_BANK_1B & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/double dragon/dd3_music_data_1.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.INCBIN "sound_bank/fc music(mapper 4)/raf world/raf_music_data_C000_dmc.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.ORG $D400
.INCBIN "sound_bank/fc music(mapper 4)/final mission/final_mission_music_data_C000_dmc.bank"

.BANK SOUND_DATA_BANK_C000 & BANK_DATA_MASK
.ORG $D800
.INCBIN "sound_bank/fc music(mapper 4)/kage/kage_music_data_E000_dmc.bank"

.ENDIF

;CHR图形数据
;======================================================================
.BANK CHR_DATA_BANK
.INCBIN "chr_bank/chr_data.chr"

;======================================================================
.BANK PROGRAM_BANK & BANK_DATA_MASK
.ORG PROGRAM_ADDR

;==================================================
NmiProcess

;关闭屏幕控制
LDA #$00
STA PPU_CTRL

;没播放音乐就不需要触发IRQ
LDA <Music_Stop_State
BNE NmiNormal

;重置IRQ索引
LDA #$00
STA <IRQ_Process_Index

;时间秒数为空则跳过
LDA <Time_H
ORA <Time_M
ORA <Time_S
BEQ EnableFirstIrq

INC <Scroll_H

EnableFirstIrq
;80条扫描线后触发IRQ
LDA #IRQ_SCANLINE
STA MMC3_IRQ_LATCH
STA MMC3_IRQ_RELOAD
STA MMC3_IRQ_ENABLE
CLI

NmiNormal

;处理PPU图像
JSR PPU_Proc

;写入精灵, 会占用516个CPU周期, 约4.53扫描线, 写入会导致1像素抖动(PPU处理徐优化)
LDA PPU_STATUS
;LDA #$00
;STA PPU_OAM_ADDR
LDA #OAM_TEMP_ADDR / $0100
STA OAM_DMA

;启用NMI中断
LDA Screen_Ctrl
STA PPU_CTRL

LDA <Text_Disable_Flag
AND #TEXT_DISABLE_RAM
BNE Nmi_Sound_Play

;处理手柄输入
JSR Key_Proc

;切换音乐(手柄触发)
LDA <Time_Wait_Cnt
BNE Nmi_Cursor_Arrow
JSR Change_Select_Item

Nmi_Cursor_Arrow

;处理光标箭头
JSR Show_Arrow

;更新调色板
JSR Update_Palette_Data

;显示时间(缓冲)
JSR Time_Show

;音乐显示(缓冲)
.IF SOUND_BAR_SHOW_ENABLE
JSR Music_Vision
.ENDIF

Nmi_Sound_Play
;播放声音
LDA <Music_Stop_State
BNE Nmi_Time_Wait_Set
JSR Sound_Play_Proc

;播放计时
JSR Time_Count

Nmi_Time_Wait_Set
LDA <Time_Wait_Cnt
BEQ NmiNormalProcessEnd
DEC <Time_Wait_Cnt
NmiNormalProcessEnd

INC <Nmi_Time_Count

RTS

;==================================================
Init_MMC3
;==============================
;禁用IRQ
STA MMC3_IRQ_DISABLE

;水平镜像
LDA #$01
STA MMC3_MIRRORING

;初始化图形bank
JSR Init_MMC3_Chr_Bank

RTS
;==================================================
ProgramBegin;主程序
LDA #$00
STA PPU_CTRL
LDA #$00
STA PPU_STATUS
STA PPU_MASK
STA JOY2_FRAME

STA PPU_SCROLL
STA PPU_SCROLL

;==================================================
LDX #$FF
TXS

JSR Init_MMC3

LDX #$02
Check1
BIT PPU_STATUS
BPL Check1
Check2
BIT PPU_STATUS
BMI Check2

LDA #$0F
STA APU_STATUS
LDA #$C0
STA JOY2_FRAME

LDA PPU_STATUS
LDA #$10
TAX
Check3
STA PPU_ADDRESS
STA PPU_ADDRESS
EOR #$00
DEX
BNE Check3
;==============================
;调色板清空
LDA PPU_STATUS
LDA #$3F
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDA #$0F
Palette_Clear
STA PPU_DATA
INX
CPX #$20
BCC Palette_Clear
LDA #$00
STA APU_STATUS

;==============================
;RAM初始化
RAM_Clear_All
LDY #$00
LDX #$08
LDA #$00
STA <$00
STA <$01
RAM_Clear_All_Start
STA [$00],Y
INY
BNE RAM_Clear_All_Start
INC <$01
DEX
BNE RAM_Clear_All_Start

JSR VramClear
JSR VramInit
JSR OAM_Ram_Init
JSR Init_Palette_Addr

LDA #$FF
STA Use_Ram_End
;==============================
;初始化背景调色板
JSR Set_Palette_Color
JSR Set_NameTable_Attributes

LDA #$00
STA PPU_OAM_ADDR
LDA #OAM_TEMP_ADDR / $0100
STA OAM_DMA

JSR Sound_Reset_Proc
JSR Set_Sound_Total

Init_Start_Music
LDX #$00
Init_Start_Music_Write
LDA Sound_Start_Port,X
STA <Music_Cur,X
INX
CPX #ITEM_MAX_SIZE
BCC Init_Start_Music_Write

JSR Show_Music_Text

.IF SOUND_BAR_SHOW_ENABLE
JSR Sound_Bar_Text_Set
.ENDIF

.IF Track_Name_Pos
JSR Show_Track_Info
.ENDIF

JSR PPU_Proc

;==================================================
;音乐bank初始化
JSR Init_Sound_Bank

JSR Music_Show
JSR Time_Show
JSR Music_State_Show
JSR Time_Delay

LDA #$01
STA <Music_Stop_State

LDA #$88
STA Screen_Ctrl
STA PPU_CTRL

JSR Show_Page_Text

LDA #$10
STA <Time_Wait_Cnt

Wait_Time_Over
LDA <Time_Wait_Cnt
BNE Wait_Time_Over

JSR Show_Arrow
LDA #OAM_TEMP_ADDR / $0100
STA OAM_DMA

LDA #$1E
STA Screen_State

LDX <Music_Item_Cur
LDA <Music_Cur,X
JSR Sound_Init_Proc

CLI
JMP MainLoop

;==============================
Time_Delay;延时等待
LDA PPU_STATUS
BPL Time_Delay
RTS

;==============================
OAM_Ram_Init;初始化精灵内存
LDX #$00
OAM_Ram_Init_Write
LDA #$F8
STA OAM_TEMP_ADDR,X
INX
LDA #$F8
STA OAM_TEMP_ADDR,X
INX
LDA #$00
STA OAM_TEMP_ADDR,X
INX
LDA #$F8
STA OAM_TEMP_ADDR,X
INX
BNE OAM_Ram_Init_Write
RTS

;==============================
VramClear;初始化图形内存
LDA #$20
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDA #$00
LDY #$00
LDX #$10
VramClearWrite
STA PPU_DATA
INY
BNE VramClearWrite
DEX
BNE VramClearWrite
RTS

;==================================================
;设置MMC3图像bank
Init_MMC3_Chr_Bank
LDX #$05
Init_MMC3_Chr_Bank_Write
STX MMC3_BANK_CTRL
LDA MMC3_Chr_Bank_Data,X
STA MMC3_BANK_DATA
DEX
BPL Init_MMC3_Chr_Bank_Write
RTS
;--------------------------------------------------
MMC3_Chr_Bank_Data
.DB $00,$02,$04,$05,$06,$07

;==============================
VramInit;初始化图形内存
.IF CHR_RAM_ENABLE
LDA #CHR_DATA_BANK
JSR Switch_Bank_A000
LDA #LOW(CHR_DATA_ADDR)
STA <Data_L
LDA #HIGH(CHR_DATA_ADDR)
STA <Data_H
LDY #$00
LDX #$20
LDA #$00
STA PPU_ADDRESS
STA PPU_ADDRESS
VramInitWrite
LDA ,Y
STA PPU_DATA
INY
BNE VramInitWrite
INC <Data_H
DEX
BNE VramInitWrite
.ENDIF
RTS

;==============================
;音乐切换
Music_Play_Change
LDA <Key_Once
AND #$FF
BEQ Music_Play_Change_Check

;禁用音乐条刷新
LDA <Text_Disable_Flag
ORA #TEXT_DISABLE_BAR | TEXT_DISABLE_TIME
STA <Text_Disable_Flag

Music_Play_Change_Check
Music_arrow
LDA <Key_Once
AND #$0F
BEQ Music_Play_Change_End
JSR Music_Track_Change
JSR Sound_Reset_Proc
JSR Music_Show
Music_Play_Change_End
RTS

;==============================
;音乐曲目切换
Music_Track_Change
LDX <Music_Item_Cur
LDA <Music_Cur,X
STA <Music_Last
Music_Decrease
LDA <Key_Once
AND #$42
BEQ Music_Increase
LDA <Music_Cur,X
BEQ Music_Increase
DEC <Music_Cur,X
Music_Increase
LDA <Key_Once
AND #$81
BEQ Music_Decrease_10
JSR Set_Sound_Total
LDA <Music_Cur,X
CMP Music_Total
BCS * + 4
INC <Music_Cur,X
Music_Decrease_10
LDA <Key_Once
CMP #$04
BNE Music_Increase_10
LDA <Music_Cur,X
CMP #10
BCC Music_Start_Song_Min
LDA <Music_Cur,X
SEC
SBC #10
STA <Music_Cur,X
LDA #$00
BEQ Music_Increase_10
Music_Start_Song_Min
LDA #$00
STA <Music_Cur,X
Music_Increase_10
LDA <Key_Once
CMP #$08
BNE Music_Track_Change_End
LDA <Music_Cur,X
CLC
ADC #10
CMP Music_Total
BCS Music_Start_Song_Max
STA <Music_Cur,X
LDA #00
BEQ Music_Track_Change_End
Music_Start_Song_Max
LDA Music_Total
STA <Music_Cur,X
Music_Track_Change_End
RTS

;==============================
;按键处理
Key_Proc
JSR Key_Scan
LDA <Key_Keep
STA <Key_Temp
JSR Key_Scan
LDA <Key_Keep
CMP <Key_Temp
BEQ Key_Get_Once
LDA <Key_Kemp
STA <Key_Keep
Key_Get_Once
TAY
EOR Key_Kemp
AND <Key_Keep
STA <Key_Once
STY <Key_Kemp
RTS
;------------------------------
;按键扫描
Key_Scan
LDX #$01
STX JOY1_FRAME
DEX
STX JOY1_FRAME
LDX #$08
Key_Value
LDA JOY1_FRAME
STA <Key_Getv
LSR A
ORA <Key_Getv
LSR A
ROL <Key_Keep
DEX
BNE Key_Value
RTS

;==============================
.IF SOUND_BAR_SHOW_ENABLE
;音乐条显示
Music_Vision
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_ITEM
BNE Music_Vision_End
AND #TEXT_DISABLE_BAR
BNE Music_Vision_Set
LDX PPU_Cur
JSR Music_Animation
STX PPU_Cur
Music_Vision_Set
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_BAR ^ $FF
STA <Text_Disable_Flag
Music_Vision_End
RTS
;------------------------------
;音乐条显示处理
Music_Animation
LDA #PPU_MODE_CNT_LINE
STA PPU_Addr,X
INX
LDA #HIGH(Sound_Bar_Pos)
STA PPU_Addr,X
INX
LDA #LOW(Sound_Bar_Pos)
STA PPU_Addr,X
INX
LDA #$08
STA PPU_Addr,X
INX
LDA Sound_Bar
JSR Volume_Convert

JSR Volume_Set_Cnt
LDA Sound_Bar+$4
JSR Volume_Convert

JSR Volume_Set_Cnt
LDA Sound_Bar+$8
JSR Volume_Convert

JSR Volume_Set_Cnt
LDA Sound_Bar+$C
JSR Volume_Convert

JSR Volume_Set_Cnt

LDY #$10
LDA APU_STATUS
AND #$10
BNE Volume_Count
LDY #$00
BEQ Volume_Count

;------------------------------
;音乐条处理
Volume_Convert
AND #$0F
TAY
Volume_Count
LDA #$08
STA Sound_Bar_Cnt
Volume_FILL
DEY
BEQ Volume_Half
BMI Volume_Empty
DEY
Volume_Full
LDA #$16
BNE Volume_PPU
Volume_Half
LDA #$15
BNE Volume_PPU
Volume_Empty
LDA #$14
Volume_PPU
STA PPU_Addr,X
INX
DEC Sound_Bar_Cnt
BNE Volume_FILL
RTS

Volume_Set_Cnt
LDA #PPU_MODE_CNT_LINE_NEXT
STA PPU_Addr,X
INX
LDA #$08
STA PPU_Addr,X
INX
RTS

.ENDIF

;==============================
PPU_MODE_CNT_LINE         = $FA    ;行计数写入
PPU_MODE_CNT_LINE_NEXT    = $FB    ;转下行计数模式
PPU_MODE_CNT_CLEAR      = $FC    ;行计数清除
;------------------------------
;PPU处理
PPU_Proc
LDX PPU_Cur
LDA #$00
STA PPU_Cur
STA PPU_Addr,X
LDA PPU_Addr
BNE PPU_Proc_Beg
PPU_Proc_Ret
RTS

;------------------------------
PPU_Mode_Return_Cnt;转下行模式
INX
LDA PPU_Addr_L
CLC
ADC #$20
STA PPU_Addr_L
BCC PPU_Mode_Return_Cnt_End
INC PPU_Addr_H
PPU_Mode_Return_Cnt_End
LDA PPU_Addr_H
STA PPU_ADDRESS
LDA PPU_Addr_L
STA PPU_ADDRESS
LDA PPU_Addr,X
TAY
PPU_Mode_Return_Cnt_Write
INX
LDA PPU_Addr,X
STA PPU_DATA
DEY
BNE PPU_Mode_Return_Cnt_Write
JMP PPU_Proc_End

;------------------------------
PPU_Proc_Beg;处理开始
LDX #$00
STX PPU_MASK
;------------------------------
PPU_Mode_Select;模式选择
LDA PPU_Addr,X
CMP #PPU_MODE_CNT_CLEAR
BEQ PPU_Proc_Clear
CMP #PPU_MODE_CNT_LINE
BEQ PPU_Proc_Cnt_Line
CMP #PPU_MODE_CNT_LINE_NEXT
BEQ PPU_Mode_Return_Cnt
JMP PPU_Proc_End_Write
;------------------------------
PPU_Proc_End;单行写入结束
INX
LDA PPU_Addr,X
BNE PPU_Mode_Select
STA PPU_Addr
JSR Update_Palette_Color

PPU_Proc_End_Write
LDA #$00
STA PPU_ADDRESS
STA PPU_ADDRESS
LDA <Text_Disable_Flag
AND #(TEXT_DISABLE_BAR | TEXT_DISABLE_TIME | TEXT_DISABLE_RAM) ^ $FF
STA <Text_Disable_Flag
LDA #Scroll_X
STA PPU_SCROLL
LDA #Scroll_Y
STA PPU_SCROLL
LDA Screen_State
STA PPU_MASK
RTS

PPU_Proc_Clear
INX
LDA PPU_Addr,X
STA PPU_ADDRESS
INX
LDA PPU_Addr,X
STA PPU_ADDRESS
INX
LDY PPU_Addr,X
LDA #$00
PPU_Proc_Clear_Write
STA PPU_DATA
DEY
BNE PPU_Proc_Clear_Write
JMP PPU_Proc_End

PPU_Proc_Cnt_Line
INX
LDA PPU_Addr,X
STA PPU_Addr_H
STA PPU_ADDRESS
INX
LDA PPU_Addr,X
STA PPU_Addr_L
STA PPU_ADDRESS
INX
LDY PPU_Addr,X
PPU_Proc_Cnt_Line_Write
INX
LDA PPU_Addr,X
STA PPU_DATA
DEY
BNE PPU_Proc_Cnt_Line_Write
JMP PPU_Proc_End

;==============================
HEX_To_Dec;十六进制转十进制
STA <HEX_Data
PHA
TXA
PHA
LDX #$00
LDA #$00
HEX_Cln
STA <DEC_H,X
INX
CPX #$03
BCC HEX_Cln
LDA <HEX_Data
;------------------------------
HEX_100
CMP #100
BCC HEX_10
SEC
SBC #100
INC <DEC_H
BNE HEX_100
;------------------------------
HEX_10
CMP #10
BCC HEX_1
SEC
SBC #10
INC <DEC_T
BNE HEX_10
;------------------------------
HEX_1
STA <DEC_L
PLA
TAX
PLA
RTS

;==============================
;音乐曲目显示
Music_Show
LDX <Music_Item_Cur
LDA <Music_Cur,X
CLC
ADC #$01
JSR HEX_To_Dec
LDX PPU_Cur
LDA #PPU_MODE_CNT_LINE
STA PPU_Addr,X
INX
LDA #HIGH(Play_Index_Pos)
STA PPU_Addr,X
INX
LDA #LOW(Play_Index_Pos)
STA PPU_Addr,X
INX

LDA #$07
BNE Music_Show_Length

Music_Show_Length
STA PPU_Addr,X
INX

LDA <DEC_H
ORA #'0'
STA PPU_Addr,X
INX

LDA <DEC_T
ORA #'0'
STA PPU_Addr,X
INX

LDA <DEC_L
ORA #'0'
STA PPU_Addr,X
INX

LDA #'/'
STA PPU_Addr,X
INX
Music_Show_Total
LDA Music_Total
CLC
ADC #$01
JSR HEX_To_Dec

LDA <DEC_H
ORA #'0'
STA PPU_Addr,X
INX

LDA <DEC_T
ORA #'0'
STA PPU_Addr,X
INX

LDA <DEC_L
ORA #'0'
STA PPU_Addr,X
INX

STX PPU_Cur
Music_Show_End
RTS

;==============================
Time_Show;播放时间显示
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_ITEM
BNE Time_Show_End
AND #TEXT_DISABLE_TIME
BNE Time_Show_Enable

LDX PPU_Cur
LDA #PPU_MODE_CNT_LINE
STA PPU_Addr,X
INX
LDA #HIGH(Play_Time_Pos)
STA PPU_Addr,X
INX
LDA #LOW(Play_Time_Pos)
STA PPU_Addr,X
INX
LDA #$08
STA PPU_Addr,X
INX
Time_Show_H
LDA <Time_H
JSR HEX_To_Dec
JSR Time_Digit
LDA #':'
STA PPU_Addr,X
INX
Time_Show_M
LDA <Time_M
JSR HEX_To_Dec
JSR Time_Digit
LDA #':'
STA PPU_Addr,X
INX
Time_Show_S
LDA <Time_S
JSR HEX_To_Dec
JSR Time_Digit
STX PPU_Cur
Time_Show_Enable
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_TIME ^ $FF
STA <Text_Disable_Flag
Time_Show_End
RTS

Time_Digit
LDA <DEC_T
ORA #'0'
STA PPU_Addr,X
INX
LDA <DEC_L
ORA #'0'
STA PPU_Addr,X
INX
RTS

;==============================
Time_Count;计时
LDA <Music_Stop_State
ORA <Time_Wait_Cnt
BNE Time_Count_End
INC <Time_Cnt
LDA <Time_Cnt
CMP #60
BCC Time_Count_End
LDA #00
STA <Time_Cnt
INC <Time_S

Time_S_Cnt
LDA <Time_S
CMP #60
BCC Time_Count_End
LDA #00
STA <Time_S
INC <Time_M

Time_M_Cnt
LDA <Time_M
CMP #60
BCC Time_Count_End
LDA #00
STA <Time_M
INC <Time_H

Time_H_Cnt
LDA <Time_H
CMP #24
BCC Time_Count_End
LDA #00
STA <Time_H

Time_Count_End
RTS

;==============================
Time_ReSet;播放时间重置
LDA #$00
STA <Time_S
STA <Time_M
STA <Time_H
STA <Time_Cnt
RTS

;==============================
Music_Bar_ReSet;音乐条重置
LDA #$00
LDX #$00
Music_Bar_ReSet_Set
STA Sound_Bar,X
INX
CPX #$10
BCC Music_Bar_ReSet_Set
RTS

;==============================
PPU_Data;PPU数据写入
STY <Data_L
STX <Data_H
LDY #$FF
LDX PPU_Cur
DEX
PPU_Data_Beg
INX
INY
LDA ,Y
STA PPU_Addr,X
BNE PPU_Data_Beg
STX PPU_Cur
PPU_Data_End
RTS

;==============================
Music_State_Show;播放状态显示
LDA <Music_Stop_State
BEQ Music_State_Show_Play
Music_State_Show_Stop
LDY #LOW(Music_State_Stop)
LDX #HIGH(Music_State_Stop)
JSR PPU_Data
RTS
Music_State_Show_Play
LDY #LOW(Music_State_Play)
LDX #HIGH(Music_State_Play)
JSR PPU_Data
RTS

.IF SOUND_BAR_SHOW_ENABLE
;==============================
Sound_Bar_Text_Set;标题与音乐条初始化
LDY #LOW(Sound_Bar_Text_Data)
LDX #HIGH(Sound_Bar_Text_Data)
JSR PPU_Data
RTS

.ENDIF

;==============================
Set_NameTable_Attributes;设置命名表属性
BIT PPU_STATUS
LDA #$23
STA PPU_ADDRESS
LDA #$C0
STA PPU_ADDRESS
LDX #$00
Set_NameTable_Attributes_Write
LDA Palette_Attributes,X
STA PPU_DATA
INX
CPX #$40
BCC Set_NameTable_Attributes_Write
RTS

;==============================
Set_Palette_Color;设置调色板数据
BIT PPU_STATUS
LDA #$3F
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDX #$00
Set_Palette_Color_Write
LDA Palette_Data,X
STA PPU_DATA
INX
CPX #$20
BCC Set_Palette_Color_Write
RTS

;==============================
Init_Palette_Addr;初始化调色板数据
LDX #$00
Init_Palette_Addr_Write
LDA Palette_Data,X
STA Palette_Addr,X
INX
CPX #$20
BCC Init_Palette_Addr_Write
RTS

;==============================
Update_Palette_Color;更新调色板颜色
LDA <Palette_Update_Flag
BEQ Update_Palette_Color_End
LDA #$3F
STA PPU_ADDRESS
LDA #$0C
STA PPU_ADDRESS
LDX #$0C
Update_Palette_Color_Write
LDA Palette_Addr,X
STA PPU_DATA
INX
CPX #$14
BCC Update_Palette_Color_Write
LDA #$00
STA <Palette_Update_Flag
Update_Palette_Color_End
RTS


Update_Sprite_Palette_Data
.DB $21
.DB $21
.DB $11
.DB $01
.DB $01
.DB $11
.DB $21
.DB $21
.DB $11
.DB $01
.DB $11
.DB $21
.DB $21
.DB $11
.DB $01
.DB $11
;==============================
Update_Palette_Data;更新调色板数据
LDA Nmi_Time_Count
AND #$08
CMP #$08
BNE Update_Bkg_Palette_Data

Update_Sprite_Palette_Data_Set
LDA Nmi_Time_Count
LSR A
LSR A
LSR A
LSR A
AND #$0F
TAX
LDA Update_Sprite_Palette_Data,X
STA Sprite_Palette_Update_Addr
LDA #$01
STA <Palette_Update_Flag

Update_Bkg_Palette_Data
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_RAM
BNE Update_Palette_Data_End
LDA <Music_Stop_State
BNE Update_Palette_Data_End

Update_Palette_Data_Check
LDA Palette_Wait_Cnt
BPL Update_Palette_Data_Check_Over
LDA #PALETTE_UPDATE_INTERVAL
STA Palette_Wait_Cnt
Update_Palette_Data_Check_Over
DEC Palette_Wait_Cnt
BNE Update_Palette_Data_End

LDA <Text_Disable_Flag
ORA #TEXT_DISABLE_BAR | TEXT_DISABLE_TIME
STA Text_Disable_Flag
INC Palette_Update_Flag

LDA #PALETTE_UPDATE_INTERVAL
STA Palette_Wait_Cnt

LDA Bkg_Palette_Update_Addr
CMP #PALETTE_UPDATE_MAX
BNE Update_Bkg_Palette_Data_Set
LDA #PALETTE_UPDATE_MIN - 1
STA Bkg_Palette_Update_Addr
Update_Bkg_Palette_Data_Set
INC Bkg_Palette_Update_Addr

Update_Palette_Data_End
RTS

;==============================
Show_Music_Text;显示静态文本
LDX #$00
Show_Music_Text_Set
LDA Static_Text_Data,X
STA <Data_L
INX
LDA Static_Text_Data,X
STA <Data_H
INX
LDY #$00
LDA ,Y
STA <Data_Cnt
DEX
DEX
LDA Static_Text_Pos,X
STA PPU_ADDRESS
INX
LDA #$20
SEC
SBC <Data_Cnt
LSR A
STA <Data_Buf
LDA Static_Text_Pos,X
AND #$E0
CLC
ADC <Data_Buf
STA PPU_ADDRESS
INX
Show_Music_Text_Set_Write
INY
LDA ,Y
STA PPU_DATA
DEC <Data_Cnt
BNE Show_Music_Text_Set_Write
CPX #Static_Text_Pos_End - Static_Text_Pos
BCC Show_Music_Text_Set
RTS

;==============================
.IF Track_Name_Pos;显示曲目信息

Clear_Track_Info
PHA
LDX <Music_Item_Cur
LDA Track_Name_Addr_Flag,X
BEQ Clear_Track_Info_End_Ex
PLA

LDX PPU_Cur
PHA
LDA #PPU_MODE_CNT_CLEAR
STA PPU_Addr,X
INX
PLA
JSR Show_Get_Track_Name_Center_Pos
STX PPU_Cur
Clear_Track_Info_End
RTS
Clear_Track_Info_End_Ex
PLA
RTS

Write_Track_Info
PHA
LDX <Music_Item_Cur
LDA Track_Name_Addr_Flag,X
BEQ Write_Track_Info_End_Ex
PLA

PHA
LDX PPU_Cur
LDA #PPU_MODE_CNT_LINE
STA PPU_Addr,X
INX
PLA
JSR Show_Get_Track_Name_Center_Pos
Write_Track_Info_Data
INY
LDA ,Y
STA PPU_Addr,X
INX
DEC <Data_Cnt
BNE Write_Track_Info_Data
STX PPU_Cur
Write_Track_Info_End
RTS
Write_Track_Info_End_Ex
PLA
RTS

Show_Track_Info
Show_Track_Info_Clear
LDA <Music_Last

JSR Clear_Track_Info

LDX <Music_Item_Cur
LDA <Music_Cur,X
JSR Write_Track_Info
RTS

;==============================
Show_Get_Track_Name_Center_Pos;获取中间位置

;取出集合名索引
PHA

LDA <Music_Item_Cur
ASL A
TAY
LDA Track_Name_Addr_Port,Y
PHA
INY
LDA Track_Name_Addr_Port,Y
STA <Data_H
PLA
STA <Data_L

PLA

ASL A
TAY
LDA ,Y
PHA
INY
LDA ,Y
STA Data_H
PLA
STA Data_L

LDY #$00
LDA ,Y
STA <Data_Cnt
LDA #$20
SEC
SBC <Data_Cnt
LSR A
STA <Data_Buf
LDA #HIGH(Track_Name_Pos)
STA PPU_Addr,X
INX
LDA #LOW(Track_Name_Pos)
AND #$E0
CLC
ADC <Data_Buf
STA PPU_Addr,X
INX
LDA <Data_Cnt
STA PPU_Addr,X
INX
Show_Get_Pos_Center_End
RTS
.ENDIF

;==============================
;音乐端口清除
Sound_Data_Clear
JSR Sound_Port_Clear
JSR Sound_Ram_Clear
RTS

;==============================
;音乐端口清除
Sound_Port_Clear
LDA #$00
STA APU_STATUS
LDX #$00
Sound_Port_Clear_Write
STA $4000,X
INX
CPX #$14
BCC Sound_Port_Clear_Write
RTS

;==============================
Sound_Ram_Clear;RAM清除
LDX #$00
LDA #$00
Sound_Ram_Clear_1
STA Sound_Ram_Addr_1,X
INX
CPX #Sound_Ram_Addr_1_Size
BNE Sound_Ram_Clear_1
LDX #$00
Sound_Ram_Clear_2
STA Sound_Ram_Addr_2,X
INX
CPX #Sound_Ram_Addr_2_Size
BNE Sound_Ram_Clear_2
LDX #$00
Sound_Ram_Clear_3
STA Sound_Ram_Addr_3,X
INX
CPX #Sound_Ram_Addr_3_Size
BNE Sound_Ram_Clear_3
LDX #$00
Sound_Ram_Clear_4
STA Sound_Ram_Addr_4,X
INX
CPX #Sound_Ram_Addr_4_Size
BNE Sound_Ram_Clear_4
Sound_Ram_Clear_5
STA Sound_Ram_Addr_5,X
INX
CPX #Sound_Ram_Addr_5_Size
BNE Sound_Ram_Clear_5
RTS

Get_Music_Collection_Name
PHA
LDA <Music_Item_Cur
ASL A
TAY
LDA Music_Collection_Name,Y
STA <Data_L
INY
LDA Music_Collection_Name,Y
STA <Data_H
PLA
RTS

Set_Sound_Total
LDY <Music_Item_Cur
LDA Sound_Total_Port,Y
SEC
SBC #$01
STA <Music_Total
RTS

Get_Sound_Start
LDY <Music_Item_Cur
LDA Sound_Start_Port,Y
RTS

Set_Sound_Init_Port
PHA
LDA #$20
STA <JSR_Addr_Op
LDA <Music_Item_Cur
ASL A
TAY
LDA Sound_Init_Port,Y
STA <JSR_Addr_L
INY
LDA Sound_Init_Port,Y
STA <JSR_Addr_H
LDA #$60
STA <JSR_Addr_Rts
PLA
RTS

Set_Sound_Play_Port
PHA
LDA #$20
STA <JSR_Addr_Op
LDA <Music_Item_Cur
ASL A
TAY
LDA Sound_Play_Port,Y
STA <JSR_Addr_L
INY
LDA Sound_Play_Port,Y
STA <JSR_Addr_H
LDA #$60
STA <JSR_Addr_Rts
PLA
RTS

Set_Sound_Reset_Port
PHA
LDA #$20
STA <JSR_Addr_Op
LDA <Music_Item_Cur
ASL A
TAY
LDA Sound_Reset_Port,Y
STA <JSR_Addr_L
INY
LDA Sound_Reset_Port,Y
STA <JSR_Addr_H
LDA #$60
STA <JSR_Addr_Rts
PLA
RTS

;初始化音乐bank
Init_Sound_Bank
LDY <Music_Item_Cur
LDA Sound_Bank_8000,Y
STA <Music_Bank_8000
LDY <Music_Item_Cur
LDA Sound_Bank_A000,Y
STA <Music_Bank_A000
RTS

;==================================================
Sound_State_Reset;音乐状态重置
JSR Music_Bar_ReSet      ;重置音乐条
JSR Time_ReSet             ;重置播放时间

LDA #$00
STA <Music_Stop_State
JSR Music_State_Show       ;显示播放状态

.IF Track_Name_Pos
JSR Show_Track_Info      ;音乐曲目名显示
.ENDIF

RTS

;==================================================
Sound_Init_Proc;音乐初始化处理
PHA
JSR Set_Sound_Init_Port    ;设置音乐初始化地址
LDA #$00
STA <Scroll_H               ;重设水平滚动
LDA #$0F
STA APU_STATUS
PLA
JSR Sound_Init             ;音乐初始化
JSR Sound_State_Reset      ;重置音乐播放状态
RTS

;==================================================
Sound_Play_Proc;音乐播放处理
JSR Set_Sound_Play_Port    ;设置音乐播放地址
JSR Sound_Play             ;音乐播放
RTS

;==================================================
Sound_Reset_Proc;音乐重置处理
JSR Set_Sound_Reset_Port   ;设置音乐重置地址
LDA <JSR_Addr_L
ORA <JSR_Addr_H
BEQ Sound_Reset_Proc_Default
JSR Sound_Reset            ;执行音乐重置
JMP Sound_Reset_Proc_Init_Sound

Sound_Reset_Proc_Default    ;默认音乐重置处理

;清理内存很耗费cpu周期, 这里禁用一下NMI中断
LDA #$00
STA PPU_CTRL

JSR Sound_Data_Clear

Sound_Reset_Proc_Default_Wait
LDA PPU_STATUS
BPL Sound_Reset_Proc_Default_Wait

LDA #$00
STA PPU_ADDRESS
STA PPU_ADDRESS
STA PPU_SCROLL
STA PPU_SCROLL

;恢复PPU控制
LDA Screen_Ctrl
STA PPU_CTRL

Sound_Reset_Proc_Init_Sound
LDA <Music_Stop_State
BNE Sound_Reset_Proc_End
LDX <Music_Item_Cur
LDA <Music_Cur,X
JSR Sound_Init_Proc
Sound_Reset_Proc_End
RTS

;==================================================
Clear_Item_Text;清除页项目
LDX PPU_Cur
LDA #PPU_MODE_CNT_CLEAR
STA PPU_Addr,X
INX

LDA <Page_Last
SEC
SBC <Page_Last_Index
ASL A

TAY
LDA Item_Pos_Data,Y
PHA
INY
LDA Item_Pos_Data,Y
STA PPU_Addr,X
INX
PLA
STA PPU_Addr,X
INX

LDA <Page_Last
ASL A
TAY
LDA Music_Collection_Name,Y
STA <Data_L
INY
LDA Music_Collection_Name,Y
STA <Data_H

LDY #$00
LDA ,Y
STA PPU_Addr,X
INX
Clear_Item_Text_End
STX PPU_Cur
RTS

;==================================================
Show_Item_Text;显示页项目
LDX PPU_Cur
LDA #PPU_MODE_CNT_LINE
STA PPU_Addr,X
INX
LDA Page_Cur
SEC
SBC <Page_Cur_Index
ASL A
TAY
LDA Item_Pos_Data,Y
PHA
INY
LDA Item_Pos_Data,Y
STA PPU_Addr,X
INX
PLA
STA PPU_Addr,X
INX

LDA Page_Cur
ASL A
TAY
LDA Music_Collection_Name,Y
STA <Data_L
INY
LDA Music_Collection_Name,Y
STA <Data_H

LDY #$00
LDA ,Y
STA PPU_Addr,X
STA Data_Cnt
INX

INY
Show_Item_Text_Write
LDA ,Y
STA PPU_Addr,X
INY
INX
DEC Data_Cnt
BNE Show_Item_Text_Write

Show_Item_Text_End
STX PPU_Cur
RTS

;==================================================
Get_Page_Start_Index;获取当前页号起始与条目数量
STA <Data_Buf
LDA #$00
Get_Page_Index_Calc
CLC
ADC #PAGE_SIZE
CMP <Data_Buf
BCC Get_Page_Index_Calc
BEQ Get_Page_Index_Calc_End
SEC
SBC #PAGE_SIZE
Get_Page_Index_Calc_End
STA <Data_Buf
Get_Page_Index_Cnt
LDA #PAGE_SIZE
STA Data_Cnt

LDA <Data_Buf
CLC
ADC #PAGE_SIZE
CMP #ITEM_MAX_SIZE
BCC Get_Page_Index_Cnt_End

LDA #ITEM_MAX_SIZE
SEC
SBC <Data_Buf
STA <Data_Cnt

Get_Page_Index_Cnt_End
RTS

;==================================================
Get_Last_Page_Start_Index
LDA <Music_Item_Last
JSR Get_Page_Start_Index
LDA Data_Buf
STA Page_Last
STA Page_Last_Index
LDA Data_Cnt
STA Page_Last_Cnt
RTS

;==================================================
Get_Cur_Page_Start_Index
LDA <Music_Item_Cur
JSR Get_Page_Start_Index
LDA Data_Buf
STA Page_Cur
STA Page_Cur_Index
LDA Data_Cnt
STA Page_Cur_Cnt
RTS

;==================================================
Show_Page_Text;显示页文本
LDA <Text_Disable_Flag
ORA #TEXT_DISABLE_BAR | TEXT_DISABLE_TIME | TEXT_DISABLE_ITEM
STA <Text_Disable_Flag

JSR Get_Last_Page_Start_Index
JSR Get_Cur_Page_Start_Index

Show_Page_Text_Set

Clear_Page_Last_Item;清理上一页
LDA Page_Last_Cnt
BEQ Clear_Page_Last_Item_End
JSR Clear_Item_Text
INC Page_Last
DEC Page_Last_Cnt
Clear_Page_Last_Item_End

Show_Page_Cur_Item;显示当前页
LDA Page_Cur_Cnt
BEQ Show_Page_Cur_Item_End
JSR Show_Item_Text
INC Page_Cur
DEC Page_Cur_Cnt
Show_Page_Cur_Item_End

INC <Time_Wait_Cnt
Show_Page_Text_Set_Wait;等待NMI完成PPU操作
LDA <Time_Wait_Cnt
BNE Show_Page_Text_Set_Wait

LDA Page_Last_Cnt
ORA Page_Cur_Cnt
BNE Show_Page_Text_Set
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_ITEM ^ $FF
STA <Text_Disable_Flag
RTS

;==================================================
Last_Item;上一项
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw

LDA <Music_Item_Cur
STA <Music_Item_Last

JSR Get_Last_Page_Start_Index

LDA #$00
STA Data_Buf

LDA <Page_Last
CMP <Music_Item_Cur
BNE Last_Item_Begin

LDA #$01
STA Data_Buf
Last_Item_Begin
LDA <Music_Item_Cur
BNE Last_Item_Set
LDA #ITEM_MAX_INDEX + 1
STA <Music_Item_Cur

Last_Item_Set
DEC <Music_Item_Cur
LDA <Music_Item_Cur
JSR Reset_Current_Music

Last_Item_Play
LDA Data_Buf
BEQ Last_Item_End
JSR Show_Page_Text
Last_Item_End
RTS

;==================================================
Next_Item;下一项
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw

LDA <Music_Item_Cur
STA <Music_Item_Last

JSR Get_Last_Page_Start_Index

LDA #$00
STA Data_Buf

LDA <Page_Last
CLC
ADC <Page_Last_Cnt
SEC
SBC #$01
CMP <Music_Item_Cur
BNE Next_Item_Begin

LDA #$01
STA Data_Buf
Next_Item_Begin
LDA <Music_Item_Cur
CMP #ITEM_MAX_INDEX
BCC Next_Item_Set
LDA #$FF
STA <Music_Item_Cur
Next_Item_Set
INC <Music_Item_Cur
LDA <Music_Item_Cur
LDA <Music_Item_Cur
JSR Reset_Current_Music
Next_Item_Play
LDA Data_Buf
BEQ Next_Item_End
JSR Show_Page_Text
Next_Item_End
RTS

;==================================================
Last_Page;上一页
RTS

;==================================================
Next_Page;下一页
LDA #PAGE_MAX_INDEX
CMP #$01
BEQ Next_Page_End

LDA <Music_Item_Cur
STA <Music_Item_Last

JSR Get_Last_Page_Start_Index

LDA <Page_Last_Index
CMP #PAGE_MAX_INDEX
BCS Next_Page_In_End_Page

Next_Page_Not_End_Page;不是在最后一页
LDA <Music_Item_Cur
CLC
ADC #PAGE_SIZE
CMP #ITEM_MAX_SIZE
BCC Next_Page_Not_End_Page_Less
LDA <Music_Item_Cur
SEC
SBC <Page_Last_Index
CLC
ADC #PAGE_MAX_INDEX
CMP #ITEM_MAX_SIZE
BCC Next_Page_Not_End_Page_Less
LDA #ITEM_MAX_INDEX
Next_Page_Not_End_Page_Less
STA <Music_Item_Cur
JMP Next_Page_Reset

Next_Page_In_End_Page;在最后一页
LDA <Music_Item_Cur
SEC
SBC <Page_Last_Index
STA <Music_Item_Cur

Next_Page_Reset
LDA <Music_Item_Cur
JSR Reset_Current_Music
JSR Show_Page_Text
Next_Page_End
RTS

;==================================================
Disable_Text_Draw;禁用音乐条刷新
LDA <Text_Disable_Flag
ORA #TEXT_DISABLE_BAR | TEXT_DISABLE_TIME
STA <Text_Disable_Flag
RTS

;==================================================
Clear_Last_Track_Name;清除上次曲目名
LDX <Music_Item_Cur
LDA <Music_Cur,X
.IF Track_Name_Pos
JSR Clear_Track_Info
.ENDIF
RTS

;==================================================
Reset_Current_Music;重设当前曲目

;写入当前总曲目
JSR Set_Sound_Total
LDX <Music_Item_Cur

LDA #$00
STA <Music_Last

JSR Sound_Reset_Proc
JSR Music_Show
RTS

;==================================================
Music_Song_Stop;音乐停止
LDA #$01
STA <Music_Stop_State
JSR Music_Bar_ReSet
JSR Time_ReSet
JSR Sound_Data_Clear
JSR Music_State_Show
RTS

;==================================================
Music_Song_Play;音乐播放
LDA #$00
STA <Music_Stop_State
LDX <Music_Item_Cur
LDA <Music_Cur,X
JSR Sound_Init_Proc
RTS

;==================================================
Music_Song_Last_10;上10曲
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw
LDX <Music_Item_Cur
JSR Set_Sound_Total
LDA <Music_Cur,X
SEC
SBC #10
BCS Music_Song_Last_10_Set
LDA #$00
Music_Song_Last_10_Set
STA <Music_Cur,X
JSR Sound_Reset_Proc
JSR Music_Show
Music_Song_Last_10_End
RTS

;==================================================
Music_Song_Next_10;下10曲
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw
LDX <Music_Item_Cur
JSR Set_Sound_Total
LDA <Music_Cur,X
CLC
ADC #10
CMP Music_Total
BCC Music_Song_Next_10_Set
LDA Music_Total
Music_Song_Next_10_Set
STA <Music_Cur,X
JSR Sound_Reset_Proc
JSR Music_Show
Music_Song_Next_10_End
RTS

;==================================================
Music_Song_Last;上一曲
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw
LDX <Music_Item_Cur
JSR Set_Sound_Total
LDA <Music_Cur,X
BEQ Music_Song_Last_Set
DEC <Music_Cur,X
Music_Song_Last_Set
JSR Sound_Reset_Proc
JSR Music_Show
Music_Song_Last_End
RTS

;==================================================
Music_Song_Next;下一曲
JSR Clear_Last_Track_Name
JSR Disable_Text_Draw
LDX <Music_Item_Cur
JSR Set_Sound_Total
LDA <Music_Cur,X
CMP Music_Total
BCS Music_Song_Next_Set
INC <Music_Cur,X
Music_Song_Next_Set
JSR Sound_Reset_Proc
JSR Music_Show
Music_Song_Next_End
RTS

;==================================================
Change_Select_Item;改变当前选择项
;--------------------------------------------------
Change_Select_Stop_Play_Item;停止/播放
LDA <Key_Once
CMP #$10
BNE Change_Select_Last_Item
LDA <Music_Stop_State
BNE Change_Select_Play
JSR Music_Song_Stop
LDA <Music_Stop_State
RTS

Change_Select_Play
JSR Music_Song_Play
RTS

;--------------------------------------------------
Change_Select_Last_Item;上一个专辑
LDA <Text_Disable_Flag
AND #TEXT_DISABLE_ITEM
BNE Change_Select_Item_End
LDA <Key_Once
CMP #$08
BNE Change_Select_Next_Item
JSR Last_Item
;--------------------------------------------------
Change_Select_Next_Item;下一个专辑
LDA <Key_Once
CMP #$04
BNE Change_Select_Last_10
JSR Next_Item
LDA <Music_Item_Cur
JSR Get_Page_Start_Index
;--------------------------------------------------
Change_Select_Last_10;前10曲
LDA <Key_Once
CMP #$40
BNE Change_Select_Next_10
JSR Music_Song_Last_10
;--------------------------------------------------
Change_Select_Next_10;后10曲
LDA <Key_Once
CMP #$80
BNE Change_Select_Last
JSR Music_Song_Next_10
;--------------------------------------------------
Change_Select_Last;上一曲
LDA <Key_Once
CMP #$02
BNE Change_Select_Next
JSR Music_Song_Last
;--------------------------------------------------
Change_Select_Next;下一曲
LDA <Key_Once
CMP #$01
BNE Change_Page_Next
JSR Music_Song_Next
;--------------------------------------------------
Change_Page_Next;下一页
LDA <Key_Once
CMP #$20
BNE Change_Select_Item_End
JSR Next_Page
;--------------------------------------------------
Change_Select_Item_End
RTS

;==================================================
Show_Arrow;显示箭头光标
LDA <Music_Item_Cur
JSR Get_Page_Start_Index
LDA #$00
STA PPU_OAM_ADDR
LDA <Music_Item_Cur
SEC
SBC <Data_Buf
ASL A
ASL A
ASL A
ASL A
CLC
ADC #ARROW_Y_OFFSET
STA OAM_TEMP_ADDR + $00
;STA PPU_OAM_DATA
LDA #$1F
STA OAM_TEMP_ADDR + $01
;STA PPU_OAM_DATA
LDA #$00
STA OAM_TEMP_ADDR + $02
;STA PPU_OAM_DATA
LDA #ARROW_X_OFFSET
STA OAM_TEMP_ADDR + $03
;STA PPU_OAM_DATA
RTS

;--------------------------------------------------
;命名表数据
Palette_Attributes
.IF SOUND_BAR_SHOW_ENABLE
.DB $00,$00,$00,$00,$00,$00,$00,$00,$55,$55,$55,$55,$55,$55,$55,$55
.DB $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55
.DB $55,$F5,$F5,$F5,$F5,$F5,$F5,$55,$55,$FF,$FF,$FF,$FF,$FF,$FF,$75
.DB $A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
.ELSE
.DB $00,$00,$00,$00,$00,$00,$00,$00,$55,$55,$55,$55,$55,$55,$55,$55
.DB $55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55
.DB $55,$F5,$F5,$F5,$F5,$F5,$F5,$55,$55,$FF,$FF,$FF,$FF,$FF,$FF,$75
.DB $A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
.ENDIF

;--------------------------------------------------
;调色板数据
Palette_Data
.DB $0F,$27,$20,$0F,$0F,$23,$20,$0F,$0F,$21,$20,$0F,$0F,$24,$20,$0F
.DB $0F,$21,$24,$25,$0F,$24,$20,$0F,$0F,$24,$20,$0F,$0F,$24,$20,$0F

;--------------------------------------------------
Static_Text_Data
.WORD Static_Text_Caption_Data
.WORD Static_Text_Author_Data
.WORD Static_Text_Date_Data
Static_Text_Data_End

;--------------------------------------------------
Static_Text_Pos
.DB HIGH(Caption_Text_Pos),LOW(Caption_Text_Pos)
.DB HIGH(Author_Text_Pos),LOW(Author_Text_Pos)
.DB HIGH(Date_Text_Pos),LOW(Date_Text_Pos)
Static_Text_Pos_End

;--------------------------------------------------
Music_State_Stop
.IF SOUND_BAR_SHOW_ENABLE
.DB PPU_MODE_CNT_LINE,HIGH(Play_State_Pos),LOW(Play_State_Pos),$07,"STOPPED",$00
ELSE
.DB PPU_MODE_CNT_LINE,HIGH(Play_State_Pos),LOW(Play_State_Pos),$07,"STOPPED",$00
.ENDIF
Music_State_Play
.DB PPU_MODE_CNT_LINE,HIGH(Play_State_Pos),LOW(Play_State_Pos),$07,"PLAYING",$00

;--------------------------------------------------
Sound_Bar_Text_Data;声音类型文本
.DB PPU_MODE_CNT_LINE,HIGH(Sound_Track_Pos),LOW(Sound_Track_Pos),$04,"SQ1-"
.DB PPU_MODE_CNT_LINE_NEXT,$04,"SQ2-"
.DB PPU_MODE_CNT_LINE_NEXT,$04,"TRI-"
.DB PPU_MODE_CNT_LINE_NEXT,$04,"NOI-"
.DB PPU_MODE_CNT_LINE_NEXT,$04,"DMC-",$00

.IF Track_Name_Pos

;--------------------------------------------------
Track_Name_Addr_00;曲目名地址索引
.WORD Trackr_00_01

Trackr_00_01 .DB 15,"RAF WORLD BGM 1"
Trackr_00_02 .DB 15,"RAF WORLD BGM 2"

;--------------------------------------------------
Track_Name_Addr_01;曲目名地址索引
.WORD Trackr_01_01

;==================================================
Trackr_01_01 .DB 19,"FINAL MISSION BGM 1"
Trackr_01_02 .DB 19,"FINAL MISSION BGM 2"

;==================================================
Track_Name_Addr_Port            ;曲目名地址间接索引
.WORD Track_Name_Addr_00
.WORD Track_Name_Addr_01
.WORD Track_Name_Addr_01

.ENDIF

;--------------------------------------------------
Static_Text_Caption_Data;静态文本数据
.DB 16
.DB "FC MUSIC 12 IN 1"
Static_Text_Author_Data
.DB 25
.DB "EXTRACTED BY FLAMECYCLONE"
Static_Text_Date_Data
.DB 10
.DB "2023.07.23"

;==================================================
Music_Collection_Name               ;专辑名间接索引
.DW Music_Collection_Name_00
.DW Music_Collection_Name_01
.DW Music_Collection_Name_02
.DW Music_Collection_Name_03
.DW Music_Collection_Name_04
.DW Music_Collection_Name_05
.DW Music_Collection_Name_06
.DW Music_Collection_Name_07
.DW Music_Collection_Name_08
.DW Music_Collection_Name_09
.DW Music_Collection_Name_10
.DW Music_Collection_Name_11

;==================================================
Music_Collection_Name_00            ;专辑名文本数据
.DB 11,"1.RAF WORLD"
Music_Collection_Name_01
.DB 15,"2.FINAL MISSION"
Music_Collection_Name_02
.DB 06,"3.KAGE"
Music_Collection_Name_03
.DB 16,"4.DOUBLE DRAGON"
Music_Collection_Name_04
.DB 17,"5.DOUBLE DRAGON 2"
Music_Collection_Name_05
.DB 17,"6.DOUBLE DRAGON 3"
Music_Collection_Name_06
.DB 09,"7.ROCKMAN"
Music_Collection_Name_07
.DB 12,"8.ROCKMAN 2"
Music_Collection_Name_08
.DB 12,"9.ROCKMAN 3"
Music_Collection_Name_09
.DB 12,"10.ROCKMAN 4"
Music_Collection_Name_10
.DB 12,"11.ROCKMAN 5"
Music_Collection_Name_11
.DB 12,"12.ROCKMAN 6"

;==================================================
Track_Name_Addr_Flag                ;显示曲目名标记
.DB 0,0,0,0,0,0,0,0,0,0,0,0

;==================================================
Item_Pos_Data                         ;光标箭头位置
.WORD ITEM_SHOW_POS
.WORD ITEM_SHOW_POS + $0040
.WORD ITEM_SHOW_POS + $0080
.WORD ITEM_SHOW_POS + $00C0
.WORD ITEM_SHOW_POS + $0100
.WORD ITEM_SHOW_POS + $0140

;==================================================
Sound_Init_Port               ;音乐初始化入口地址
.DW $BFC8
.DW $D7F0
.DW $9FC0
.DW $BF70
.DW $8003
.DW $BF30
.DW $9003
.DW $8003
.DW $8003
.DW $8003
.DW $8003
.DW $8003

;==================================================
Sound_Play_Port                   ;音乐播放入口地址
.DW $8000
.DW $8001
.DW $A000
.DW $8003
.DW $8000
.DW $8003
.DW $9000
.DW $8000
.DW $8000
.DW $8000
.DW $8000
.DW $8000

;==================================================
Sound_Reset_Port                  ;音乐重置入口地址
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000
.DW $0000

;==================================================
Sound_Total_Port                        ;曲目总数
.DB 38
.DB 33
.DB 49
.DB 41
.DB 83
.DB 70
.DB 50
.DB 67
.DB 57
.DB 71
.DB 76
.DB 102

;==================================================
Sound_Start_Port                      ;起始播放曲目
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00
.DB 00

;==================================================
Sound_Bank_8000                      ;专辑bank_8000
.DB $10
.DB $12
.DB $14
.DB $16
.DB $18
.DB $1A

.DB $00
.DB $02
.DB $0D
.DB $04
.DB $07
.DB $0A


;==================================================
Sound_Bank_A000                      ;专辑bank_A000
.DB $11
.DB $13
.DB $15
.DB $17
.DB $19
.DB $1B

.DB $01
.DB $03
.DB $0E
.DB $05
.DB $08
.DB $0B


;==================================================
.BANK RESET_BANK & BANK_DATA_MASK
.ORG RESET_ADDR

;==================================================
Switch_Bank_8000;切换bank到8000-9FFF
PHA
LDA #$06
STA MMC3_BANK_CTRL
PLA
STA MMC3_BANK_DATA
RTS

;==================================================
Switch_Bank_A000;切换bank到A000-BFFF
PHA
LDA #$07
STA MMC3_BANK_CTRL
PLA
STA MMC3_BANK_DATA
RTS

;==================================================
Switch_Main_Bank;切到主程序bank
LDA #PROGRAM_BANK & BANK_DATA_MASK
JSR Switch_Bank_8000   ;设置$8000地址bank
RTS

;==================================================
Sound_Reset;音乐重设(如果有的话)
JSR Switch_Music_Bank;切换到音乐bank
JSR JSR_Addr_Op      ;执行音乐重置
JSR Switch_Main_Bank   ;切回主程序
RTS

;==================================================
Switch_Music_Bank;切换音乐bank
JSR Init_Sound_Bank    ;拿到音乐bank号
LDA <Music_Bank_8000
JSR Switch_Bank_8000   ;设置$8000地址bank
LDA <Music_Bank_A000
JSR Switch_Bank_A000   ;设置$A000地址bank
RTS

;==================================================
Sound_Init;音乐初始化
PHA
JSR Switch_Music_Bank;切换到音乐bank
PLA
JSR JSR_Addr_Op      ;执行音乐初始化
JSR Switch_Main_Bank   ;切回主程序
RTS

;==================================================
Sound_Play;音乐播放
JSR Switch_Music_Bank;切换到音乐bank
JSR JSR_Addr_Op      ;执行音乐播放
JSR Switch_Main_Bank   ;切回主程序
RTS

;==================================================
MainLoop;死循环
JMP MainLoop

IRQ_SUBPROCESS_JMP = 0

.IF IRQ_SUBPROCESS_JMP
;==================================================
IRQ_Process_0;IRQ处理过程0

;15条扫描线后触发IRQ
LDA #15
STA MMC3_IRQ_LATCH

;设置屏幕滚动
LDA <Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL

IRQ_Process_0_End
INC <IRQ_Process_Index
JMP IrqProgramEnd

;==================================================
IRQ_Process_1;IRQ处理过程1

LDA #55
STA MMC3_IRQ_LATCH

;设置屏幕滚动
LDA #$00
STA PPU_SCROLL
STA PPU_SCROLL

INC <IRQ_Process_Index
JMP IrqProgramEnd

;==================================================
IRQ_Process_2;IRQ处理过程2

LDA #15
STA MMC3_IRQ_LATCH

;设置屏幕滚动
LDA #$00
SEC
SBC <Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL

INC <IRQ_Process_Index
JMP IrqProgramEnd

;==================================================
IRQ_Process_3;IRQ处理过程3

;设置屏幕滚动
LDA <Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL

;禁用IRQ
STA MMC3_IRQ_DISABLE
JMP IrqProgramEnd

IrqProcessAddr
.DW IRQ_Process_0,IRQ_Process_1,IRQ_Process_2,IRQ_Process_3

.ENDIF

;==================================================
;IRQ滚动模式常量
IRQ_SCROLL_MODE_ZERO    =   0       ;不滚动
IRQ_SCROLL_MODE_LEFT    =   1       ;向左滚动
IRQ_SCROLL_MODE_RIGHT   =   2       ;向右滚动

;IRQ扫描线数据
IRQ_Scanline_Data
.DB 8
.DB 54
.DB 8
.DB 00 ;关闭IRQ

;IRQ滚动控制模式
IRQ_Scanline_Mode
.DB IRQ_SCROLL_MODE_ZERO
.DB IRQ_SCROLL_MODE_ZERO
.DB IRQ_SCROLL_MODE_RIGHT
.DB IRQ_SCROLL_MODE_LEFT

;==================================================
;IRQ处理
IRQ_Process
LDX <IRQ_Process_Index
LDA IRQ_Scanline_Data,X
BNE IRQ_Process_Latch
IRQ_Process_Disable;禁用IRQ
STA MMC3_IRQ_DISABLE
STA IRQ_Process_Index
BEQ IRQ_Process_Scroll
IRQ_Process_Latch;设置下次 IRQ 触发扫描线
STA MMC3_IRQ_LATCH
INC <IRQ_Process_Index
IRQ_Process_Scroll;IRQ滚动控制
LDA IRQ_Scanline_Mode,X
CMP #IRQ_SCROLL_MODE_LEFT
BEQ IRQ_Process_Scroll_Left
CMP #IRQ_SCROLL_MODE_RIGHT
BEQ IRQ_Process_Scroll_Right
IRQ_Process_Scroll_Zero;不滚动
LDA #$00
STA PPU_SCROLL
STA PPU_SCROLL
RTS
IRQ_Process_Scroll_Left;向左滚动
LDA <Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL
RTS
IRQ_Process_Scroll_Right;向右滚动
LDA #$00
SEC
SBC <Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL
RTS

;==================================================
NmiProgram;Nmi中断处理
PHA
TXA
PHA
TYA
PHA

;读取清除Vblank标志, 防止重复进入
BIT PPU_STATUS

;切换主程序bank
JSR Switch_Main_Bank

;Nmi处理
JSR NmiProcess

Nmi_Proc_End
PLA
TAY
PLA
TAX
PLA
RTI

;==================================================
ResetProgram;重置中断处理
SEI
CLD
LDA #$00
STA PPU_CTRL
STA PPU_MASK

;切换主程序bank
JSR Switch_Main_Bank

;程序处理开始
JMP ProgramBegin

;==================================================
IrqProgram;Irq中断处理
PHA
TXA
PHA
TYA
PHA

;关闭IRQ
STA MMC3_IRQ_DISABLE

;允许下个IRQ触发
STA MMC3_IRQ_ENABLE

.IF IRQ_SUBPROCESS_JMP

;执行IRQ过程
LDA <Data_L
PHA
LDA <Data_H
PHA
LDA <IRQ_Process_Index
ASL A
TAY
LDA IrqProcessAddr,Y
STA <Data_L
INY
LDA IrqProcessAddr,Y
STA <Data_H
JMP

.ELSE

JSR IRQ_Process

.ENDIF

IrqProgramEnd
.IF IRQ_SUBPROCESS_JMP
PLA
STA <Data_H
PLA
STA <Data_L
.ENDIF
PLA
TAY
PLA
TAX
PLA
RTI

.ORG $FFFA
.WORD NmiProgram
.WORD ResetProgram
.WORD IrqProgram

.BANK RESET_BANK & BANK_DATA_MASK
.IF SOUND_BAR_SHOW_ENABLE

.ORG $FE00
PHA
STY $07BA
LDA #$8D
STA $07BC
TYA
CLC
ADC #LOW(Sound_Bar)
STA $07BD
LDA #HIGH(Sound_Bar)
STA $07BE
LDA #$60
STA $07BF
PLA
RTS

.ORG $FE20
STA $07BA
CLC
ADC #LOW(Sound_Bar)
STA $07BD
LDA #$8D
STA $07BC
LDA #HIGH(Sound_Bar)
STA $07BE
LDA #$60
STA $07BF
RTS

.ORG $FE40
PHA
STY $07F1
LDA #$8D
STA $07F3
TYA
CLC
ADC #LOW(Sound_Bar)
STA $07F4
LDA #HIGH(Sound_Bar)
STA $07F5
LDA #$60
STA $07F6
PLA
RTS

.ORG $FE60
STA $07F1
CLC
ADC #LOW(Sound_Bar)
STA $07F4
LDA #$8D
STA $07F3
LDA #HIGH(Sound_Bar)
STA $07F5
LDA #$60
STA $07F6
RTS

.ORG $FF40
STA $4000
STA Sound_Bar + $00
RTS

.ORG $FF48
STA $4004
STA Sound_Bar + $04
RTS

.ORG $FF50
STA $4008
STA Sound_Bar + $08
RTS

.ORG $FF58
STA $400C
STA Sound_Bar + $0C
RTS

.ORG $FF60
STX $4000
STX Sound_Bar + $00
RTS

.ORG $FF68
STX $4004
STX Sound_Bar + $04
RTS

.ORG $FF70
STX $4008
STX Sound_Bar + $08
RTS

.ORG $FF78
STX $400C
STX Sound_Bar + $0C
RTS

.ORG $FF80
STY $4000
STY Sound_Bar + $00
RTS

.ORG $FF88
STY $4004
STY Sound_Bar + $04
RTS

.ORG $FF90
STY $4008
STY Sound_Bar + $08
RTS

.ORG $FF98
STY $400C
STY Sound_Bar + $0C
RTS

.ORG $FFA0
STA $4000,X
STA Sound_Bar + $00,X
RTS

.ORG $FFA8
STA $4000,Y
STA Sound_Bar + $00,Y
RTS

.ORG $FFB0
STA $4004,X
STA Sound_Bar + $04,X
RTS

.ORG $FFB8
STA $4004,Y
STA Sound_Bar + $04,Y
RTS

.ORG $FFC0
STA $4008,X
STA Sound_Bar + $08,X
RTS

.ORG $FFC8
STA $4008,Y
STA Sound_Bar + $08,Y
RTS

.ORG $FFD0
STA $400C,X
STA Sound_Bar + $0C,X
RTS

.ORG $FFD8
STA $400C,Y
STA Sound_Bar + $0C,Y
RTS

.ENDIF

**** Hidden Message *****

leshui 发表于 2023-8-5 12:37:15

非常支持您
页: [1]
查看完整版本: [FC][音乐12 IN 1][nes + 源码]