久々にTone.js再開!前回はコード切り替えボタンと鍵盤を連携しました。これからコードを増やしていくにあたり、今の書き方だとコード名とコード音の把握が分かりにくくなりそうな気がします。今回はコードのリファクタリングをメインにしてみたく思います。それでは行きましょう!
【目次】
※参考:【Tone.js】コード切り替えボタンと鍵盤の連携 - クモのようにコツコツと
※参考:Tone.jsを習得するためにやった事まとめ qiita.com
前回のおさらい
前回作ったもの。
See the Pen tone.js-12cord- 10 by イイダリョウ (@i_ryo) on CodePen.
上の切り替えボタンを押すとボタンの下のコード名の表記が変わる。そして鍵盤の和音がメジャー、マイナーに切り替わる。
※参考:【Tone.js】コード切り替えボタンと鍵盤の連携 - クモのようにコツコツと
コードタイプの書き換え
コードタイプ名を連想配列に変更
コードタイプのところは配列になっている。
//コードタイプ var codeTypes = [ [1,5,8],[1,4,8] ];
- 変数
codeTypes
の中に配列。値は2つ。値も配列になっている - 1番目の値の配列はメジャーでルート音(1)に5音上、8音上を重ねる
- 2番目の値の配列はマイナーでルート音(1)に4音上、8音上を重ねる
今は2種類だから1番目、2番目でいいのだが、このままだとコード種類を増やしたときに「○番目」と数えるのが直感的ではない。
配列の中を連想配列に書き換えてみる。
//コードタイプ var codeTypes = [ {'codeName': 'M', 'codeKeys': [1,5,8]}, {'codeName': 'm', 'codeKeys': [1,4,8]} ];
- 変数
codeTypes
の中に配列。値は2つ。値は連想配列に変更 - 1番目の値の
codeName
キーの値=メジャー(M)、
codeKeys
キーの値=ルート音(1)に5音上、8音上を重ねる - 2番目の値の
codeName
キーの値=マイナー(m)、
codeKeys
キーの値=ルート音(1)に4音上、8音上を重ねる
Console.logで検証
ちゃんと変数が読めるかConsole.logで検証する。
//検証 console.log(codeTypes[1]['codeKeys'].length); //3 console.log(codeTypes[1]['codeKeys'][2]); //8
- 変数
codeTypes
の配列1番目のcodeKeys
キーの値の数をコンソールに表示→3つ - 変数
codeTypes
の配列1番目のcodeKeys
キーの値の3番目の値をコンソールに表示→8
配列1番目はメジャーで和音の数は3つ。和音の3番目(0からカウントなので2)は8
ちゃんと読めているようだ。
和音のfor文の書き換え
和音を作るfor文を書き換える。元のコードはこちら。
//和音 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); } } }
for文は3重のループになっている。このうちCodeType
が出てくるのは1番目と3番目。しかし、1番目codeTypes.length
はcodeTypes
直下の配列数(コードタイプ数)でメジャー、マイナーの2種類なので変わらない。変わるのは3番目のループの部分。ここにcodeKeys
キーを反映する。
変更後のコード
//和音 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]['codeKeys'].length; j++){ var nmb = scale[twelveCode[i]+codeTypes[h]['codeKeys'][j]]; chords[h][i].push(nmb); } } }
- for文の条件の2番目、
codeTypes[h].length
をcodeTypes[h]['codeKeys'].lengthに変更 - 変数
nmb
のcodeTypes[h][j]
をcodeTypes[h]['codeKeys'][j]
に変更
codeTypes[h]
のあとに['codeKeys']
を追記するとこで「変数codeTypes
の配列h
番目のcodeKeys
キーの」という意味になる。for文の条件はcodeKeys
キーの値の数、変数nmb
はcodeKeys
キーのj
番目、という意味になる。
できたのがこちら!
See the Pen tone.js-12cord- 11 by イイダリョウ (@i_ryo) on CodePen.
見た目も動きもまったく変わらないのだが、キーの種類はわかりやすくなってコードは読みやすくなった!
なお、コード名を「Cメジャー」「Eマイナー」などわかりやすいように鍵盤の表記はローマ字(C〜)に変更した。
和音の書き換え
ルート音と12コードを連想配列でまとめる
同じようなやり方で和音の部分の書き換えられそう。
元のコード
//ルート音 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}; //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']]
- 変数
root
は連想配列。キー名にC4などの鍵盤名、値に0からカウントを始める数字 - 変数
twelveCode
は配列。配列root
のキー名の値を入れる
これは下のfor文をキー名ではなくi
番目と数字で指定するために、わざわざroot
に数字を入れている。
似たような内容が2つの場所に分かれているのがわかりにくので合体させてみる。
//ルート音 var root =[ {'rootName':'C4', 'rootNmb': 0}, {'rootName':'Cs4', 'rootNmb': 1}, {'rootName':'D4', 'rootNmb': 2}, {'rootName':'Ds4', 'rootNmb': 3}, {'rootName':'E4', 'rootNmb': 4}, {'rootName':'F4', 'rootNmb': 5}, {'rootName':'Fs4', 'rootNmb': 6}, {'rootName':'G4', 'rootNmb': 7}, {'rootName':'Gs4', 'rootNmb': 8}, {'rootName':'A4', 'rootNmb': 9}, {'rootName':'As4', 'rootNmb': 10}, {'rootName':'B4', 'rootNmb': 11}, {'rootName':'C5', 'rootNmb': 12} ]
- 変数
root
の中は配列。配列の値は連想配列。 - 連想配列の中は
rootName
キー(ルート音)とrootNmb
キー(番号)
コンソールで検証
//検証 console.log(root.length); //13 console.log(root[3]['rootNmb']); //3
- 配列
root
の数→13 - 配列
root
の4番目のrootNmb
キーの番号→3
うむ、想定通りに読めてる。
for文の書き換え
和音のfor文を書き換える。
元のコート
//和音 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]['codeKeys'].length; j++){ var nmb = scale[twelveCode[i]+codeTypes[h]['codeKeys'][j]]; chords[h][i].push(nmb); } } }
多重ループの3番目のfor文、変数nmb
の中にtwelveCode
がある。ここを書き換える。
変更後
//和音 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]['codeKeys'].length; j++){ var nmb = scale[root[i]['rootNmb']+codeTypes[h]['codeKeys'][j]]; chords[h][i].push(nmb); } } }
twelveCode[I]
をroot[i]['rootNmb']
に変更
さあどうだ?
See the Pen tone.js-12cord- 12 by イイダリョウ (@i_ryo) on CodePen.
やた!なった!
つーか鍵盤(Key)の数でよかった…
そこでふと気づいたのだが、そもそものfor文のi
番目は変数Key
の数length
ではないか?
もしかしてKey
の数(i
)を入れるだけでいい?とよぎった…。
//和音 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]['codeKeys'].length; j++){ var nmb = scale[i+codeTypes[h]['codeKeys'][j]]; chords[h][i].push(nmb); } } }
変数nmb
のroot[i]['rootNmb']
をi
に変更
恐る恐る実行…
See the Pen tone.js-12cord- 13 by イイダリョウ (@i_ryo) on CodePen.
うお!音がなった!なんだ、鍵盤数(i
)を入れればいいだけだったんだ!
ということで、変数root
はまるまる削除したw
最終的なコード
最新状態はこんなん。
//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 codeTypes = [ {'codeName': 'M', 'codeKeys': [1,5,8]}, {'codeName': 'm', 'codeKeys': [1,4,8]} ]; //和音入れ場 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]['codeKeys'].length; j++){ var nmb = scale[i+codeTypes[h]['codeKeys'][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); }
結局、ルート音のコードはまるまる必要ないということに気づいた旅だったw
最後に
ということで、今回はコードのリファクタリングのみ!外観は鍵盤名をローマ字にしたくらい。次回はいよいよ、コードの種類をいろいろ増やしていきたいと思います!(セブンスとかナインスとか)それではまた!
※参考:Tone.jsを習得するためにやった事まとめ qiita.com