#プログラミングでコード(和音)を鳴らす(Tone.js)(1)
##この記事を書くに至った経緯
音楽が好きなこともあり、何か音楽に絡めたプログラミングとかしてみたいなーと思い、
ネットサーフィンしていると見つけたのがTone.jsでした。
これをどんなふうに使っているのかなど読み漁っていくうちに
これ使えば楽器弾けない人でもコード進行を作れて、
コード進行を確認するのにも使えるツールを作れるんじゃね?と思いつきました。
それから、CPM(コード進行作成ツール)なるものを作ったものの、
大した宣伝もしていなかったので、自分しか使っていませんでした。
せっかく作ったのに、このまま放っておくのも勿体ないかなーと思ったので、
いい機会だし、Qiitaで記事でも書いてみようとなったわけです。
CPMもよろしければ一度触ってみてください↓
CPM(コード進行作成ツール)
##今回ご紹介すること
- HTMLでコードを選択する部分を作成する方法
- コード(和音)を関数で簡単に用意する方法
- 選んだコードを鳴らす方法
以上を私が作ったものを元に紹介していきます。
##前提
- HTMLとJavascriptを使います。
- Tone.jsはダウンロードしてあるものとし、HTMLファイルと同階層にあるとします。
- 同様にselect.jsもHTMLファイルと同階層にあるとします。
##HTMLでコードを選択する部分を作成する
簡単に言うとHTMLのselectを使います。
下にソースコード(htmlファイル全文)を記しておきます。
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" charset="UTF-8">
<title>コード再生</title>
<script src="Tone.js"></script>
<script src="select.js"></script>
</head>
<body style="text-align:center;">
<h1>コード再生</h1>
<div>
<select id="chord" style="font-size:2em"></select>
</div>
<button id="play" style="margin:30px;">play!!</button>
</body>
これで実際のファイルをブラウザで開いてみると下の図1のようになります。
図1:htmlファイルのみ表示した画像
枠だけ作って中身は入れていないので、もちろん何もできません。
これからここにJavascriptで中身を入れていきます。
1オクターブ上がるまでに音、すなわちコードは12個あります。
これを1つ1つ手打ちで用意するのは大変なので、関数を用意します。
まず、12個の音の配列を用意します。
連想配列にはしません。(後々便利なので)
const tone=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];
const Key=4;
先にこれを使って、selectに要素を加えます。
HTMLのselectにidを振っておいたのはこのためです。
また下にあるKeyは音の高さを表しています。(例えばA4がA3の1オクターブ上の音)
function opt_make() {
let chord = document.getElementById("chord");
let opt = "";
for (let i = 0; i < 12; i++) {
opt += "<option value=" + tone[i] +">" + tone[i] + "</option>";
}
chord.innerHTML = opt;
}
これを入れることで下の図2のように音が選べるようになります。
図2:selectに選択する要素を表示した画像
##コード(和音)を関数で簡単に用意する方法
1オクターブの間に音が12個であることと、
コードのルート音以外の音が根音(ルート音)との相対関係によって決まることを利用します。
根音(ルート音)、すなわちコード名とそれを1度としたときの他の2つの音の度数を入れるとコードを作る関数を作成します。
番号が12を超えた場合、そこから12を引いたのちに対応するkeyをインクリメントすることで、
少ない配列でできるようにしています。
function make_chord(i,k,t3,t5){
key={1:k,3:k,5:k};
let I,III,V;
let chord;
I=i;
III=i+t3;
V=i+t5;
if(III>=12){
III-=12;
key[3]+=1;
}
if(V>=12){
V-=12;
key[5]+=1;
}
chord=[tone[I]+key[1],tone[III]+key[3],tone[V]+key[5]];
return chord;
}
私が最初にこの関数を作ったときには7thコードとかのことを考えて、
引数をもう少し多く用意していましたが、
結局あとで加えたほうが管理しやすいと言うことになったので、
基本となる3音だけで作るようにしました。
i→ルート音のtoneでの番号
k→Key(音の高さ)
t3→ルート音の1つ上の音(メジャーコードでいうルート音を1度とした場合の3度の音)の番号
t5→ルート音の2つ上の音(メジャーコードでいうルート音を1度とした場合の5度の音)の番号
として、いろんな種類のコードを作っています。
以下では例としてメジャーコードを用意します。
var M_chord=[];
function prepare_chord(Key){
for(let i=0;i<12;i++){
M_chord[tone[i]]=make_chord(i,Key,4,7);
}
}
音が全部で12音あるので、
3度の音はルートの音に4足して、5度の音はルートの音に7足してできるのが今回作ったメジャーコードです。
マイナーコードならば3度の音に加える番号を4から3にすればいいということになります。
(配列toneでは番号が1増えるごとに半音上がります。)
ここで使っている音楽の知識はそこまで難しいものではないです。
「コード理論」などで調べていただければ、
参考にするといいかもしれない文献にも載せてあるようないいサイトが結構出てきますし、
それを読んでいればわかるようなことだと思うので、
必要な方は是非そちらを参考にしてみてください。
##選んだコードを鳴らす方法
次に先ほど用意したコードを鳴らす部分を作っていきます。
先にソースコードを示しておきます。
var synth = new Tone.PolySynth().toMaster();
function play_chord() {
let r = document.getElementById("chord").value;
prepare_chord(Key);
Tone.Transport.bpm.value = 100;
synth.triggerAttackRelease(M_chord[r], '4n');
}
同時にたくさんの音を鳴らすので、PolySynthを使います。
bpmは100に設定しています。「4n」は4分の長さで音を出すということです。
それではplayボタンを用意しておいたので、
押すとselectの部分に表示されたコードがなるようにしていきます。
と言っても簡単なので、ソースコードを先に示しておきます。
window.onload = function () {
opt_make();
document.getElementById("play").addEventListener("click", function () {
play_chord();
});
}
window.onloadを使います。
「opt_make()」でselect部にコードを選択するボタンを用意しています。
playボタンを押すとplay_chord関数を呼び出して、音がなるようにしています。
##出来上がったselect.jsのソースコード
var synth = new Tone.PolySynth().toMaster();
const tone=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];
const Key=4;
var M_chord=[];
function prepare_chord(Key){
for(let i=0;i<12;i++){
M_chord[tone[i]]=make_chord(i,Key,4,7);
}
}
function make_chord(i,k,t3,t5){
key={1:k,3:k,5:k};
let I,III,V;
let chord;
I=i;
III=i+t3;
V=i+t5;
if(III>=12){
III-=12;
key[3]+=1;
}
if(V>=12){
V-=12;
key[5]+=1;
}
chord=[tone[I]+key[1],tone[III]+key[3],tone[V]+key[5]];
return chord;
}
function opt_make() {
let chord = document.getElementById("chord");
let opt = "";
for (let i = 0; i < 12; i++) {
opt += "<option value=" + tone[i] +">" + tone[i] + "</option>";
}
chord.innerHTML = opt;
}
function play_chord() {
let r = document.getElementById("chord").value;
prepare_chord(Key);
Tone.Transport.bpm.value = 100;
synth.triggerAttackRelease(M_chord[r], '4n');
}
window.onload = function () {
opt_make();
document.getElementById("play").addEventListener("click", function () {
play_chord();
});
}
##考察
コードを作る部分とコードを用意する部分を別に関数で用意しましたが、
classを使えばもう少し綺麗にかけて扱いやすいものになっていたのかもしれないなーと思いました。
javascriptは元々軽くゲームを作ったり、行列計算ソフトを作っていただけなので、
書き慣れておらず、書き方が変になっているところもあると思いますが、ご容赦ください。
ご意見等がございましたら、コメントいただければ幸いです。
##感想
今回はメジャーコードだけ鳴らせるようにしましたが、
prepare_chordに別の種類のコードを追加して、select部を増やしていけば、
鳴らせるコードを増やすことができます。
気が向いたら、(2)を作るつもりです。
最後まで読んでいただきありがとうございました。
##参考にするといいかもしれない文献
ギタリストのためのコード理論講座
https://www.aki-f.com/kouza/riron/