クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【Tone.js】Tone.Part()でメロディのタイミング、音の長さ、音量を調節する(マリオのゲームオーバー音)

Tone.jsの続きです。前回はメロディ再生、シンセ音源加工、エフェクター接続を行いました。マリオの地上面メロディを打ち込みました。今回は「Tone.Part()」とうメソッドを使ってもう少し細かくメロディのタイミング、長さ、音量を調節しました。マリオのゲームオーバー音の三連符を再現♪それではいきましょう!

【目次】

今回作ったものはこちら。マリオのゲームオーバー音。

See the Pen Mario TheEnd 03 by イイダリョウ (@i_ryo) on CodePen.

「Play」を押すと音が鳴り「Stop」を押すと止まる。前回よりもメロディを細かく制御できている。

※前回:【Tone.js】メロディ再生、シンセ音源加工、エフェクター接続(マリオを打ち込んだ!) - クモのようにコツコツと

Tone.Sequence()だとメロディのリズムが一定になる

前回、メロディの打ち込みで活躍したTone.Sequence()。こちらは直感的に打ち込めるメリットがある反面、リズムが一定になってしまうのが難点。例えばTone.Sequence()でマリオのゲームオーバーと打ち込むとこうなる。

See the Pen Mario TheEnd 01 by イイダリョウ (@i_ryo) on CodePen.

「ターラーラー、ターラーラー♪」と三連符にしたいところが「タッタラ、タッタラ」とやけに歯切れの良いシンコペーションになってあまりガッカリ感がないw。最後の「タララー〜♪」と伸ばしたいところも「タララッ」と途切れてしまい、随分あっさりした印象。。

メロディ部分はこちら。

//メロディ
const melodyLine = [
  'c5',null, null,'G4',
  null, null,'E4', null,
  'A4', null,'B4','A4', 
  'G#4',null, 'A#4', 'G#4',
  'G4', 'F#4','G4', null,
  null, null, null, null
]

nullが休符になる。

再生ボタンのイベント

//再生ボタン
play.addEventListener("click", function () { 

//ボタン表示切替
play.style.display = "none"; 
stop.style.display = "block"; 

//音源
const synth = new Tone.AMSynth().toMaster(); 
 
//8分音符で再生
function setPlay(time, note) { synth.triggerAttackRelease(note,'8n', time);
}

//メロディをセット  
const melody = new Tone.Sequence(setPlay, melodyLine); 

//メロディ再生
melody.start();

//ループ回数
//melody.loop = 0; 

//テンポ
Tone.Transport.bpm.value = 400;
  
//再生実行
Tone.Transport.start(); 

}, false);
  • DOMplayのクリックイベント
  • playボタンの非表示、stopボタンの表示
  • 音源設定(Tone.AMSynth()に変えてみた)
  • 関数setplay()で再生設定synth.triggerAttackRelease()、8分音符8nの長さ
  • 変数melodyでメロディセットTone..Sequence()setplay()の8分音符でmelodyLineのメロディ。
  • melodyの再生start()
  • melodyのループ回数は指定しない(無限ループ)
  • テンポTransport.bpm.value400
  • 再生を実行Transport.start()

停止ボタンのコードはいじってない。前回参照。

※参考:【Tone.js】メロディ再生、シンセ音源加工、エフェクター接続(マリオを打ち込んだ!) - クモのようにコツコツと

Tone.Part()でメロディのタイミングを調節

Tone.Sequence()Tone.Part()に変更することでもっと厳密にメロディのタイミングを調節できた。

See the Pen Mario TheEnd 02 by イイダリョウ (@i_ryo) on CodePen.

//メロディ
const melodyLine = [
  ['0:0:0','c5'],
  ['0:3:0','G4'],
  ['1:2:0','E4'],
  ['2:0:0','A4'],
  ['2:1.5:0','B4'],
  ['2:2.8:0','A4'], 
  ['3:0.2:0','G#4'],
  ['3:1.6:0','A#4'], 
  ['3:2.8:0','G#4'],
  ['4:0:0','G4'], 
  ['4:0.75:0','F#4'],
  ['4:1.25:0','G4']
];
  • 先ほどのメロディは全体が一つの配列になっていたが、今回は配列の中にさらに配列が入れ子になっている。
  • 入れ子の配列には値が2つずつ入っている。
  • 1つ目の値がタイミング(小節:拍:半拍)、2つ目の値が音程。

Tone.Part()は何小節目の何拍目と細かくタイミングを指定できたため、休符nullの指定は不要になった。「小節」が0→1→2→3→4と進んでいるのがわかると思う。また、2番目の「拍」が小数点で細かく指定できたため、今回は3番目の「半拍」の指定は使わなかった。

次、再生ボタンの変えたところ

//(前略)

//メロディをセット  
const melody = new Tone.Part(setPlay, melodyLine); 

//(中略)

//ループ(デフォルトでfalse)
melody.loop = true;
melody.loopStart = "0";
melody.loopEnd = "16";

//(後略)
  • メロディセットのところ、Tone.Sequence()Tone.Part()に変更
  • ループをtrueに設定。(デフォルトはfalseだった)
  • ループの開始位置loopStart、終了位置loopEndも細かく設定(デフォルトのloopEndは1秒1mだった)

※参考:Part

なお、loopStartloopEndの値は、単位無しだと拍数、単位mは秒数になった。

さて、これでもだいぶ自由度は上がったが、欲をいえば音符の長さも一音ずつ変えたくなる。

連想配列でさらに音の長さ、音量も調整する

メロディの中を連想配列(キーと値)にすることでさらに細かい調整(音の長さ、音量)もできた!

See the Pen Mario TheEnd 03 by イイダリョウ (@i_ryo) on CodePen.

変更したメロディ部分

//メロディ
const melodyLine = [
  {'time': '0:0:0', 'note': 'c5', 'duration': ' 16n','velocity': 1},
  {'time': '0:3:0', "note": 'G4', 'duration': '16n','velocity': 0.75},
  {'time': '1:2:0', "note": 'E4', 'duration': '16n','velocity': 0.5},
  {'time': '2:0:0', "note": 'A4', 'duration': '4n','velocity': 0.75},
  {'time': '2:1.5:0', "note": 'B4', 'duration': '4n','velocity': 1},
  {'time': '2:2.8:0', "note": 'A4', 'duration': '4n','velocity': 0.75},
  {'time': '3:0.2:0', "note": 'G#4', 'duration': '4n','velocity': 0.5},
  {'time': '3:1.6:0', "note": 'A#4', 'duration': '4n','velocity': 0.75},
  {'time': '3:2.8:0', "note": 'G#4', 'duration': '4n','velocity': 0.5},
  {'time': '4:0:0', "note": 'G4', 'duration': '16n','velocity': 1},
  {'time': '4:0.75:0', "note": 'F#4', 'duration': '16n','velocity': 0.5},
  {'time': '4:1.25:0', "note": 'G4', 'duration': '1n','velocity': 0.75},
];
  • 配列の中の入れ子を連想配列(キーと値)にする。キーは4種類入れている。
  • timeキーはタイミング、noteキーは音程、durationキーは長さ、velocityは音量

timenoteは先ほどの値と変わらない。duration16nは十六分音符、4nは四分音符、1nは全音符。velocity1を基準に小さい音を0.5などにしてみた。鍵盤を弾く指の強さをイメージしてみた。

ちなみに音の長さdurationは公式リファレンスでは見当たらなかったのだが、こちらの記事で実現されていた!多謝!!

※参考:Tone.jsを使用した複雑な音階の再生、和音を伴うメロディの作成 │ よねぴ

再生ボタンの変えたところ

//(前略)
 
//再生設定
//function setPlay(time, note) { synth.triggerAttackRelease(note,'8n', time);
function setPlay(time, note) { synth.triggerAttackRelease(note.note, note.duration, time, note.velocity);}

//(後略)
  • 関数setPlay()synth.triggerAttackRelease()の引数をnote.notenote.durationtimenote.velocityの4つに

音程notenote.noteとこまかいプロパティを指定しており、音の長さ8nnote.durationにしている。また、音量のnote.velocityも追加されている。

最後に

f:id:idr_zz:20190603211020j:plain

前回よりも細かいメロディを打ち込むことができました!そしてそして、Tone.Part()はなんと、メロディだけでなく和音も再生できそうです!次回は和音の再生に取り組みたく。それではまた!!


※参考:Tone.jsを習得するためにやった事まとめ qiita.com