クモのようにコツコツと

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

【Tone.js】3コード楽器を1オクターブに拡張する

Tone.jsシリーズ、前回は3コード楽器のコードを拡張しやすいようにリファクタリングしました。今回は鍵盤を1オクターブ分に拡張しました。また、和音の一箇所を打ち替えるだけでメジャー調をマイナー調に変更することにも成功。それではどうぞ!

【目次】

※参考:【Tone.js】3コード楽器のコードをリファクタリング(ループとイベントと即時関数) - クモのようにコツコツと

前回のおさらい(3コード)はこちら

前回の3コード

See the Pen tone.js-3cord-6 by イイダリョウ (@i_ryo) on CodePen.

コードの詳細は前回記事を参照。

※参考:【Tone.js】3コード楽器のコードをリファクタリング(ループとイベントと即時関数) - クモのようにコツコツと

これを1オクターブに拡張したい。

メジャースケール(1オクターブ)

試行錯誤して、鍵盤を1オクターブ分増やせた。

See the Pen tone.js-12cord-1 by イイダリョウ (@i_ryo) on CodePen.

以前作った1オクターブ鍵盤と同じ見た目だが、鍵盤を弾くとメジャースケールの和音が鳴る。

※参考:【tone.js】一音鍵盤を1オクターブに拡張したらコードが冗長だったので書き直した - クモのようにコツコツと

HTLMコード

<h1>和音</h1>
<p>メジャー(1オクターブ)</p>
<ul id="piano">
   <li id="C4" class="w_key"></li>
   <li id="Cs4" class="b_key"></li> 
   <li id="D4" class="w_key"></li>
   <li id="Ds4" class="b_key"></li> 
   <li id="E4" class="w_key"></li>
   <li id="F4" class="w_key">ファ</li>
   <li id="Fs4" class="b_key"></li>
   <li id="G4" class="w_key"></li>
   <li id="Gs4" class="b_key"></li>
   <li id="A4" class="w_key"></li>
   <li id="As4" class="b_key"></li>
   <li id="B4" class="w_key"></li>
   <li id="C5" class="w_key"></li>
</ul>

HTMLは1オクターブ鍵盤の時とほどんど同じ。(省略するがCSSも同じ)

次、JSコード

まずDOMの取得。

//DOM
var Key = document.querySelectorAll('#piano li');

3コードの時は鍵盤一つずつID名で取得したが今回はliタグをquerySelectorAll()で配列として取得した。鍵盤が1オクターブの12音階(白鍵8+黒鍵4)に次のオクターブのドを加え全部で12個。この方法は1オクターブ鍵盤の時と同じ方法。

次に音階の設定。

//音階
var scale = [
  //休符
  'null', 
  //1オクターブ目
  'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'F#4', 'G4', 'G#4', 'A4', 'A#4', 'B4',
  //2オクターブ目
  'C5', 'C#5', 'D5', 'D#5', 'E5', 'F5', 'F#5', 'G5', 'G#5', 'A5', 'A#5', 'B5'];

変数scaleに2オクターブ分の音階名を入れる。これの名前はTone.jsの正式名称でC44は一番低い音から4オクターブ目を意味する。ここは前回と変わらない。

この後に細々とした設定をしている。まずルート音(和音の一番低い音)。

//ルート音
var root = {C4: 0, Cs4: 1, D4: 2, Ds4: 3, E4: 4, F4: 5, Fs4: 6, G4: 7, Gs4: 8, A4: 9, As4: 10, B4: 11, C5: 12};

まず変数rootに連想配列で和音のルート音を設定。前回の12音階に加えてC5キーを追加。

次にメジャースケールの音程を設定。

//メジャースケール
var codeM =[1,5,8];

ルート音を1とすると第二音は5、第三音は8(前回と同じ設定)

変数twelveCodeの配列にルート音を登録。

//12コード
var twelveCode =[root['C4'],root['Cs4'],root['D4'],root['Ds4'],root['E4'],root['F4'],root['Fs4'],root['G4'],root['Gs4'],root['A4'],root['As4'],root['B4'],root['C5']]

前回は3コードなので3つだったが今回は13個のルート音を全て登録。

変数chordsは和音入れ場。

//和音入れ場
var chords = [];

前回はここに3コードthreeCodeの配列の値を入れたが、よく考えたらここは空っぽの器にすればいいことがわかった。

次に和音を作る。

//和音
for (var i = 0 ; i < Key.length; i++ ) {
  chords.push( [] );
  for (var  j = 0; j < codeM.length; j++){
    var nmb = scale[twelveCode[i]+codeM[j]];
    chords[i].push(nmb); 
  }
}
  • キーボード13個分の回数lengthを繰り返す。
  • 先ほどのchordsに空の配列をここで13個追加pushする。
  • 入れ子のループでcodeMの3和音分の回数lengthを繰り返す。
  • 変数nmbscalei番目に3和音のルート、第二音、第三音を入れる。
  • 和音入れ場chordsi番目にnmbの音を追加する。

シンセ音を生成

//シンセ生成
var synth = new Tone.PolySynth().toMaster();

ここは前回通り

鍵盤を叩いたときのクリックイベント

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(chords[i], '4n');
  }, false);
 })(i);
}
  • 13個分の回数lengthを繰り返す。
  • キーボードのi番目をクリックした時に
  • chordsI番目の音が鳴る

JSコードの全体

//DOM
var Key = document.querySelectorAll('#piano li');

//音階
var scale = [
  //休符
  'null', 
  //1オクターブ目
  'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'F#4', 'G4', 'G#4', 'A4', 'A#4', 'B4',
  //2オクターブ目
  'C5', 'C#5', 'D5', 'D#5', 'E5', 'F5', 'F#5', 'G5', 'G#5', 'A5', 'A#5', 'B5'];

//ルート音
var root = {C4: 0, Cs4: 1, D4: 2, Ds4: 3, E4: 4, F4: 5, Fs4: 6, G4: 7, Gs4: 8, A4: 9, As4: 10, B4: 11, C5: 12};

//メジャースケール
var codeM =[1,5,8];

//12コード
var twelveCode =[root['C4'],root['Cs4'],root['D4'],root['Ds4'],root['E4'],root['F4'],root['Fs4'],root['G4'],root['Gs4'],root['A4'],root['As4'],root['B4'],root['C5']]

//和音入れ場
var chords = [];

//和音
for (var i = 0 ; i < Key.length; i++ ) {
  chords.push( [] );
  for (var  j = 0; j < codeM.length; j++){
    var nmb = scale[twelveCode[i]+codeM[j]];
    chords[i].push(nmb); 
  }
}

//シンセ生成
var synth = new Tone.PolySynth().toMaster();

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //ID名取得
    var idName = this.id;
  //3コードが8分音符の長さ鳴る
  synth.triggerAttackRelease(chords[i], '4n');
  }, false);
 })(i);
}

和音をマイナーに

和音部分を打ち替えるとマイナー調になった!哀愁を帯びてる。

See the Pen tone.js-12cord-2 by イイダリョウ (@i_ryo) on CodePen.

変えた場所は1箇所!

//マイナースケール
var codeM =[1,4,8];

変数codeMの配列の2番目を5から4にしただけ!和音の第二音が半音下がる。

最後に

f:id:idr_zz:20190730235120j:plain

四苦八苦しながらなんとか作れました。ルート音rootの連想配列を12コードtwelveCodeの配列に登録するあたり、もう少し簡略化できたらなーと思います。普段あまり使わないけど、for...inとか配列系のfor文がいくつかあるようなので、それを使うと簡略化できるかもしれない。成功したら記事にします。

和音を1箇所うち変えたらメジャー調がマイナー調になりました!この意気でセブンスとかナインスとかいろんな和音を作っていきたい。できればそれをボタンで一発で切り替えるところまで行きたいです。あとはアルペジオ(分散和音)など伴奏メロディに切り替えたり、シンセ音を切り替えたり。

やりたいことは果てしなく有りますが、引き続きコツコツと継続。それではまた!


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