前回の記事では、楽器をピアノだけにしてメロディーを演奏するプログラムを作りました。今回はそれを発展させてベースとドラムを追加してバンド演奏っぽくしてみたいと思います。
複数の楽器を同時に演奏させても、普通のプログラムの作り方ではそれぞれの楽器に少しずつメロディーのズレが生じてしまいます。
今回はそのようなメロディーのずれを補正するテクニックを使って最後まで演奏するプログラムを作っていきます。
なお、楽曲は前回と同じパブリックドメインであるアメリカ民謡の「I’ve Been Working on the Railroad(日本語の曲名:線路は続くよどこまでも)」にしています。
この記事を読んでいただくと、複数の楽器のタイミングを合わせてバンド演奏するプログラミングの方法が分かります。
完成品
この章の内容をご自身のScratch環境に反映すると、同じ動きを再現することができます。
完成した動き
「緑の旗でスタート」ボタンを押すと『線路は続くよどこまでも』をピアノとベースとドラムで演奏した感じの音楽が流れ始めます。
音楽が流れている間は「演奏中」のロゴが表示され、演奏が終わると消えます。
使用したスプライト
スプライトは「ネコ」「ロゴ」「ピアノ」「ベース」「ドラム」の5つです。
【ネコのスプライト】
スプライトは何でも良いのですが、Scratchで新規プロジェクトをつくると最初に登場するスプライトを使用しています。
【ロゴのスプライト】
新規にスプライトをつくって「演奏中」の文字をタイピングします。画像をベクターモードに変換して「テキスト」ツールを使うとやり易いと思います。
【ピアノのスプライト】
ピアノっぽい絵柄であれば何でも良いです。今回はScratchに標準で用意されている「Keyboard」を読み込んで使っています。
【ベースのスプライト】
ベースっぽい絵柄であれば何でも良いです。今回はScratchに標準で用意されている「Guitar-electric1」を読み込んで使っています。
【ドラムのスプライト】
ドラムっぽい絵柄であれば何でも良いです。今回はScratchに標準で用意されている「Drum Kit」を読み込んで使っています。
スプライト以外に演奏する楽曲の楽譜も必要になります。下に楽譜を示していますので参考にしてください。
完成したスクリプト
完成したスクリプトの全体です。
【ネコのスクリプト】
- ピアノ:すべてのスプライト用 or このスプライトのみ
- ベース:すべてのスプライト用 or このスプライトのみ
- ドラム:すべてのスプライト用 or このスプライトのみ
【ロゴのスクリプト】
【ピアノのスクリプト】
【ベースのスクリプト】
【ドラムのスクリプト】
スクリプトの作り方
ここからはプログラムを作っていく中でポイントとなる部分を説明します。
ポイント①:楽譜から楽器のごとのメロディーやリズムを読み取る
前回の記事で作ったピアノの楽譜にベースとドラムの楽譜を付け加えました。ここからそれぞれの楽器について音階(音の高さ)と拍(音の長さ)を読み取ります。
ベースは、ピアノの楽譜にコード(F B♭ C)が記載されているので、このコードのルート音を弾くように音符を配置しています。また、ドラムは、8ビートで「ツ タン ド ド タン」と叩くように音符を並べています。
ピアノとベースの場合
ピアノの楽譜の読み取りは前回の記事で説明していますので省略します。
ベースの音階は「ファファファファ・シ♭シ♭ファ・ファファファファ・ドドド・ドドファファ・シ♭シ♭ファ・シ♭シ♭ファファ・ファファファ」となります。ヘ音記号であることに注意してください。
ピアノとベースについては、下表を参考にして音符の形を見ればドレミ(音の高さ)と拍(音の長さ)が分かります。
音符・名称 | 拍数(長さ) | 休符・名称 | ||
---|---|---|---|---|
全音符 | 4 | 全休符 | ||
2分音符 | 2 | 2分休符 | ||
4分音符 | 1 | 4分休符 | ||
8分音符 | 0.5 | 8分休符 | ||
16分音符 | 0.25 | 16分休符 | ||
付点全音符 | 6 | 付点全休符 | ||
付点2分音符 | 3 | 付点2分休符 | ||
付点4分音符 | 1.5 | 付点4分休符 | ||
付点8分音符 | 0.75 | 付点8分休符 |
ドラムの場合
一方でドラムについては、五線譜のどの位置(高さ)に音符があるかでどのドラムの種類の楽器を打つかが決まってきます(下図参照)。拍(音符休符の長さ)はピアノなどと同じように読み取ります。
ポイント②:読み取った音符を数値に置き換えてブロックに設定する
ピアノとベースの場合
ピアノとベースについては、「楽器を~にする」ブロックをつかって最初に楽器を選択する必要があります。
楽器を選択したあとに「~の音符を~拍鳴らす」ブロックをつなげていきます。
「~の音符を~拍鳴らす」ブロックを設定するときに、ポイント①で読み取った音階(音の高さ)と拍(音の長さ)を数値に置き換えて設定します。
あらかじめ数値に置き換えてから入力しても良いですし、下の図のようにピアノ鍵盤が表示されるのでクリックして選択することで数値が設定されます。
このようにして設定した「~の音符を~拍鳴らす」ブロックを縦につなげていくことで楽曲を演奏することができます。
ドラムの場合
ドラムの場合は、「~のドラムを~0.5拍鳴らす」ブロックの中で楽器の選択と拍の設定を同時に行います。そのため、ドラム楽器を選択する専用のブロックはありません。
この理由は楽譜を見てもらえば分かりますが、ドラムの音符を置いた位置(高さ)がそもそも楽器の種類を表わすことになっているためです。
あとはピアノなどと同じようにブロックを縦につなげていくことでドラムを演奏することができます。
ポイント③:それぞれの楽器のタイミングを合わせる
演奏する楽曲のテンポは「テンポを~にする」ブロックで設定します。今回は「110bpm」に設定しているので1拍あたり約0.545秒かかる計算になります(60秒÷110bpm)。
しかし、すべての楽器を1拍あたり0.545秒間隔で最後まで正確に演奏することをScratchで再現するのは非常に困難です。
パソコンなどの汎用コンピューターの場合は、裏で色々な処理をしながら(マウスを動かすだけでもその処理が割り込んだりもします)Scratchのプログラムを動かしているので、その時々でどうしても微妙な差が発生してしまいます。
時間が経つにつれてその差がだんだんと大きくなったり、または小さくなったりもします。
なので、1拍あたりにかかる時間は完全にコンピューターに任せることとして、テンポが一番遅れた楽器に他の楽器のタイミングを合わせるという手法を用いることで楽曲全体が同期するようなプログラムにします。
ピアノを例にとって説明すると、まずピアノの演奏がどこまで進んだかをカウントする変数「ピアノ」を用意して0で初期化しておきます。
このような変数は各楽器ごとに用意する必要があります。今回は3つの楽器用に「ピアノ」「ベース」「ドラム」の3つの変数をつくっています。
そして、8拍進むごとに「ピアノを1ずつ変える」ブロックを置いて「ピアノ」変数の値をカウントアップしていきます。
曲が8拍目まで進むと「ピアノ」変数の値は1になり、曲は全部で64拍あるので曲が終わるときには「ピアノ」変数の値は8になります。
ベースとドラムにも同じように演奏が8拍進むごとに変数を1ずつカウントアップするようにブロックを追加します。
次がもっとも重要なポイントであるそれぞれの楽器のタイミングを合わせる部分です。
変数「ピアノ」と「ベース」と「ドラム」の値が一致するまで待つというブロックをつくります。これは、各楽器の進み具合がもっとも遅い楽器が他の楽器に追いついてきたら次の処理に移るという意味でもあります。
このブロックを何か所にも追加するので「タイミング合わせ」定義ブロックにしてあります。
この「タイミング合わせ」定義ブロックを先ほどの「ピアノ」変数をカウントアップした直後に挿入していきます。
このようにすれば、パソコンの動作が急に重くなった時でも全体的にゆっくりした曲(テンポは無視する)にはなりますがタイミングがズレることはなくなります。
ここまでのポイントを押さえれば、複数の楽器のタイミングを合わせてバンド演奏するためのスクリプトを完成させることができると思います。
失敗しやすいポイント
「タイミング合わせ」定義ブロックは、必ず一定の拍数ごとに組み込むことです。
他の楽器は8拍ごとになっているにも関わらず、1つの楽器だけが6拍ごととかになっていると演奏が崩れてしまいますので注意しましょう。
応用編
今回応用編は特にありません。
まとめ
さいごに、今回の記事で説明した『複数の楽器のタイミングを合わせてバンド演奏するプログラミング』のポイントをまとめます。
- ポイント①:楽譜から楽器のごとのメロディーやリズムを読み取る(ドラムの楽譜の読み方に注意)
- ポイント②:読み取った音符を数値に置き換えてブロックに設定する
- ポイント③:それぞれの楽器のタイミングを合わせる(一定の拍ごとに変数をカウントアップ)
ネットの情報を見てみると「タイマー」ブロックを使ったタイミング合わせの方法をよく見かけますが、よほどの高性能パソコンか専用マシンでない限り、これをやるのは無理があると思います。
タイマーは時間を一定間隔で刻みますが、プログラム(JavaScript)の処理はそうはいかないんですよね。同じ処理でも書き方によっても処理速度は変わってきますので。
次回はリストを使ってすっきりしたプログラムに改良してみようと思います。
どうでしたか?上手く再現できたでしょうか?
他にも役に立つTips(ティップス)記事をたくさん書いてますので、ぜひ見てみてください。(記事のタイトルに「Tips」と書いていたり「Tips」タグを貼ってあります)
いつもドラムが必ず遅くなるんですが、ドラムのブロックだけは毎回楽器を選んでから音を鳴らしているためですかね?他の楽器は最初に楽器を選択すればいいだけですからね。楽器を選ぶということはMIDI音源をサーチして再生するという手間が増えるためかな~?と思ってます。