15、音乐

我前段时间写了一篇关于NES Audio文章。

https://nesdoug.com/2015/12/02/14-intro-to-sound/ (往下翻,在后面有翻译)

我们不需要对声音寄存器了解太多,我们使用Famitracker编音乐,用Famitone 2 v1.15播放音乐,我的例子中都包含famitone代码,这就足够用的了。

你需要做的就是把音乐数据文件包含在music_data下的crt0.s文件中。

我对音乐制作不是很擅长,你可以看看这个

https://youtu.be/UbGfosQHfm0

(墙外地址,以后有空再搬运油管的视频)

我很喜欢这个工具,famitone2还是有些局限性。

(这些东西有些专业,暂时不翻译了,以后再说)

1、No volume column.

2、Allowed notes are C-1..D-6, Note Cut

3、Only Volume, Arpeggio, and Pitch sequences

4、All instruments should have a volume envelope assigned

5、no Duty sequence

6、64 instruments max

7、no fx except Tempo Fxx, Looping backwards Bxx, and ending the frame early D00

8、Up to 17 sub songs in a file

由于没有音量的列,你制作的时候需要使用不同的乐器(最大的音量不同)来制作音乐。

将每首歌放到同一个文件夹中,使用“module properties”添加歌曲

一切都完成后,导出一个txt文件。您需要使用famitone2程序text2data.exe处理此文件。使用命令行,并添加-ca65开关,以便我们的汇编器在读取它时不会有任何问题。如果你想看看它们的样子,我把/ MUSIC中的所有文件都留了下来。

我写了2段音乐并放到了游戏中。

music_play(0) 播放第一段音乐

music_play(1) 播放第二段音乐

按 START 按钮切换音乐

neslib代码自动更新音频寄存器以匹配歌曲。在nmi代码的末尾,每帧调用一次FamiToneUpdate。

暂停音乐 music_pause(1)

继续播放 music_pause(0)

停止音乐 music_stop()

PS:我写了一个方法用来改变音乐的播放速度。通常情况下你只能在famitracker文件中设置速度。

比如boss战的时候我们希望音乐加速播放,或者是受伤等状态需要减速播放音乐,都可以使用上面的方法轻松实现

set_music_speed()

数字越小意味着越快,越大意味着越慢。6是默认值。

https://github.com/nesdoug/18_Music

另外,还有其他音乐驱动程序。

Pently,有一些游戏用了这个工具,如果你喜欢使用乐谱写音乐,可能这个是一个比较好的选择。他使用描述语言,用音乐宏(MML)或者LilyPond

https://github.com/pinobatch/pently

ggsound 是另一个选择,NESmaker这个软件使用了这个(使用方式不详)

https://github.com/gradualgames/ggsound

完整的famitracker驱动程序是另一种选择,但它非常大,比其他驱动程序慢一点。你可以从shiru的示例文件中获取它。

https://shiru.untergrund.net/files/src/cc65_neslib_famitracker.zip

本地镜像此文件

您可以查看cppchriscpp的示例代码

https://github.com/cppchriscpp/nes-starter-kit/tree/master/source/neslib_asm/ft_drv

我还写了2个关于famitone的非官方更新

https://nesdoug.com/2018/09/05/links-and-misc/


声音介绍

你可能会为NES使用APU发声的功能犯愁,但是用了Famitracker以后,这一切都变得简单了。

下载SnoBrow开发的Sound Test NES

http://nesdev.com/sndtest.zip

本地镜像缓存

他可能无法兼容所有的模拟器,FCEUX上运行没问题。

按 SELECT 按键切换声道,按 START 按键会触发声音播放。

该程序中,通道0=方波1,通道1=方波2,通道3=三角波,通道4=噪声

声音寄存器映射到$ 4000-4017

4000-4003 =方波1寄存器

4004-4007 =方波2寄存器

4008-400b =三角波寄存器

400c-400f =噪声寄存器

4010-4013 = DMC频道

4015 =控制音频输出

4017 =帧计数器

从http://wiki.nesdev.com/w/index.php/APU 搬运来的

4000-4003 = Square 1 channel

4000 = DDLC VVVV

D =占空比,改变声波的形状(10=平滑,01 或 11 =ok,00=annoying......让我想起Atari的声音)。

L =循环(重复声音)

C =等容体

V =音量(有时)

如果L或C都没有设置,他开始的时候声音很大,然后声音变小,再变小。。。

如果您将音符长度设置为0000 1(在寄存器4003中),你可以听到音量变化。V =音符长度,V为0时候还是会有声音。

如果设置了L(而C不设置),则V =重复声音的速度。较小的V =较快的重复声音。(满音量)0的V是快速的哔哔声。

如果设置了C和L,V将控制通道的音量,并且音符将无限播放,直到您将另一个值写入4000.这实际上是它在音乐代码中一直设置的方式。您可以通过计算帧来控制长度,通过每帧更改音量来创建音量包络,并通过设置音量为零或频率为零来结束音符。 要使方形通道静音,请将音量设置为零($ 4000 = $ 30)。

4001 - 频率扫描寄存器

4001 = EPPP NSSS

E =打开频率扫描

P =更小=更快的扫描

N = 0 =向下扫描,1 =向上扫描

S =更小=更快的扫描

请注意,一旦到达扫描结束,即使您将其设置为不断播放,音符也会停止。设置扫描和循环将重复几次,直到扫描结束。这可以产生很酷的效果。

4002 = TTTT TTTT =音符频率的低字节

4003 = LLLL LTTT

L =影响音符的长度,假设您没有将其设置为播放常量音符 (L&C均设置为4000)。非常奇怪的设置。0000 1 =很长的音符。

T =音符频率的高3位。

注意:为了播放最低音符,必须设置N标志($ 4001)(例如,某些游戏在扫描关闭时写入$ 7f到$ 4001)。

另外:可播放的最高音符是000..0000 1000.任何频率更高(例如000..0000 0111)将从Square 1频道产生静音。你不会想要它更高,它在较高频率范围内非常烦人。

-----------

4004-4007 = Square 2 Channel,与Square 1完全相同。

-----------

4008-400b =三角形通道

4008 - CRRR RRRR(C =常数,无限音符)

R =很奇怪。更改这些数字似乎会影响音符的长度。只需将此值设置为$ ff表示常量音符,将$ 80设置为off(静音)。如果设置为$ 7f,则长度将由$ 400b的L位控制。(感谢Pokun 纠正我)。

4009 - 未使用。

400a - TTTT TTTT - 音符频率的低字节

400b - LLLL LTTT - 频率的长度和高位...有关详细信息,请参见Sq 1通道。

注意 - 三角形通道没有音量控制。此外,它将比方形通道上的相同设置低1个八度音程。与方形通道不同,三角形频率可以高于000 0000 1000(例如000 0000 0100),并且播放非常高的音高。

----------

400c-400f =噪声通道

400c - xxLC VVVV - 与方波通道相同,但没有占空比。

400d - 未使用

400e - Z - - - TTTT

Z =如果为0,听起来像白噪声

如果是1,听起来像金属铿锵声

T =音符频率,更多=更低。频率为零将播放最高音调。

400f - LLLL L - - - -

L =影响音符的长度,假设未设置为播放常量音符(L&C均设置)。

要使噪声通道静音,请将音量设置为零($ 400c = $ 30)。

-----

DMC频道,是一种低采样率的声音压缩。最快的采样率提供了合理的音质,但占用了大量的ROM空间。较慢的采样率占用较少的空间,但是具有恼人的高音调嗡嗡声和较低质量的声音。

谨慎使用DMC。您也可以使用非常短的循环样本,这可能适用于Bass Notes。我认为DMC最常见的用途是改进鼓声,以及听起来像人类语音的单个单词 - “战斗”。

4010 - IL- - RRRR

I =设置DMC触发的IRQ

L =循环样本

R =采样率(F =最高)

4011 - xDDD DDDD =加载。基本上是样本的起始值,这里的一些设置将使样本更安静。这也可以用来(通过不断改变值)来制作高质量的PCM声音。

4012 - AAAA AAAA =样本的地址......

%11AA AAAA.AA00 0000

因此,最低地址是11000000 00000000 = $ C000

...最高地址是11111111 11000000 = $ ffc0。

注意,DMC样本必须位于$ c000和$ ffff之间。您可以使用Famitracker制作样品。

4013 - LLLL LLLL =样本长度......

%LLLL.LLLL 0001

最小的样本是10001 = $ 11字节。最大的样本是$ ff1字节。(你可以背靠背地播放样本,如果它太短了)。

4015 - 控制打开哪些通道。使用此功能启动和停止DMC通道。

4015 - - - 5 4 3 2 1

1. Square 1

2. Square 2

3. Triangle

4. Noise

5. DMC

4017 - 我从来没有学过这是为了什么,除了大多数游戏的启动代码在开始时存储0x40,我想要关闭某种IRQ。

-------

对于前4个通道,注释将在其最后一个寄存器被写入时触发... 4003触发方形1,4007触发方形2,400b - 三角形,400f噪声。反复写入这些(每一帧)可能会产生令人不快的点击。

要触发DMC声音,首先将$ 0f写入4015,然后将$ 1f写入4015.或者,如果DMC样本已结束,仅将$ 1f写入4015将重新触发样本进行播放。

------

额外的声道。一些高级映射器(特殊盒式磁带)具有额外的声道。例如,VRC7拥有更先进的FM合成芯片(仅用于1游戏,Lagrange Point)。

-------

PCM,即。高品质的声音。我从来没有尝试过这个,但我的理解是,你可以通过将值一遍又一遍地写入4011来模拟高质量的声音。这将花费大量的CPU,以至于在这种情况下运行游戏逻辑是不可能的。也许它可以在静态标题屏幕上完成。

--------

让我们添加一些快速声音代码,只是为了好玩。如果需要,将其插入其中一个课程的无限循环中。确保声道已打开...

*((unsigned char *)0x4015)= 0x0f;

//快速哔 -

if(((joypad1old&START)== 0)&&((joypad1&START)!= 0)){

*((unsigned char *)0x4000)= 0x0f;

*((unsigned char *)0x4003)= 0x01;

}

//扫频效果 - 跳跃声音

if(((joypad1old&START)== 0)&&((joypad1&START)!= 0)){

*((unsigned char *)0x4000)= 0x0f;

*((unsigned char *)0x4001)= 0xab;

*((unsigned char *)0x4003)= 0x01;

}

//噪音测试 -

if(((joypad1old&START)== 0)&&((joypad1&START)!= 0)){

*((unsigned char *)0x400c)= 0x0f;

*((unsigned char *)0x400e)= 0x0c;

*((unsigned char *)0x400e)= 0x00;

}

对于SoundTest程序随便用用就好,然后立即忘记一切,转到用Famitracker。

这一段随便看看就好,直接谷歌翻译的,作者都不太建议看太细,了解点就够了,直接用工具就好