这是一篇老文章了,最早放在CGDS上.
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的开发,希望您把您的其它探索也写出来, 共同进步。

GBA MOD音乐播放探索!相关推荐

  1. 推荐5款好用的Linux音乐播放器

    适用于 Linux 的音乐播放器可说数不胜数,不同的用户也有各自的喜好.知名且应用广泛的有 Cantata 和 Exaile,不太知名的工具有 Clementine.Nightingale 和 Quo ...

  2. animation基础练习源码_用vue简单写一个音乐播放组件「附源码」

    作者:vipbic 转发链接:https://segmentfault.com/a/1190000022980992 前言 上次小编也分享一个关于Vue 开发过音乐播放对项目: 基于 electron ...

  3. linux登陆界面卡死_Linux 上最好的五款音乐播放器

    Jack Wallen 盘点他最爱的五款 Linux 音乐播放器. 不管你做什么,你都有时会来一点背景音乐.不管你是开发.运维或是一个典型的电脑用户,享受美妙的音乐都可能是你在电脑上最想做的事情之一. ...

  4. 微信小程序音乐播放控制API在真机上貌似不可用?

    写了一个音乐播放页面,在IDE上调试正常,但是在真机上wx.getBackgroundAudioPlayerState()好像拿不到数据啊,seek也没有作用. 有哪位大神是运用正常的?求指点. 原文 ...

  5. VB.net写的音乐播放器,带百度翻译歌词

    Imports System.Drawing.Text Imports System.IOPublic Class Form1Public RND As New RandomPublic g As B ...

  6. MetroMusic音乐播放器开发心得

    MetroMusic音乐播放器开发心得 在这个假期,我独立开发了自己的音乐播放器MetroMusic,之所以叫做MetroMusic,是因为这个播放器的界面采用目前最为流行的win8Metro风格.这 ...

  7. Go语言案例(一)音乐播放器

    Go语言案例(一)音乐播放器 一.GOPATH 与 Go Mod 二.常用的标准库 (一)ftm (二)os/exec 三.项目中涉及语法概念 (一)结构体 (二)接口 四.源码附录 参考文档 一.G ...

  8. [转载]历上最强的音乐播放器(jetAudio-8.0.5.320-Plus-VX

    原文地址:历上最强的音乐播放器(jetAudio-8.0.5.320-Plus-VX-完全汉化版)下载作者:盖世天星 历上最强的音乐播放器(jetAudio-8.0.5.320-Plus-VX-完全汉 ...

  9. 适用于计算机/手机的常用音乐播放器推荐

    文章来源:https://www.reneelab.com.cn/best-music-player.html 目录 一.计算机音乐播放器推荐 1.Windows Media Player 2.VLC ...

最新文章

  1. 满足条件的两个数或多个数
  2. java宠物店多态源代码
  3. 70%以上程序员,不懂数据结构和算法!
  4. c语言枚举和结构体的区别,全面了解结构体、联合体和枚举类型
  5. 开源操作系统年度盛会最新日程曝光,邀您一同开启烧脑模式!
  6. python web开发框架 支持windows_基于Python的Web开发框架研究_曾浩
  7. Python format()函数
  8. elmentui的短信验证界面_[javascript] elementui下login登录页界面和js验证逻辑
  9. Andrew Ng 如何重拾梦想
  10. vbs无限循环代码_vbs整人代码
  11. wmv怎么转换成视频mp4?
  12. 解决mongodb 取出时是 UTC时间问题
  13. 建立人脉关系以及可能认识的人推荐
  14. [200814] 自己动手,搞定软件著作权申请(已成功)
  15. 上古卷轴5捏脸php导入,上古卷轴5捏脸预设导入 上古卷轴5捏脸预设怎么导入
  16. java实现爬虫,爬取网易歌单信息
  17. 李宏毅2020机器学习作业3-CNN:食物图片分类
  18. ORACLE中dual的详解及其故障恢复
  19. linux安装mysql8⼀步⼀步超详细教程
  20. sqlite的可视化管理工具SQLite Expert

热门文章

  1. 【答学员问】女生适合做运维吗?
  2. 2022-2028年中国高端幼儿园行业市场全景调查及投资潜力研究报告
  3. Netty 核心知识点
  4. 武汉新时标文化传媒有限公司抖音发布内容怎么写?
  5. 苹果5G遇冷影响AirPods,国产蓝牙耳机可否弯道超车
  6. Python常用库整理(给自己看的)
  7. 荣耀8xmax鸿蒙,荣耀8X Max是什么屏幕?
  8. 容器云系列之Docker镜像和仓库管理
  9. C++之获取本机Ip地址 CString 可直接使用
  10. 前端程序猿搞笑小故事