GBA MOD音乐播放探索
写在前面
我并不是搞音乐的,甚至五音不全,仅仅是为了能在GBA上播放MOD音乐,我进行了一些学习,
找了大量资料后,基本有一个完整的结构,拿出来让大家打牙祭。专业音乐人士不要笑哟?
1、音乐是一门艺术
音乐是一门艺术(地球人都知道,你不是废话吗?)。一个最简单的佐证就是:
影响现代音乐理论最深的十二平均律是同一个时代出现在东西方的,但当时他们肯定是不可能有
交流的。这两个人是
欧洲荷兰人斯特芬(Stevin约1548 - 约1620):
他于1600年前后用两音频率比严格地确立了十二平均律;
中国明代科学家、音乐家朱载堉(1536 - 1612):
他表述的十二平均律甚至将2的12次平方根及各次幂均计算到小数点后24位(约完成
于1581年前)。
这绝不是什么巧合,而是他们都发现了音乐艺术的真谛。音乐是一门艺术,艺术是没有国界的。
那么什么是音乐的十二平均律?让我们从头说起------都是为了和谐,为了人的主观听觉。
首先古人很早就发现,如果一根空弦调整好后发出的音很好听,那么它的二分之一长度的音仍然
很好听,
并且这两个音听起来很和谐(当然你不能无休止的分下去)。于是人们就在不断的探索中发现了
和谐音的规律,五度律(不同时代东西方都有),由于五度律是一种整数比关系,人们曾经普遍
认为和谐音的规律必须
满足整数比的关系,例如把一根弦平分成N份后,它的1, 9/8, 81/64, 3/2, 27/16都将产生和谐
音,后来又发现
它的1, 9/8, 81/64, 4/3, 3/2, 27/16, 243/128也产生和谐音,这就是5音阶和7音阶。
为什么是整数比的关系呢?显然是因为当时的人还不能从理性的角度认识无理数,他们只能用能
理解的整数比的形式
来表达。到了17世纪前后,才有上述两位大哥(很崇敬的说)运用无理数的知识发现了相邻各
音(半音)频率之比:
2的12次平方根约等于1.05946,十二平均律(等比,不是等差)诞生。有了这个,数字音乐有了数字
化基础。
总结一下:音遵循相邻各音(半音)频率之比为1.05946的规律,当12个半音之后(1.05946的
12次方=2),音被提高了
一倍,即高8度,因为有7个音名C、D、E、F、G、A、B,对应唱名do、re、mi、fa、so、la、si。
学物理我们知道,声音是一种波(震动产生),波是有频率的,那各个音的频率是多少呢?
目前国际通用的标准音高(第一国际高度)是:a(小字一组的a,什么意思不再祥述,对于我这个外
行言多必失)音作为标准音,
标定它的频率为440Hz,那么其它频率你可以计算出来。但要注意,不要一直乘1.05946或一直除
1.05946,应该一个8度
一个8度的计算,即,以440Hz为基准计算小字一组,以880Hz为基准计算小字一组高8度,以220Hz
为基准计算小字一组低8度等等。
因为1.05946只是一个近似值,累计计算有误差,这样计算误差小一些 。
对于乐器来讲,不同的乐器发出的音的音色不同,如果反映为图像---音频包络线,你可以看到更
直观的不同。
例如:有如下包络线,它的音色听起来会像什么呢?
(插图)
2、欺骗你的耳朵
实际上,上面的声音听起来像什么,是可以变化的,因为它受播放的频率(速度)影响。我们知
道声音用数字化来存储,必须设定
采样率(每秒采集的数据量),采样率越高,越接近真实的情况。但到底多高才能满足要求呢?
对此有一个采样定理:
如果对某一模拟信号进行采样,则采样后可还原的最高信号频率只有采样频率的一半,
或者说只要采样频率高于输入信号最高频率的两倍,就能从采样信号系列重构原始信号。
因为人的听力范围大约在11-20000多Hz,所以就产生了CD音质44.1KHz的采样标准。
音乐中使用的音一般在27-4100Hz,也就是说对纯数字音乐,8KHz采样就可以满足有求了。但自然
中的音乐情况要比这复杂的多,因为
还没有哪一个乐器可以发出单一频率的音(含有泛音),这正是乐器的魅力所在,单一频率的音
是不会好听的。
这也就是电子琴的声音没有钢琴的音色好的原因(扯远了,赶快回来)。
例如上面的声音,本来是木鱼的声音,如果采样时按10KHz,播放按10KHz,那听起来就是木鱼的
声音,但是如果你播放的频率与
10KHz的差距太大,那听起来可能像敲竹筒的声音或别的什么声音。
总结一下:假设乐器的音色是固定的包络线,通过改变播放的频率,可以得到不同的音。
例如:你按440Hz采样钢琴小字一组a的声音,并按照十二平均律规律播放(1.05946作为等比)的
话,不同的播放频率你能听到最接近
标准音的所有键的声音,并不需要把钢琴的每一个键的音都采样。简单吧!其实我个人认为,之
所以能达到这种效果,更根本的原因是:
人的耳朵比眼睛更容易被欺骗,比较一下立体声和立体电影的发展进度就知道了。
(如果人有狗的听力,问题可就复杂了呀!)
又例如:你把一个女声用慢于采样频率的频率播放,听起来就会像从古堡里发出的低沉吼叫。
再例如:电影《大腕》中把哀乐以两倍的速度播放听起来就很欢快喜庆。
3、Module乐
Module乐的历史其实已经很长了,毫不夸张的讲Module乐可以轻松表现CD般的品质,而体积却很
小。因此Module成为游戏音乐中的宠儿。
原因很简单,让我们拿Module乐与MIDI乐比较一下:
MIDI很小,Module比MIDI大一点。
MIDI中定义的是声音代号,不是数据,真正的包络线数据在硬件中(或软波表),与硬件有关;
Module中的声音是自带的(自带采样数据----samples,当然什么声音都可以存放),与硬件无
关。
另一个好处是制作编辑Module乐太直观了、太方便了。用了你就会知道!
CD般的品质、体积很小、与硬件无关、什么声音都可以存放、制作编辑直观方便、简直是完美无
缺。
在Module的发展中有很多不同的标准(文件格式),如:
MOD----------ProTracker / NoiseTracker Music Module
S3M----------ScreamTracker III Music Modules
XM ----------FastTracker II Music Modules
IT ----------Impulse Tracker Music Modules
等等。
在这里我只能给大家介绍ProTracker MOD(以后简称MOD)的结构,因为别的都比他复杂,采样率
也不符合GBA要求,我也不懂。
总结一下:MOD中带有声音采样数据(8Bits采样,我们称之为样本),可以是乐器的音色,也可以
是其它什么声音,
但要注意采样频率于播放频率变化的关系。
MOD中除了样本,就是怎么把声音样本播放的信息,大致有以下几个方面:
频率:从C-0,C#0,D-0,D#0,E-0,E#0,F-0,F#0,G-0,G#0,A-0,A#0,B-0,B#0
C-1,C#1,D-1,D#1,E-1,E#1,F-1,F#1,G-1,G#1,A-1,A#1,B-1,B#1
到
C-8,C#8,D-8,D#8,E-8,E#8,F-8,F#8,G-8,G#8,A-8,A#8,B-8,B#8
C-9,C#9,D-9,D#9,E-9,E#9,F-9,F#9,G-9,G#9,A-9,A#9,B-9,B#9
每两个相邻频率间的关系是等比------1.05946
C-0的频率是262Hz,B#9的频率是252867Hz。这是我自己按4舍5入计算的,
注意ModPlug Tracker网站上有一篇精确计算频率的文章,很有技巧,感兴趣的可以看一下。
他与我的计算有差异,当然按ModPlug的为准,方法稍后会介绍。
特效:可以进行一些声音特效处理,太复杂,谁的英文好,翻译一下吧!ModPlug Tracker网站上
有资料。
播放序列:样本播放的次序
另外:在样本中还可以定义样本的循环播放。
总结一下:
MOD乐就是通过按照不同的频率、特效、指定的播放序列、循环等来播放样本声音。
MOD乐相关属性:
默认扩展名 轨道数目 样本数目 最大块的个数 样本采样要求
MOD 4 31 64 8 bits
具体存储结构看以下C语言定义:(有些名词是我自己的习惯)
//歌曲名,长度20,OFFSET=0--19
typedef struct Mod_Header{
u8 songname[20];
};
//31个样本的相关信息,长度31*30=930,OFFSET=20--949
typedef struct Mod_Sample
{
u8 name[22];//样本名
u16 length;//8位样本长度/2
u8 finetune;//微调值(作用不清楚,猜测是防止混音时出现静音,后面
会讲)
u8 volume;//音量
u16 loopoffset;//循环偏移量
u16 looplength;//循环偏长度
};
//乐曲的播放序列,是按块划分,每块有64小ROW(我称之为节),每节4Bites,长度
134,OFFSET=950--1083
typedef struct Mod_song
{
u8 songlength;//乐曲块长度
u8 songjump;//Song end jump position (乐曲循环重放)
//我没有验证,好像是乐曲循环重放,GBA上可以忽略
u8 song[128];//固定128个块序列由此计算出块的个数
u32MK;//字符M.K.内部定义的文件格式标示字符
};
//块的数据,由节组成,4个轨道,块长度 = 块的个数*4*4*64=块的个数*1024
Bytes,OFFSET=1084 //计算才知道
//节的数据结构
//Byte 1 Byte 2 Byte 3 Byte 4
//--------- --------- --------- ---------
//7654-3210 7654-3210 7654-3210 7654-3210
//wwww XXXX xxxxxxxxx yyyy ZZZZ zzzzzzzzz
//wwwwyyyy ( 8 bits) : 样本号
//XXXXxxxxxxxx (12 bits) : 调整频率
//ZZZZzzzzzzzz (12 bits) : 特效
//实际播放频率有两种计算方法
//1:PAL 制实际播放频率=7093789.2/调整频率/2
//2:NTSC制实际播放频率=7159090.5/调整频率/2
//至于用那一种你自己考虑
//节的结构定义
typedef struct Mod_Patterns_
{
u16 wXx;
u16 yZz;
}
typedef Mod_Patterns_ Mod_Patterns[64*4];
//接下来是8位样本数据,OFFSET=计算才知道--计算才知道
typedef s8 * Mod_PSample
以上就是顺序存放的结构,当然你可能有更好的定义方法。
4、在GBA上播放MOD乐
终于到达目的地了,其实经过上述铺垫,对于在GBA上WAVE播放有经验的朋友来讲,基本已经明白
了,
所以要说的并不多。
关于GBA上声音(WAVE)的播放我不想多说,不懂的到CGDN、金点时空(还有其它网站)里看看,
相关文章很好,
我可不想照抄别人的文章。这里仅谈一谈GBA播放MOD乐的原理和特别注意的地方。
有了前面的结构信息,你可以方便的调入MOD乐的数据,进行分析,按照不同的频率、特效、指定
的播放序列、循环来
播放样本(其实就是WAVE)。当然要有正确的DMA、TIMER、FIFO、中断设置,不同的程序员用起来
肯定有自己的特色。
问题还有两个:
1、混音
因为MOD乐有4个轨道,GBA只有两个FIFO声音通道,你需要把4个轨道混合成2个轨道。
给出最简单的混合公式:FIFOA=(T0+T1)/2;FIFOB=(T2+T3)/2。
当然FIFOx指的是送往FIFO声音通道的8Bits数据,Tn指的是0至3轨道8Bits有符号样本数据。
那8个轨道的声音怎么做呢?原理你可能想到了,我不想研究了,如果你研究好了,请不吝赐教。
混音有可能出现的问题:
一:不同的频率是要混合成相同的频率的,因此要进行频率的调整,原理不难,可问题不少。
如果你真想做,就要查资料了,痛苦呀!!!对此我已经写不下去了,要写应该是一个专题
了。
二:混音后的静音问题
如果你的两个混合样本的包络线正好是垂直翻转的,即(Tn+Tm)=0,那播放出来就什么也听不
到了。
不过解决起来反而简单,不用编程,只要在MOD乐制作期把其中一个样本数据的前面加一些填
充0数据就行了。
当然如果编程解决就显得高明了,可是对GBA有限的CPU资源是一种浪费。
2、缓冲区
这也就是我为什么不用afm_v1.1的MOD乐播放库的主要原因之一,因为有混音等问题,所以必须要
有缓冲区来存放
计算后的数据,对于GBA有限资源来讲,自己清清楚楚的控制资源是有意义的。
写在后面
如果你想要源代码,不好意思,
第一,我还没有完成,
第二,编程的乐趣就在痛苦的探索后得到解脱,
第三,其实早就有afm_v1.1的MOD乐播放库,虽然不提供源码,不允许未经同意用于商业用途,但使用很方便,
你可以拿来作为学习。
说了这么一大通,希望对您有所帮助,希望更多的人加入GBA的开发,希望您把您的其它探索也写出来, 共同进步。