注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

深夜是徘徊在潮湿睫毛上的我的梦以及他的梦

是直到最后都无法放手的一种气息,是我们生命中最后的思念……

 
 
 

日志

 
 

NSF音乐植入NES的一个初步方法  

2012-06-17 23:09:00|  分类: FC教程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

叶枫 & 维京猎人

 

 

NSF是一种播放NES音乐的文件,其内部不光是音乐数据,而是还有一段程序,nsf的播放其实要依赖这个程序。为什么程序会在音乐文件里面?这说明了,大部分nsf的程序是不同的,同时数据结构也是不同的,如果只取出数据,用同一个播放程序,那是播不了所有的。换句话说:从不同的nsf中取出音乐数据,是有可能不能用同一个程序播放。

 

原因之一是,NES的基本音乐是由NESCPU内嵌音乐合成器完成的,而NES的高级卡带有特殊声音芯片,那么不同的特殊声音芯片对应的nsf就要有所不同了。这种不同不光是出现在mapper上,还会出现在程序上。在我的一次试验中就出现了声音的损失。

 

那么能不能对于没有特殊声音芯片的nsf有一个统一的程序,而对应不同的特殊声音芯片有相应的程序;更理想的是有一个万能播放程序。。。那我现在回答不了。我只能说我的下一步,将是先对nsf进行分类,将有同一播放程序的nsf归为一类。然后才是分析不同的程序。

 

以上只是我个人的猜测,真正缘由只能留给任天堂来回答。

 

 

那么一切都是围绕“寻找程序”和“寻找数据”这两个主题。

我们现在来看看NSF文件。

我这里有NSF文件的资料。

 

任天堂声音文件NSF(Nintendo Sound File)头格式

偏移地址

字节数

类型

            

$0000

5

字符串

"NESM",$1A;  NSF必须的信息,用来识别NSF文件

$0005

1

字节

当前NSF文件的版本号

$0006

1

字节

NSF中乐曲数

$0007

1

字节

起始播放乐曲的号码

$0008

2

载入的内存地址,范围($8000-$FFFF)

$000A

2

初始化开始的地址,范围($8000-$FFFF)

$000C

2

乐曲播放地址,范围($8000-$FFFF)

$000E

32

字符串

游戏或乐曲的标题

$002E

32

字符串

曲作者或艺术家名称

$004E

32

字符串

版权部分,附加说明等

$006E

2

NTSC制式下乐曲循环播放速度,常为$411A

$0070

8

字节

Bank切换, 初始8bit,详细请看下面⑴

$0078

2

PAL制式下乐曲循环播放速度

$007A

1

字节

PAL/NTSC制式选择,详细请看下面⑵

$007B

1

字节

特殊声音芯片,详细请看下面⑶

$007C

4

字节

4个多余字节,未用,以后可能用到,必须都为$00

$0080

XXX

字节

NSF的程序和数据

 

注解:

      .6502的寻址空间为64K,但是NES却只用$8000-$FFFF,32K,有可能.NSF也会遇到空间不够的情况,这时就要用到存储体(Bank)切换.NSF存储体(Bank)切换大小为4K.

      .PAL/NTSC制式选择:

         007AH

         D0 : 0,NTSC制式;1,PAL制式

         D1 : 如果为1, NTSC/PAL制式

        即

0,NTSC

1,PAL

23,双制式

   D2-D7 : 未用,但必须都为0

 

      .声音芯片:

         D0:1,Konami(VRC6)

         D1:1,Konami(VRC7)

         D2:1,Nintendo(FDS)

         D3:1,Nintendo(MMC5)

         D4:1,Namco(106)

         D5:1,Sunsoft(FME7)

         D6-D7:当前未用,为将来扩充功能用.会有更多的声音芯片出现的可能.

 

 

我们找到一个nsf,它足够简单,我们来分析它的文件头信息:

 

Contra.nsf一个美版的魂斗罗I,用HEX工具打开。只看前面$80个字节(即文件头)

NSF音乐植入NES的一个初步方法 - 维京人 - 深夜是徘徊在潮湿睫毛上的我的梦以及他的梦

 

[图1]

我们按头文件来进行解读。

偏移地址

例子内容

信息

$0000-$0004

4e45 534d 1a

“NESM”+1AH,表示自己是NSF

$0005

01

版本号=$01=1

$0006

0b

乐曲数量=$0b=11

$0007

01

起始播放乐曲的号码=$01,由第1首开始播

$0008-$0009

0080

载入的内存地址=$8000

$000A-$000B

bec3

初始化开始的地址=$C3BE

$000C-$000D

d580

乐曲播放地址=$80D5

$000E-$002D

436f 6474 7261 00…00

标题=”Contra”

$002E-$004D

482e 204d 6165 …

艺术家=”H. Maezawa, K. Sada”

$004E-$006D

3139 3838 204b …

版权说明=”1988 Koami”

$006E-$006F

1a41

NTSC制式下乐曲循环播放速度=$411A=16666

$0070-$0077

0000 0000 0000 0000

Bank切换信息(本NSF没有切页)

$0078-$0079

0000

PAL制式下乐曲循环播放速度=$0000

$007A

00

制式选择=NTSC

$007B

00

特殊声音芯片=没有

$007C-$007F

0000 0000

未用

我们看看模拟器显示的信息:

NSF音乐植入NES的一个初步方法 - 维京人 - 深夜是徘徊在潮湿睫毛上的我的梦以及他的梦

 

[图2]

 

与上表对比,正好对位。

 

对于我们有用的数据:

载入的内存地址,初始化开始的地址,乐曲播放地址。

 

留意本例:

载入的内存地址=$8000

初始化开始的地址=$C3BE

乐曲播放地址=$80D5

 

我们来查看NSF载入到内存后的情况。

Fcdebug打开本例子,点击RAM

拉到$8000的位置

这里显示的数据与NSF$0080开始的数据完全一样。这说明本NSF除文件头以外全部载入到模拟器的$8000的位置。

本例大小是17K,凡32K以下都没切页,那么处理都比较简单。

 

本教程目前只讨论没有切页和不用特殊声音芯片NSF

 

下面我们通过一个实验将NSF塞进一个空的NES,目的是看看这3个地址我们上、是怎么利用的。下面的内容要求读者对6502汇编非常熟悉,并会编写汇编程序。

 

 

第一步,我们要取出NSF中的程序和数据(即内存文件)

因为这个例子是小于32K的,那么我们只要简单的去掉文件头就行,同时还有一点空间写入属于NES的主程序。如果是等于32K,那么主程序就没有位置写了;如果是大于32K那要从Fcdebug中用DUMP的方法来取出。

方法:

1HEX工具打开NSF,删除前$80=128字节,即$0000-$007F。另存为同名的mem内存文件。本例(Contra.nsf)Contra.mem

2然后用Fcdebug打开NSF,打开RAM,查看程序和数据结束的位置,本例在$C3CF处结束。记下这个数。

 

第二步,写一个NES主程序

新建记事本TXT文本,输入代码,保存成asm文件。(本例是Contra.asm)代码如下

       .inesprg 2   ;2 x 16 = 32k

       .ineschr 0   ;no chr rom

       .inesmap 0   ;no mapper

       .inesmir 0   ;mirror

 

MUSIC_INI   equ    $c3be

MUSIC_PLAY  equ    $80d5

DataLoad    equ    $8000

 

       .bank 0

       org DataLoad

       .incbin "Contra.mem"

      

       .bank 3

       .org $e000

reset:

       sei

       cld

       ldx #$ff

       txs

       inx

       stx $2001

      

       lda #1

       jsr MUSIC_INI

      

       lda #$80

       sta $2000

loop:

       jmp loop

      

nmi:

       jsr MUSIC_PLAY

irq:  rti

      

       .org $fffa

       .dw  nmi

       .dw  reset

       .dw  irq

注意,本代码中不能写中文注释。同时每行语句前面一定要加一个Tab或空格。而标签必须顶行写。

本代码用nesasm.exe编译。

 

本代码中的主程序开始位置在$E000。与NSF结束位置没有冲突,就是说主程序没有覆盖NSF。否则应适当调整主程序的位置。

 

第三步,建立批文件

新建记事本TXT文本,输入脚本,保存成bat文件,(本例是生成nes.bat”)脚本如下:

nesasm Contra.asm

pause

 

第四步,生成NES

把代码Contra.asm,内存文件Contra.mem,批文件生成nes.bat”,还有nesasm.execygwin1.dll放在同一个文件夹中,然后双击批文件生成nes.bat”

 

OK.这就生成Contra.nes

 

用模拟器打开Contra.nes可以听到本例NSF01号乐音在循环播放。

 

总结一下:

本代码中

DataLoad是指向“载入的内存地址”,那么从NSF取出的内存文件,因为其中包括了程序,那么载入的地址不能有变化。(接下来的研究,必然要解决这个问题)

       .bank 0                 ; bank0开始,代码部分每个bank8K

       org DataLoad            ; 从原本的载入位置定位

       .incbin "Contra.mem"     ; 载入内存文件

 

指定下面程序的位置

       .bank 3

       .org $e000

Bank中指nesROM中的分块,PROM部分每bank8K,那么Contra.mem17K

Bank0必定是$8000$C000开始的,现在Bank0后面定位的org,指定DataLoad$8000,那么就是从$8000开始。

Bank 0 : $8000 - $9FFF

Bank 1 : $A000 - $BFFF

Bank 2 : $C000 - $DFFF

Bank 3 : $E000 - $FFFF

 

于是这样就合理了。

 

接下来是NES的初始化

reset:

       sei

       cld

       ldx #$ff

       txs

       inx

       stx $2001

 

MUSIC_INI是指向“初始化开始的地址”,也就是说

       lda #1

       jsr MUSIC_INI

指定播放第01首音乐。

 

开启中断功能,并进入死循环。

       lda #$80

       sta $2000

loop:

       jmp loop

 

每次中断播放一部分,MUSIC_PLAY是指向“乐曲播放地址”。

nmi:

       jsr MUSIC_PLAY

 

 

好这次教程就到这里,大家自己研究研究吧。

 所有文件可以到我的网盘下载

http://fogota.ys168.com/

找到"FC-研究和教程" \  "NSF植入到nes的方法.rar"

2012-6-17 父亲节

  评论这张
 
阅读(3288)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017