生命的伊始,婴儿用明亮的哭声宣告一个新生命的诞生,睁开双眼之前,一双小耳朵已经开始聆听这个世界。在如今的用户体验领域,几乎所有公司都会有视觉设计师,却鲜有注重听觉交互的公司。随着各大厂商对HTML5支持的日渐完善,前端工程师其实早已可以摆弄各种音波,让复合型开发走得更远。
声波是一种机械波,通过波的物理属性我们可以做很多事情。比如,利用声波的频率编码进行数据传递,分析频域或者时域的数据进行可视化应用,或者结合光波的特性做些视听联动。通过HTML5中的Web Auido规范,以上所有都能实现。我在自己的github里面建立了一个项目,整理了之前写的一些web audio相关的东西,欢迎互相学习交流。
千里之行始于足下,这系列的开篇,我会从基本的如何使用HTML5发出do,ri,mi开始。
所谓的音乐是由时值和音高组成,这里每一个音高都有自己频率。在web audio中,可以通过oscillator节点,产生指定频率的声音。代码如下:
var context = new webkitAudioContext(),
osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);
通过osc对象frequency属性的value值,上面的代码产生了一个440HZ的音。运行代码浏览器就会持续发出440HZ的音,在12平均律中这就是A1的音高。有了这个基准音,我们就能推断出其他音的频率,让浏览器发出不同音高的声音。至于各中关系,就需要首先介绍一下12平均律。
在乐理中,每组音由12个音组成,音名分别是C,C#,D,D#,E,F,F#,G,G#,A,A#,B,每2个音之间相差半个音程,同时每相邻半音的频率比值为2^(1/12)。B之后就是C,进入下一个循环,A1就是小字1组中A的频率值。根据半音频率的比值,小字1组中A#的频率就是440*2^(1/12) HZ。
因为这些音的音高是一定的,且数量有限,所以我们可以预先计算出这些音对应的频率值并储存起来,避免重复计算。读者可根据个人需要决定要初始化的音高数目。
var MusicalAlphabet = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'],
freqChat={},
freqRange=3,//C1-B3
i,j,base; for(i=1;i<freqRange;i++){
freqChat[i]={};
base = (i-1)*12;
for(j=0;j<12;j++){
//A1=440
freqChat[i][MusicalAlphabet[j]]=440*Math.pow(2,(base+j-9)/12);
}
}
在自然C大调中,我们选取C,D,E,F,G,A,B构成一组音。其唱名便对应do,ri,mi,fa,so,la,si。音高只和音名对应,和唱名无关。有了各音高的频率,我们可以很方便地初始化各种调式,不懂音律的同学可以自行搜索学习。
有了音高,接下来需要学习的就是时值了。要控制一个音符发声的长短,最直接的方法就是调用oscillator节点start和end方法。代码如下:
var context = new webkitAudioContext();
var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
var _c = context.currentTime;
osc.start(_c);
osc.stop(_c+1);
需要注意的是,web audio有自己的时间轴,通过context对象的currentTime属性可以获取当前时间。根据W3C规范,这是一个只读的属性。oscillator的start和end方法的参数都是double型,所以这里 osc.stop(_c+1)表示的是在当前时间1秒后停止。常见的节拍器上的数字,表示的是一分钟多少拍,这里简单除下就可以得出各个每一拍的物理时间了。
有了最基本的音高和时值,我们就可以动手写写最简单的谱子了。当然,滑音、颤音、推弦等演奏技巧,失真、混响等效果还需要别的web audio节点的辅助才能完成,这些节点以及开篇讲到的一些技术我都会在以后的博文中慢慢讲述。