クモのようにコツコツと

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

【Tone.js】コード切り替えボタンと鍵盤の連携

Tone.jsの続きです。前回はコード切り替えボタンを設置しました。が、まだ鍵盤の音とは連携できていません。今回はその連携にチャレンジ。それではいきましょう!

【目次】

前回の記事

※参考:【Tone.js】コード切り替えボタンを設置(鍵盤とは未連動) - クモのようにコツコツと

前回のおさらい

鍵盤の上のコードタイプの切り替えボタンを設置。

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

ボタンを押すとコードタイプ名が表示される。しかし鍵盤の音には連携しない。

変数codemにマイナーコードは書いてあるがどことも紐づいていない。

//メジャー
var codeM =[1,5,8];
//マイナー
var codem =[1,4,8];

鍵盤からはメジャーコードcodeMを直接呼び出している。

//和音
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); 
  }
}

詳細はこちら

※参考:【Tone.js】コード切り替えボタンを設置(鍵盤とは未連動) - クモのようにコツコツと

コードタイプを連想配列に入れる

2種類のコードを変数codeTypeの中に連想配列として入れてみる。

//コードタイプ
var codeTypes = {
  codeM: [1,5,8],
  codem: [1,4,8]
};

試しに2番目のcodemを鍵盤から呼び出してみる。

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

codeMcodeTypes['codem']に変更した。

さあどうだ?

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

やた!ちょっと哀愁お帯びたマイナーな和音になった。

切り替えボタンのコードタイプ名を戻り値で返してみる

切り替えボタンのコードタイプ名CodeTypeValueを関数codeTypeSelect()の戻り値として返してみる。

//コードタイプ設定
  function codeTypeSelect() {
    var codeType = document.getElementsByName("code_type");
    for(var i = 0; i < codeType.length; i++){
      if(codeType[i].checked) {
        var CodeTypeValue = codeType[i].value;
        codeTypeText.innerHTML = CodeTypeValue;
        return CodeTypeValue;
      }
    }
  }

return CodeTypeValue;の部分。これで関数codeTypeSelect()を実行するとCodeTypeValueを返すはず。

ちゃんと返しているかテスト。鍵盤のクリックイベントにアラートを仕込む。

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(chords[i], '4n');
  //コードタイプを出してみるテスト
  alert(codeTypeSelect());
  }, false);
 })(i);
}

alert(codeTypeSelect());の部分、アラートの中で関数codeTypeSelect()を実行している。

さあどうだ?

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

やた!鍵盤を押した時に出るアラート、上の切り替えボタンを「マイナー」にすると「codem」になる!想定通り。

コードタイプをただの配列にしてみる

さて、このままだと上の切り替えボタンcodeTypeSelect()とコードタイプcodeTypesの繋げ方がまだ思いつかない…。

切り替えボタンのfor文の「i番目」とうまく絡められないかな。先ほどのcodeTypesの連想配列をただの配列にしてみよう。

//コードタイプ
var codeTypes = [
  [1,5,8],[1,4,8]
];

変数codeTypesの波括弧{ }を角kakko[ ]にして、キー名をなくした。

和音部分

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

codeTypes[1]のところ。配列codeTypes[1]番目=2番目(ゼロからカウントするので)

さあどうだ?

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

やた!2番目に相当するマイナーコードが鳴ってくれている。

切り替えボタンの戻り値をコードタイプ配列のi番目にする

切り替えボタンのreturnを書き換えてみる。

//コードタイプ設定
  function codeTypeSelect() {
    var codeType = document.getElementsByName("code_type");
    for(var i = 0; i < codeType.length; i++){
      if(codeType[i].checked) {
        var CodeTypeValue = codeType[i].value;
        codeTypeText.innerHTML = CodeTypeValue;
        var selectType = codeTypes[i]
        return selectType;
      }
    }
  }
  //コードタイプ実行
  codeTypeSelect();

変数selectTypeを作成。値はcodeTypes[i]で先ほどのコードタイプ配列のi番目にする。 そして戻り値をselectTypeにする。

さあどうだ?

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

鍵盤を押すと出るアラート、切り替えボタンがメジャーなら「1,5,8」、マイナーなら「1,4,8」になった!

和音をコードタイプ数分、多重ループさせてみる

和音のfor部分をコードタイプの数だけ多重ループにして配列も多次元配列にしてみる。

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

和音入れ場になっている変数chordsは変更なし。この中を多次元配列にする。

//和音
for (var h = 0 ; h < codeTypes.length; h++ ) {
  chords.push( [] );
  for (var i = 0 ; i < Key.length; i++ ) {
    chords[h].push( [] );
    for (var  j = 0; j < codeTypes[h].length; j++){
      var nmb = scale[twelveCode[i]+codeTypes[h][j]];
      chords[h][i].push(nmb); 
    }
  }
}
  • 一番外側で外側に変数hのfor文でcodeTypesの数だけループ
  • 和音入れ場chordsに配列を追加
  • 変数iのfor文でキーボードの数だけループ
  • chords内の配列h番目に配列を追加
  • 変数jのfor文でcodeTypesh番目の数だけループ
  • 変数nmbscaleの中の配列twelveCodei番目の値とcodeTypesの中のh番目のさらに中のj番目の値を追加
  • chordsの中のh番目のさらに中のi番目にnmbを追加

多次元配列はあとから読むと自分でもわかりにくい…。三重くらいが限界かな。

で、これをどうやって鍵盤に適用するかだけど…とりあえずベタ打ちで指定するか。

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(chords[0][i], '4n');
  //コードタイプを出してみるテスト
  alert(codeTypeSelect());
  }, false);
 })(i);
}

chords[0][i]chordsの中の0番目のさらに中のi番目を呼び出す。

どうか…?

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

ふー、とりあえず0番目にあたるメジャーコードは鳴った(ここに至るまでも何度も試行錯誤してます。。)

あとはこれを切り替えボタンと連携させたい。

ラジオボタンの選択状態を取得

方法を調べていて、ヒントになる記事があった!

※参考:JavaScriptでラジオボタンの選択状態を取得する | UX MILK

ラジオボタンの取得状態をチェックしているが、for文のi番目という書き方になっている!

この書き方に従うと先ほどのchords[0][I]の一つ目の配列[0]は切り替えボタンのところでchords[i]にすればいいっぽい。

切り替えボタンの設定

//コードタイプ設定
  function codeTypeSelect() {
    for(var i = 0; i < codeType.length; i++){
      if(codeType[i].checked) {
        var CodeTypeValue = codeType[i].value;
        codeTypeText.innerHTML = CodeTypeValue;
        alert(codeType[i].value + "は" + chords[i]);
      }
    }
  }

アラートでchords[I]を加えてみる。

鍵盤のイベント設定

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(chords[0][i], '4n');
  //コードタイプを出してみるテスト
  codeTypeSelect()
  }, false);
 })(i);
}

関数codeTypeSelect()を実行

さて、どうか?

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

おお、鍵盤を押すと、メジャーの時はメジャーの内訳、マイナーのときはマイナーの内訳の和音が表示された!

あとはこれを音に繋げられればOK!

選択したコードタイプに該当する和音を呼び出し

もう一歩のとこまで来ているっぽい!このまま完成まで頑張る。

//コードタイプ設定
  function codeTypeSelect() {
    for(var i = 0; i < codeType.length; i++){
      if(codeType[i].checked) {
        var CodeTypeValue = codeType[i].value;
        codeTypeText.innerHTML = CodeTypeValue;
           return chords[i];
      }
    }
  }

まず、先ほどのアラートは消して、戻り値でchords[i]を返す。

鍵盤のイベント

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //チェックされているコードタイプを確認
  var seletcCords = codeTypeSelect();
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(seletcCords[i], '4n');
  }, false);
 })(i);
}
  • 変数seletcCordsの値に関数codeTypeSelect()を入れる。
  • synth.triggerAttackRelease()メソッドの中、seletcCordsのさらに中のi番目の配列を指定。

これで変数seletcCordschords[i]になり、seletcCords[i]chords[i][i]になる。chords[I]iはコードタイプの切り替えボタンが押された時点で01が入った状態になっている。

さあどうだ!!?

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

いけた!コードタイプの切り替えボタンを押すとメジャーコード、マイナーコードに切り替わった!!!

JSコード全体

読み込み順の問題で動かないかったのでいくつかの順番を入れ替えている。

//DOM
var Key = document.querySelectorAll('#piano li');
var codeTypeText = document.querySelector('#code_type_text');
var codeType = document.getElementsByName("code_type");


//音階
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 codeTypes = [
  [1,5,8],[1,4,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 h = 0 ; h < codeTypes.length; h++ ) {
  chords.push( [] );
  for (var i = 0 ; i < Key.length; i++ ) {
    chords[h].push( [] );
    for (var  j = 0; j < codeTypes[h].length; j++){
      var nmb = scale[twelveCode[i]+codeTypes[h][j]];
      chords[h][i].push(nmb); 
    }
  }
}

//コードタイプ設定
  function codeTypeSelect() {
    for(var i = 0; i < codeType.length; i++){
      if(codeType[i].checked) {
        var CodeTypeValue = codeType[i].value;
        codeTypeText.innerHTML = CodeTypeValue;
           return chords[i];
      }
    }
  }

codeTypeSelect();

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

//イベントリスナ
for (var i = 0; i < Key.length; i++) {
(function(i) {
  Key[i].addEventListener('click', function () { 
  //チェックされているコードタイプを確認
  var seletcCords = codeTypeSelect();
  //メジャーコードが4分音符の長さ鳴る
  synth.triggerAttackRelease(seletcCords[i], '4n');
  }, false);
 })(i);
}

最後に

f:id:idr_zz:20190908190322j:plain

ということで、ようやくコード切り替えボタンと鍵盤の紐付けが完成しましたー。結構難産だった。。Tone.jsの機能ではなくバニラJSのプログラミング知識が必要な段階の内容だった。(きっともっとスマートな書き方があるのだと思うが…)

次は、ようやくマイナー、メジャー以外のいろんなコードを設定してみたく。それではまた!!


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