FC红白机NSF提取教程

Contra (J) NSF Dump

进入声音模式

使用FCEUX模拟器打开ROM, 标题画面下按 A + B + Start进入声音模式

在此界面, B键播放, A键停止.

在这里插入图片描述

声音入口查找步骤

  1. 先添加声音寄存器 4000 写断点
  2. 单击 Run 等待断点触发(如果此时程序处于暂停状态)
  3. 发生断点暂停后, 如果执行地址不在 C 000 − C000- C000FFFF, 则单击 Step Out
  4. 否则添加断点记录上一条JSR指令的跳转地址的执行断点, 并禁用添加的新断点
  5. 重复执行步骤1

开始查找

先确保声音没有播放(如果在播放则按A键停止)

打开调试器

在这里插入图片描述

添加声音寄存器 4000 的写入断点

在这里插入图片描述

在这里插入图片描述

单击激活模拟器主窗口, 然后按B键播放声音

调试器停在

>01:8736: 8D 00 40  STA $4000 = #$30

在这里插入图片描述

这里地址是8736, 按 Step Out (跳出), 直到执行地址在C000-FFFF为止, 调试器停在

>07:F9DE: 20 AF F9  JSR $F9AF

在这里插入图片描述

这里地址是F9DE, 上一行是

 07:F9DB: 20 19 87  JSR $8719

添加断点记录8719的执行断点

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

双击刚刚添加的新断点进行禁用(禁用后断点前面没有字母E)

在这里插入图片描述

单击运行

断点停留在

>01:88B5: 9D 00 40  STA $4000,X @ $4000 = #$30

在这里插入图片描述

这里地址是88B5, 按 Step Out (跳出), 直到执行地址在C000-FFFF为止, 调试器停在

>07:F9CA: 20 AF F9  JSR $F9AF

在这里插入图片描述

这里地址是F9CA, 上一行是

 07:F9C7: 20 A2 87  JSR $87A2

添加断点记录87A2的执行断点

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

双击刚刚添加的新断点进行禁用(禁用后断点前面没有字母E)

在这里插入图片描述

单击运行

断点停留在

>01:8189: 9D 00 40  STA $4000,X

在这里插入图片描述

这里地址是8189, 按 Step Out (跳出), 直到执行地址在C000-FFFF为止, 调试器停在

>07:F8C6: 20 BD C1  JSR $C1BD

在这里插入图片描述

这里地址是F8C6, 上一行是

 07:F8C3: 20 D5 80  JSR $80D5

添加断点记录80D5的执行断点

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

双击刚刚添加的新断点进行禁用(禁用后断点前面没有字母E)

在这里插入图片描述

后续再重复执行声音入口查找步骤, 得到的依旧是80D5, 重复的就不再进行断点记录添加

提取数据

单击执行, 此时模拟器暂停

在这里插入图片描述

此时执行的程序位于第01个16KB数据块中

使用 Hxd 打开 Contra (J) [!].nes, 按 Ctrl + G, 跳转到十六进制地址 01 * 4000 + 10 = 4010 地址

在这里插入图片描述

在这里插入图片描述

按 Ctrl + E, 选择 4010 起始的十六进制的4000字节数据

在这里插入图片描述

单击文件 -> 选取另存为…

在这里插入图片描述

文件名暂且叫做

Contra (J) [!] 8000_BFFF.bin

在这里插入图片描述

提取DMC数据

添加声音寄存器 4012 的写入断点

在这里插入图片描述

只启用4012 的写入断点

在这里插入图片描述

单击运行, 调试器暂停

在这里插入图片描述

可以看到, 向声音寄存器 4012 写入的数据是在8915,Y

打开模拟器的 Debug -> Hex Editor…

在这里插入图片描述

按 Ctrl + G 输入 8915, 单击 OK, 跳转到指定位置

在这里插入图片描述

在这里插入图片描述

这里的数据, 分析调试器中的程序

 01:88F3: B9 13 89  LDA $8913,Y @ $8917 = #$0F
 01:88F6: 8D 10 40  STA $4010 = #$0F
 01:88F9: B9 14 89  LDA $8914,Y @ $8918 = #$75
 01:88FC: 8D 11 40  STA $4011 = #$75
 01:88FF: B9 15 89  LDA $8915,Y @ $8919 = #$F3
>01:8902: 8D 12 40  STA $4012 = #$F0
 01:8905: B9 16 89  LDA $8916,Y @ $891A = #$25
 01:8908: 8D 13 40  STA $4013 = #$05

可以知道, 从 8913开始, 每4字节一组, 分别写入声音寄存器的4010-4013

观察了一下, 从8913开始的16个字节应该是有规律的4组数据

0F 2F F0 05 
0F 75 F3 25 
0F 7F F3 03 
0F 00 F3 25

关于DMC数据地址与长度可以参考 APU DMC - NESdev Wiki

于是可以得到4段DMC数据地址与长度

F0 05 -> F0 * 40 + C000 = FC00, 长度 0x50 字节
F3 25 -> F3 * 40 + C000 = FCC0, 长度 0x0250 字节
F3 03 -> F3 * 40 + C000 = FCC0, 长度 0x30 字节
F3 25 -> F3 * 40 + C000 = FCC0, 长度 0x0250 字节

也就是FC00开始的数据基本都是DMC数据

按 Ctrl + G 输入 FC00, 单击 OK, 跳转到指定位置

在这里插入图片描述

选中 FC00-FFFF 范围内数据

在这里插入图片描述

然后 单击 Edit -> Copy 拷贝一下

在这里插入图片描述

然后在Hxd中按 Ctrl + N 新建空白文件

在这里插入图片描述

然后 按 Ctrl + V 粘贴数据

在这里插入图片描述

然后Ctrl + S 保存, 文件名暂且叫做

Contra (J) [!] .dmc

在这里插入图片描述

在这里插入图片描述

区分播放入口与初始化入口

从上面操作中已经得到3个相关声音入口: 8719, 87A2, 80D5

那么哪个是播放入口, 哪个初始化入口呢?

思路如下

  • 如果声音没有播放时, 都会执行的, 那么一般就是播放入口
  • 如果从静音到播放时才会被执行一次的入口, 一般就是初始化入口, 而且播放不同曲目时, 执行入口时寄存器A的值是不同的

找出播放入口

按A键停止音乐播放, 然后在调试器中仅启用3个入口的断点,

结果80D5断点被执行了, 那么可以确定这个入口就是播放入口了

在这里插入图片描述

修改下断点描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

找出初始化入口

还剩下2个相关声音入口: 8719, 87A2

先禁用全部断点

在这里插入图片描述

然后单击 Run 继续运行

在这里插入图片描述

仅启用8719, 87A2的执行断点

在这里插入图片描述

然后按B键播放曲目, 执行8719时, 调试器暂停, 此时寄存器A = 80

在这里插入图片描述

单击 Run 继续运行, 执行87A2时, 调试器暂停, 此时寄存器A = 46

在这里插入图片描述

然后禁用全部断点

在这里插入图片描述

单击 Run 继续运行

在这里插入图片描述

然后单击模拟器主窗口, 先按 A键 停止播放, 再按下键切换到不同曲目

在这里插入图片描述

在调试器中仅启用8719, 87A2的执行断点

在这里插入图片描述

然后模拟器主窗口中按 B键 播放曲目, 执行8719时, 调试器暂停, 此时寄存器A = 80

在这里插入图片描述

单击 Run 继续运行, 执行87A2时, 调试器暂停, 此时寄存器A = 5A

在这里插入图片描述

这时候可以确定初始化入口是87A2

修改下断点描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

提取曲目号

禁用所有断点, 单击 Run 继续执行

在这里插入图片描述

在模拟器窗口中按 A键 停止播放

单击 Debug -> Trace Logger 打开执行日志记录窗口

在这里插入图片描述

在这里插入图片描述

单击 Start 开始记录

在这里插入图片描述

在调试器窗口仅启用87A2初始化断点

在这里插入图片描述

在模拟器窗口按 B键 播放曲目, 调试器暂停, 此时A = 5A

在这里插入图片描述

在日志记录器中查找到 5A 这个曲目号来自于这里

$04:A7F6: B9 2A AA  LDA $AA2A,Y @ $AA2B = #$5A

在这里插入图片描述

于是知道了这个 5A 来源后, 可以在调试器中添加一个读取断点

在这里插入图片描述

断点地址: A7F6, 条件: $AA2B == #5A

在这里插入图片描述

在这里插入图片描述

然后仅启用这个断点, 再单击运行继续执行

在这里插入图片描述

然后在模拟器中按B键再次播放曲目

在这里插入图片描述

打开模拟器 Debug -> Hex Editor

按 Ctrl + G, 输入 AA2A, 回车跳转到指定地址

在这里插入图片描述

在这里插入图片描述

这里的46就是最开始的曲目号

调试器上单击 Run 继续执行

在这里插入图片描述

然后再模拟器中将光标移动到最后一个曲目后按 B键 播放

调试器暂停, 得到最后一个曲目号为 72

在这里插入图片描述

回到 Hex Editor, 选中 起始曲目号 46 到终止曲目号 72 在内的数据

在这里插入图片描述

按 Ctrl + C 拷贝

然后在Hxd中, 按Ctrl + N 新建空文件, 再按 Ctrl + V 粘贴

在这里插入图片描述

然后Ctrl + S 保存, 文件名暂且叫做

Contra (J) [!] track.bin

在这里插入图片描述

在这里插入图片描述

生成NSF文件

新建文本文件 Contra (J) [!].asm

在这里插入图片描述

内容写上, 然后保存

;Contra (J) NSF
;Dump By FlameCyclone
;2025.8.4
	.INSFVERSION              	1				;版本
	.INSFTOTALSONGS           	43 				;总曲目 Contra (J) [!] track.bin 43字节
	.INSFSTARTSONG           	1				;起始曲目
	.INSFLOAD					$8000			;数据载入地址
	.INSFINIT     				Init_Addr		;初始化地址
	.INSFPLAY               	$80D5			;播放地址
	.INSFNAME                  	"Contra"		;专辑名
	.INSFARTIST              	"H. Maezawa, K. Sada"	;作者
	.INSFCOPYRIGHT         		"1988 Konami"	;版权
	.INSFSPEEDNTSC     			16666			;NTSC播放速度
	.INSFBANKSWITCH           	0,1,2,3,4,5,6,7 ;4KB数据块布局
	.INSFSPEEDPAL          		16666			;PAL播放速度
	.INSFSTANDARD             	0				;制式标准
	.INSFEXTRASOUND            	0				;扩展音源

;音乐数据
 .BANK16 0
 .ORG $8000
	.INCBIN "Contra (J) [!] 8000_BFFF.bin"

;DMC数据
 .BANK16 1
 .ORG $C000
	.INCBIN "Contra (J) [!] .dmc"

;初始化处理
Init_Addr
	TAX
	LDA Track_Data,X
	JMP $87A2;跳转到初始化入口

;曲目号数据
Track_Data
	.INCBIN "Contra (J) [!] track.bin"

打开 nesasm_Gui_3_2, 将刚刚保存的文件 “Contra (J) [!].asm” 拖到输入到nesasm_Gui_3_2窗口

在这里插入图片描述

单击编译生成nsf文件

在这里插入图片描述

在这里插入图片描述

模拟器打开试听, 发现DMC怪怪的

在这里插入图片描述

这是因为原本DMC数据地址是在FC00, 我这里是放在C000

那么需要将此前写入4012的F0和F3修改才行

F0和F3对应FC00和FCC0,

那么改成00和03对于C000和C0C0即可

结合此前写入声音寄存器4012的数据

在这里插入图片描述

可以得到

8915 F0
8919 F3
891D F3
8921 F3

于是在 “Contra (J) [!].asm” 中进行简单修改即可, 最后源码改成如下

;Contra (J) NSF
;Dump By FlameCyclone
;2025.8.4
	.INSFVERSION              	1				;版本
	.INSFTOTALSONGS           	43 				;总曲目 Contra (J) [!] track.bin 43字节
	.INSFSTARTSONG           	1				;起始曲目
	.INSFLOAD					$8000			;数据载入地址
	.INSFINIT     				Init_Addr		;初始化地址
	.INSFPLAY               	$80D5			;播放地址
	.INSFNAME                  	"Contra"		;专辑名
	.INSFARTIST              	"H. Maezawa, K. Sada"	;作者
	.INSFCOPYRIGHT         		"1988 Konami"	;版权
	.INSFSPEEDNTSC     			16666			;NTSC播放速度
	.INSFBANKSWITCH           	0,1,2,3,4,5,6,7 ;4KB数据块布局
	.INSFSPEEDPAL          		16666			;PAL播放速度
	.INSFSTANDARD             	0				;制式标准
	.INSFEXTRASOUND            	0				;扩展音源

;音乐数据
 .BANK16 0
 .ORG $8000
	.INCBIN "Contra (J) [!] 8000_BFFF.bin"

;修正DMC起始地址
 .BANK16 0
 .ORG $8915
 .DB $F0 - (($FC00 - $C000) / $40)
 
 .ORG $8919
 .DB $F3 - (($FC00 - $C000) / $40)
 
 .ORG $891D
 .DB $F3 - (($FC00 - $C000) / $40)
 
 .ORG $8921
 .DB $F3 - (($FC00 - $C000) / $40)

;DMC数据
 .BANK16 1
 .ORG $C000
	.INCBIN "Contra (J) [!] .dmc"

;初始化处理
Init_Addr
	TAX
	LDA Track_Data,X
	JMP $87A2;跳转到初始化入口

;曲目号数据
Track_Data
	.INCBIN "Contra (J) [!] track.bin"

在这里插入图片描述

保存源码后再次编译

在这里插入图片描述

再次使用模拟器打开, DMC数据也正常了, NSF提取就算成功了.

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值