65.9K
CodeProject 正在变化。 阅读更多。
Home

用HTML5写乐谱

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2015年2月11日

MIT

5分钟阅读

viewsIcon

17419

本文将介绍如何使用纯 JavaScript 编写旋律,并向您介绍一个有趣的 JavaScript 框架。

背景

婴儿出生前,最先通过耳朵感知世界。这表明声音是互动中非常重要的元素。然而,设计师和工程师通常更关注视觉而非声音。众所周知,声波是一种机械波。利用波的物理特性,我们可以做很多有趣的事情。

创作音乐

软件工程师用 1 和 0 敲打着构建他们的乌托邦,而音乐家则用音符演奏着他们的伊甸园。当编码与音乐相遇时,应该充满奇幻。音乐将丰富软件的用户体验,而编码将使人们更多地了解音乐的结构。

旋律由各种音符组成,其中时值和音高是音符最重要的属性。在下一段中,我将介绍如何用 JavaScript 创建一个音符。

人们可以识别不同音高的音符,因为每个音符都有自己的频率。根据 Web Audio API,我们可以创建一个振荡器节点。此节点可以生成具有指定频率的声波。您可以做一些测试。请参考以下代码

var context = new webkitAudioContext(),
     osc  = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);

上面的代码创建了一个频率为 440 赫兹的振荡器。根据十二平均律,440 赫兹是“LA”的频率。在十二平均律中,将一个八度音程分成 12 个相等的部分,半音的宽度,即两个相邻音符之间音程的频率比,是二的十二次方根。因此,我们可以得到其他音符的频率。请参考以下代码

var MusicalAlphabet = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'],
    freqChat={},
    freqRange=3,
    i,j,base;

for(i=1;i<freqRange;i++){
    freqChat[i]={};
    base = (i-1)*12;
    for(j=0;j<12;j++){
        freqChat[i][MusicalAlphabet[j]]=440*Math.pow(2,(base+j-9)/12);
    }
}

我建议在脚本开头计算所有音符的频率。现在,我们可以得到每个音符的音高。下一步是处理时值。最简单的方法是使用振荡器节点实例的“stop”和“start”函数。您可以参考以下代码

var context = new webkitAudioContext();
var osc  = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
var _c = context.currentTime;
osc.start(_c+1);
osc.stop(_c+2);

您可能已经注意到变量 _c。在 Web Audio 的上下文中,它有自己的时间线。上下文的“currentTime”属性是访问此时间线的唯一方法。上下文的所有节点都根据此时间线进行播放。“start”函数需要一个参数来定义振荡器节点的开始时间。如果此参数小于 context.currentTime,则“start”函数将立即执行。

不幸的是,每个实例的“start”函数只能调用一次。这意味着一旦调用了“stop”函数,就必须创建一个新实例来播放相同的音符。所以我建议另一个解决方案。关键是增益节点。使用增益节点,您可以控制振荡器节点的信号强度。如果您曾经弹过吉他放大器,您会更好地理解这个节点。

guitar amp

让我们回到编码世界。

var context = new webkitAudioContext(),
    gain = _ctx.createGain(),
    osc  = context.createOscillator(),
    _c= context.currentTime;
osc.frequency.value =440; 
gain.gain.value=0;
osc.connect(gain); 
gain.connect(context .destination); 
osc.start(_c);
gain.gain.setValueAtTime(1,_c+1);
gain.gain.setValueAtTime(0,_c+2);

上面的代码可以从 1 秒到 2 秒播放一个音符“La”(在 C 大调中)。您可以将 gain.gain.value 的值设置为 01。当此值设置为 0 时,它的作用就像调用“stop”函数一样。下图显示了信号的变化。

signal

除了“setValueAtTime”函数,增益节点还有其他一些改变其值的方法。您可以在 Web Audio API 中找到它们。

到目前为止,您应该能够通过 JavaScript 在一段时间内播放一个音符。但要实现乐谱,还有很多工作要做。在本文的后续部分,我将教您如何使用名为“Jsonic”的 JavaScript 框架创建乐谱。

使用 Jsonic 播放乐谱

Jsonic 是一个小型且功能丰富的 JavaScript 库。使用 Jsonic,您可以创作音乐、通过超声波传输数据、使声波可视化、进行语音识别等等。您可以从 **jsonic.net** 或 **github** 获取 Jsonic。

struct

上图显示了 Jsonic 的旋律模块的结构。您需要创建一个 Track 或 TrackGain 的实例来播放乐谱。乐谱由许多音符组成。让我们转到详细代码。

创建音符

var note = new Jsonic.Melody.Note(1,1/4,0,false);

您可以根据上面的代码创建一个音符。在 Jsonic 中,Jsonic.Melody.Note 的每个实例都代表一个音符。Note 的构造函数可以接受 4 个参数。第一个是音名,第三个参数定义了该音符的八度。Jsonic.Melody.Note 使用 音名 (0,1,2,3,4,5,6,7) 来创建实例,以便您可以在 MusicScore 中轻松更改音调。如果您想要中央 C,第三个参数应该是 0。第二个参数定义了音符的时值(1,1/2,1/4,1/8,1/16)。MusicScore 的速度是影响音符实际时值的另一个因素。第四个参数定义了该音符是否有附点。

创建乐谱

var musicScore = new Jsonic.Melody.MusicScore('C','major','4/4');

创建 MusicScore 实例时,可以定义其调性和拍号。上面的代码创建了一个 4/4 C 大调乐谱。您应该在这里使用音乐字母。

创建乐谱后,您可以根据以下代码将音符添加到乐谱中

musicScore.w(new Jsonic.Melody.Note(3),new Jsonic.Melody.Note(4));

w”函数会将所有参数追加到乐谱的末尾。下一步是创建一个 TrackTrackGain 实例来播放乐谱。但您应该首先调用“compile”函数。

musicScore.compile();

播放音乐

正如我在本文开头提到的,我们有两种方法来控制音符的时值。Track 和 TrackGain 对应于这两种方法。

var track = new Jsonic.Melody.Track();
track.play(musicScore,90);

上面的代码创建了一个轨道,并以 90 的速度播放乐谱。速度值指的是节拍器中的数据。

如果您仍然感到困惑,请点击 **演示**。(点击开始按钮。)

摘要

Web Audio 提供了许多节点。您可以将它们连接起来。这就像弹奏吉他放大器一样。希望您能通过 Web Audio 找到一些有趣的效果。

© . All rights reserved.