Tone.jsの続きです。前回はTone.Loop()
を使ってエイトビートを鳴らしました。ただ、この方法だと細かいタイミングでリズムを変えることが出来なそうなので、今回は以前、マリオのゲームオーバー音の時に使ったTone.Part()
で打ち込んでみました。予想通り細かいタイミングで打ち込みができました。それではいきましょう!
【目次】
※参考:【Tone.js】Tone.Loop()でエイトビートを鳴らす - クモのようにコツコツと
※参考:Tone.jsを習得するためにやった事まとめ
qiita.com
前回のおさらい
前回作ったものこちら。ボタンを押すとエイトビートが鳴る。
See the Pen tone.js-DrumBeat_1 by イイダリョウ (@i_ryo) on CodePen.
※音が鳴らない場合:CodePen - tone.js-DrumBeat_1
リズム(エイトビート)を鳴らしている主要部
// シンセ実行 const kick = () => { membrane.triggerAttackRelease('C0','2n'); }; const snare = () => { noise1.triggerAttackRelease('8n'); }; const hihat = () => { noise2.triggerAttackRelease('32n'); }; // ループ設定 let count = 1; var loop = new Tone.Loop((time) => { if(count === 1 || count === 5){ kick(); hihat(); } else if(count === 3 || count === 7){ snare(); hihat(); } else { hihat(); } if(count === 8){ count = 1; } else { count++; } }, '8n').start(0);
Tone.Loop()
を使ってfor文でカウントを繰り返しながら再生している。この方法だと8拍子にジャストな音しか出せない。
詳細は前回の記事を参照。
※参考:【Tone.js】Tone.Loop()でエイトビートを鳴らす - クモのようにコツコツと
Tone.Part()でエイトビートを鳴らす。
Tone.Part()を使った完成品
メロディ(マリオのゲームオーバ音)打ち込みの時に使ったTone.Part()
、こちらの方が細かいタイミングで打ち込みできた。
※参考:【Tone.js】Tone.Part()でメロディのタイミング、音の長さ、音量を調節する(マリオのゲームオーバー音) - クモのようにコツコツと
Tone.Part()
を使ってみたもの
See the Pen tone.js-DrumBeat_4 by イイダリョウ (@i_ryo) on CodePen.
※音が鳴らない場合:CodePen - tone.js-DrumBeat_4
ボタンを押した時になるエイトビートは前回と変わらない。
リズム設定
キックのリズム
let kickRhythm = [ ['0:0:0'], ['0:2:0'], ];
- 変数
kickRhythm
の値は配列で、配列の値もまた配列 - 配列1つ目の値は
0:0:0
- 配列2つ目の値は
0:2:0
コロンで挟まれている3つの数値(0:0:0
など)、一つ目は「小節」、二つ目は「音符」、三つ目は音符をさらに細かく微調整。色々打ち替えてみたが0
、2
(0からのカウントで1、3番目)ということで4拍子ベースになっている。
次、スネアのリズム
let snareRhythm = [ ['0:1:0'], ['0:3:0'], ];
- 変数
snareRhythm
の値は配列で、配列の値もまた配列 - 配列1つ目の値は
0:1:0
- 配列2つ目の値は
0:3:0
スネアはキックの裏拍(バックビート)のアクセントなので1
、3
(0からのカウントで2、4番目)になる。
最後、ハイハットのリズム
let hihatRhythm = [ ['0:0:0'], ['0:0.5:0'], ['0:1:0'], ['0:1.5:0'], ['0:2:0'], ['0:2.5:0'], ['0:3:0'], ['0:3.5:0'], ];
- 変数
hihatRhythm
の値は配列で、配列の値もまた配列 - 配列の音符部は上から
0
、0.5
、1
、1.5
、2
、2.5
、3
、3.5
4拍子ベースのためエイトビート(8拍子)は0.5刻みになる。
リズムをシンセに設定
Tone.Part()
を使ってシンセにリズムを設定する。
// シンセにリズムを設定 let kickPart = new Tone.Part(kick, kickRhythm).start(); let snarePart = new Tone.Part(snare, snareRhythm).start() let hihatPart = new Tone.Part(hihat, hihatRhythm).start();
- 変数
kickPart
でTone.Part()
のインスタンス作成。引数は左からkick
とkickRhythm
。start()
メソッド実行。 - 変数
snarePart
でTone.Part()
のインスタンス作成。引数は左からsnare
とsnareRhythm
。start()
メソッド実行。 - 変数
hihatPart
でTone.Part()
のインスタンス作成。引数は左からhihat
とhihatRhythm
。start()
メソッド実行。
ループ設定
最後にループ設定。
// ループ設定 kickPart.loop = true; snarePart.loop = true; hihatPart.loop = true;
kickPart
、snarePart
、hihatPart
ともにloop
設定をtrue
に
loop
設定の初期値はfalse
で1回しか鳴らなかった。true
にすると無限ループになる。(数値だと回数分ループする)
※参考:Part
JSコード全体
JSコードだとこうなる。
// DOM const beat = document.querySelector('#beat'); // エンベロープ(キック) let optsMembrane = { pitchDecay: 0.001, envelope: { attack: 0.001 , decay: 0.75 , sustain: 0.01 , release: 0.01 }, volume: 25 } // エンベロープ(スネア) let optsNoiseSnare = { envelope: { attack: 0.001 , decay: 0.5 , sustain: 0 } } // エンベロープ(ハイハット) let optsNoiseHihat = { type: "brown", envelope: { attack: 0.001 , decay: 0.03 , sustain: 0 } } // シンセ生成 const membrane = new Tone.MembraneSynth(optsMembrane).toMaster(); const noise1 = new Tone.NoiseSynth(optsNoiseSnare).toMaster(); const noise2 = new Tone.NoiseSynth(optsNoiseHihat).toMaster(); // シンセ実行 const kick = () => { membrane.triggerAttackRelease('C0','2n'); }; const snare = () => { noise1.triggerAttackRelease('8n'); }; const hihat = () => { noise2.triggerAttackRelease('32n'); }; //リズム設定 let kickRhythm = [ ['0:0:0'], ['0:2:0'], ]; let snareRhythm = [ ['0:1:0'], ['0:3:0'], ]; let hihatRhythm = [ ['0:0:0'], ['0:0.5:0'], ['0:1:0'], ['0:1.5:0'], ['0:2:0'], ['0:2.5:0'], ['0:3:0'], ['0:3.5:0'], ]; // シンセにリズムを設定 let kickPart = new Tone.Part(kick, kickRhythm).start(); let snarePart = new Tone.Part(snare, snareRhythm).start() let hihatPart = new Tone.Part(hihat, hihatRhythm).start(); // ループ設定 kickPart.loop = true; snarePart.loop = true; hihatPart.loop = true; // BPM設定 Tone.Transport.bpm.value = 90; // クリックイベント beat.addEventListener('click', () => { Tone.Transport.toggle(); }, false);
エイトビートを複雑なビートにしてみる
エイトビートその1(ドン|タン|ドド|タン)
前回もやったやつ。
「ドン|タン|ドド|タン」という音が鳴る。
See the Pen tone.js-DrumBeat_5 by イイダリョウ (@i_ryo) on CodePen.
※音が鳴らない場合:CodePen - tone.js-DrumBeat_5
キック音
let kickRhythm = [ ['0:0:0'], ['0:2:0'], ['0:2.5:0'], ];
- 変数
kickRhythm
に音符2.5
を追加。
エイトビートその2(ドン|タド|ドン|タン)
これも前回やったやつ。
「ドン|タド|ドン|タン」という音が鳴る。
See the Pen tone.js-DrumBeat_6 by イイダリョウ (@i_ryo) on CodePen.
※音が鳴らない場合:CodePen - tone.js-DrumBeat_6
キック音
//リズム設定 let kickRhythm = [ ['0:0:0'], ['0:1.5:0'], ['0:2:0'], ];
- 変数
kickRhythm
に音符1.5
を追加。
エイトビートその3(ドンッド|タッタッ|ッドン|タドン)
文字にするとわけわかんないけどw とにかく鳴らしてみてくだせい。
「ドンッド|タッタッ|ッドン|タドン」という音が鳴る
See the Pen tone.js-DrumBeat_7 by イイダリョウ (@i_ryo) on CodePen.
※音が鳴らない場合:CodePen - tone.js-DrumBeat_7
キック音
let kickRhythm = [ ['0:0:0'], ['0:0.75:0'], ['0:2.5:0'], ['0:3.25:0'], ];
- 変数
kickRhythm
の音符を0
、0.75
、2.5
、3.25
に
次、スネア部分
let snareRhythm = [ ['0:1:0'], ['0:1.75:0'], ['0:3:0'], ];
- 変数
snareRhythm
の音符を1
、1.75
、3
に(1.75
)を追加
0.25刻みの音符を入れることで16分音符のタイミングも指定できた。
ただ、あまり発生音が近接するとなんか乱れた音になるようだ。なんとかしたい。
最後に
ということでTone.Part()
を使って細かいタイミングのエイトビートを鳴らすことができました。前回のfor文と違って楽器ごとに細かい数値で指定できるので打ち込みやすくなりました♪
ちょっと気になるのは音が近接した時の音の乱れです。これまでも全く同じタイミングで鳴らすとハイハットの音が聞き取りにくいなどは感じてましたが、想定どおりに再生をコントロールするには対策を調べた方が良さそうです。
次回はTone.Part()
を使ってさらに色々なリズムを鳴らしてみたく思います。おそらく変拍子やシャッフル系のリズムもいけるんじゃないかと思っています。それではまた!
※参考:Tone.jsを習得するためにやった事まとめ
qiita.com