无门槛利用前端技术创作8bit音乐(实践篇)
为什么写这篇文章
忙碌了一整年,大家都在补充各种工作上需要用到的知识,却有些忽略了技术的娱乐性。
最近在听机核网的一期电台:我们用8bit音乐原理告诉你,FC的游戏音乐是如何制作的,原理的部分感觉和Web Audio有很多相似之处,遂撰写这篇文章,希望让没有任何音乐基础的同学,看完之后也能写一段自己的8bit音乐。
因为是实践篇,这篇文章可能涉及很多音乐知识,我会尽可能把需要用到的知识用最简单的方法让大家快速理解,也会附上相关的学习资料。
文章中涉及的代码不多,如果只对技术感兴趣的小伙伴可以就此止步了。具体技术的原理部分,年后我会另开篇写,这里先挖个坑,以下是正文。
8bit音乐介绍
什么是8bit音乐
8bit音乐也叫芯片音乐。
当时的游戏主机(例如FC)内存很小,无法存储高分辨率的PCM录音。所以游戏音乐需要实时合成,必须将基本的声音合成引擎植入硬件当中,在游戏芯片中存储音乐编码(相当于乐谱),芯片音乐由此产生,并逐渐成为一种风格。
8bit音乐如何创作
我们主要用FC的声音系统来讲解。在FC的声音系统中,不存在乐器的概念,只是提供不同的波形供编曲者使用,作曲的时候分别调用不同的波形,形成不同的声音效果。
FC提供了以下5个声道:
方波(2声道)
波形如下图所示:
方波占两个声道,因为有不同的比例的波形,可以产生不同音调的声音,一般用来模拟钢琴、吉他等乐器。
三角波(1声道)
三角波,顾名思义,就是波峰波谷全为三角形,如下图:
一般用来模拟贝司等乐器。
噪音(1声道)
噪音占一声道,在FC游戏的音乐和音效中是最常见的,爆炸声、脚步声、碰撞声以及音乐的节奏点等等都是用噪音制作的。
没找到特别合适的图,但波形类似:
比起制造音效,更重要的作用的打节奏。因为噪音比起方波三角波更有辨识度,能够营造比较好的节奏感,可以用来模拟架子鼓。
采样(1声道)
最后还有一个声道是采样声道,由于采样花样比较多,相对比较复杂,所以在这篇文章先不讲。
对一个音的修饰
最后,FC支持对一个音符的修饰,开发者可以通过音量、波封(ADSR)、颤音等等,来修饰一个音符。
Web Audio简介
Web Audio支持正弦、方波、三角波和锯齿波。你可以听到不同的波形产生不同的声音:
然而,你可能已经注意到,FC提供的声道中是没有正弦波的。因为正弦波是在游戏主机发布后推出的,它的音调要温和得多,在这次实践中我们也不会应用。
参考了这个demo,决定使用Tone.js库来进行开发,主要是两个原因:
- Tone.js接受的是音高,而不是要求它播放440Hz频率的声音,我们可以简单地演奏A4音,而不是440Hz音。
- 对ADSR中的Attack和Release做了封装,方便开发。关于ADSR有兴趣的可以参考波封,简单来说就是调节声音的效果。
正式实战
先放demo:
我们编辑一首8bit的音乐,主要关心的是单声道乐谱
、和声
和声音效果
三个部分,下面分别进行讲解。
第一步:乐谱改造
先看Tone.js提供的关键发声函数:
.triggerAttackRelease ()
包含四个参数:
- note:演奏的频率或音符位置
- duration:音符持续时间或音符形状
- time:音符什么时候被触发
- velocity:音符速度(可以理解为音量,学过物理的都知道,速度越快,振幅越大,音量也越大)
可以看出,time主要duration有关,体现的是音符在乐器中时间轴的位置。
而velocity音量,每首歌也会相对比较统一,所以我们改造一个乐谱,主要关心的是音符位置
(即音高或频率)和音符的持续时间
(即拍子),举个栗子:
var synth = new Tone.Synth().toMaster()
synth.triggerAttackRelease('C4', '4n', '8n', 1)
synth.triggerAttackRelease('E4', '8n', '4n + 8n', 1)
C4
、E4
代表声音的频率,或者是音符在乐谱中的位置,即“do”、“re”,“mi”等等,4n
、8n
代表声音持续时间,或者是乐谱中音符的形状,time参数是累加的,velocity参数也是固定的。
那么C4
、E4
、4n
、8n
这些东东是怎么算出来的呢?
以《欢乐颂(Ode To Joy)》举例,以下是钢琴谱:
音符位置(音高或频率)
先看左上方1=C
,代表这是C大调的歌,就是以钢琴上的C键位作为“do”,再看谱号:
这个乐谱是高音谱号,那么就是以“中央C”键位,作为“do”来演奏。
何为“中央C”键位?钢琴上一共52个白键,7个八度,第一个键位是A1,然后依次是B1,C1。从左往右数,第四个八度的C键位,这个C4
键位即为“中央C”,而这首乐谱的“do”,就是我们在前面代码中看到的“C4”。
怎么看五线谱?很简单,五线谱就是钢琴相对键位的谱,如下图:
钢琴上还有36个黑键,如下图:
这些黑键在函数中怎么用呢?C4``D4
之间的黑键,可以用C4#
或者D4b
来表示,至于为什么7个白键+5个黑键,12个键为一组,感兴趣的可以看看十二平均律。
音符形状
我们再来看一下乐谱左上角的“4/4”,代表这是一个44拍的乐谱,什么叫44拍?44拍是指以四分音符为一拍,每小节有4拍。其他的拍号和具体介绍可以参考拍号。
小节是什么?如下图:
两个竖线之间的区域称为一个小节。
那四分音符又是什么呢?看下图:
只要看形状就可以,上下颠倒的情况可以忽略,可以看出第一小节,所有的音符都是四分音符,前面示例代码中出现的4n
、8n
其实就代表着四分音符和八分音符。
到这大家又会有疑惑了,虽然音符的形状代表了节拍,但是这个节拍也是相对的,怎么对应到现实的绝对时间中呢?
这时要引入一个概念BPM。BPM是Beat Per Minute的简称,即每分钟有多少个节拍,以44拍乐谱为例,如果bpm设定为120,即每分钟一共120个节拍,那么意味着每一个四分音符刚好持续0.5s。
实际应用
说了半天音乐知识,我们还是要回到代码中,以第一小节举例,这个小节有四拍,每一个都是四分音符,分别是“mi”、“mi”、“fa”、“so”,在代码中我们怎么写呢?如下:
var synth = new Tone.Synth().toMaster()
Tone.Transport.bpm.value = 120
synth.triggerAttackRelease('E4', '4n', '0', 1)
synth.triggerAttackRelease('E4', '4n', '4n', 1)
synth.triggerAttackRelease('F4', '4n', '2n', 1)
synth.triggerAttackRelease('G4', '4n', '2n+4n', 1)
这样一个小节的乐谱改造就完成了。
第二步:引入和声
什么叫和声?和声是两个或两个以上不同的音按一定的法则同时发声而构成的音响组合。
不同的乐器有不同的音色,各种乐器之间通过一种和谐的方式搭配到一起,才能形成很好的音乐,而音色本质上来说,其实就是不同的波形。
完成了单声道乐谱的改造后,我们要来new几个新的乐器(波形):
var triangleOptions = {
oscillator: {
type: 'triangle'
}
}
var squareOptions = {
oscillator: {
type: 'square'
}
}
var squareSynth = new Tone.Synth(squareOptions).toMaster()
var triangleSynth = new Tone.Synth(triangleOptions).toMaster()
var noiseSynth = new Tone.NoiseSynth().toMaster()
每个音色应不同的波形,也对应了不同的乐器,squareSynth 方波主要对应旋律乐器,例如钢琴、吉他,triangleSynth 三角波主要用来模拟贝司,noiseSynth 噪音声道主要模拟打击乐,这个前文我们也讲到了。每一个乐器需要改造各自独特的乐谱。
第三部:声音效果
最后,大家可以通过波封来改变声音的效果,例如加入混响、回声、轻重音等等,让音乐听起来更加生动,这部分主要是通过Tone.Envelope()
来控制:
- attack:音量从0到最大音量的时间,单位是时间
- decay:音量从最大音量到sustain音量的时间,单位是时间
- sustain:在release执行前持续音量占总音量的百分比,单位是百分比
- release:音量从sustain音量到0的时间,单位是时间
envelope: {
attack : 0.01 ,
decay : 0.1 ,
sustain : 0.5 ,
release : 1 ,
attackCurve : linear ,
releaseCurve : exponential
}
通过控制Attack(起音)、Decay(衰减)、Sustain(延持)、与Release(释音)的时间,可以很好的实现各种声音效果,实际效果怎么样,需要大家自己去尝试。
总结
这篇文章主要讲解了,利用Web Audio技术,使用Tone.js类库,开发8bit音乐的整体步骤,主要分三步:
- 单乐器乐谱改造
- 多乐器和声
- 增加声音效果
更多内容可以查看我改的demo,里面也添加了菊苣们写的《超级玛丽》和《塞尔达传说》的乐谱,我改写的《欢乐颂》也在里面,简单改造钢琴谱,加了个贝斯谱(其实就是和弦的根音)。
希望大家看完之后,都能创作出属于自己的8bit音乐!