Tone.jsの続きです。前回はコード切り替えボタンを設置しました。が、まだ鍵盤の音とは連携できていません。今回はその連携にチャレンジ。それではいきましょう!
【目次】
- 前回のおさらい
- コードタイプを連想配列に入れる
- 切り替えボタンのコードタイプ名を戻り値で返してみる
- コードタイプをただの配列にしてみる
- 切り替えボタンの戻り値をコードタイプ配列のi番目にする
- 和音をコードタイプ数分、多重ループさせてみる
- ラジオボタンの選択状態を取得
- 選択したコードタイプに該当する和音を呼び出し
- 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); } }
codeM
をcodeTypes['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文でcodeTypes
のh
番目の数だけループ - 変数
nmb
でscale
の中の配列twelveCode
のi
番目の値と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
番目の配列を指定。
これで変数seletcCords
はchords[i]
になり、seletcCords[i]
はchords[i][i]
になる。chords[I]
のi
はコードタイプの切り替えボタンが押された時点で0
か1
が入った状態になっている。
さあどうだ!!?
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); }
最後に
ということで、ようやくコード切り替えボタンと鍵盤の紐付けが完成しましたー。結構難産だった。。Tone.jsの機能ではなくバニラJSのプログラミング知識が必要な段階の内容だった。(きっともっとスマートな書き方があるのだと思うが…)
次は、ようやくマイナー、メジャー以外のいろんなコードを設定してみたく。それではまた!!
※参考:Tone.jsを習得するためにやった事まとめ qiita.com