SHIROのIchigoJam日記

マイコン「IchigoJam」(イチゴジャム)の電子工作とプログラミングをメインに

ジングルベルをフルコーラスでPLAY

★この記事は「IchigoJam Advent Calendar 2024」に参加しています。

クリスマスにお馴染みの曲「ジングルベル」を、IchigoJamのPLAY命令で奏でてみます。

まずはそのまま演奏

とりあえず普通にプログラムを書くと、

10 PLAY "CAGFC2R2 CAGFD2R2 DA+GFE2R2 <CC>A+GA2R2 CAGFC2R2 CAGFD2R2 DA+GF<CCCC DC>A+GFR<CR >AAARAAAR A<C>F4.G8A2R2 A+A+A+A+A+AAA AGGAGR<CR >AAARAAAR A<C>F4.G8A2R2 A+A+A+A+A+AAA <CC>A+GF2R2"


190文字なので1行に何とか入りますが、何しろ長いので打ちづらいです。
もっと長い曲だったら1行(250文字)に入らないでしょう。
ですので、フレーズ(4小節)で区切ってPLAYしてみます。

10 PLAY "CAGFC2R2 CAGFD2R2":WAIT 470
20 PLAY "DA+GFE2R2 <CC>A+GA2R2":WAIT 470
30 PLAY "CAGFC2R2 CAGFD2R2":WAIT 470
40 PLAY "DA+GF<CCCC DC>A+GFR<CR":WAIT 470
50 PLAY "AAARAAAR A<C>F4.G8A2R2":WAIT 470
60 PLAY "A+A+A+A+A+AAA AGGAGR<CR":WAIT 470
70 PLAY "AAARAAAR A<C>F4.G8A2R2":WAIT 470
80 PLAY "A+A+A+A+A+AAA <CC>A+GF2R2"

PLAY命令は実行するとすぐ次へ行ってしまうので、WAITを入れないと演奏する前に次の行へ行ってしまって、曲になりません。
標準だとテンポ120(T120、1秒間に2拍)なので、4小節(16拍)だと8秒(WAIT 480)待てばよいです。
が、そのまま「WAIT 480」だとIchigoJam環境によっては間延びするので、「WAIT 470」にしています。
正確に前のフレーズ演奏が終わってから次へ行くには、

10 PLAY "CAGFC2R2 CAGFD2R2"
15 IF SOUND() CONT
20 PLAY "DA+GFE2R2 <CC>A+GA2R2"
25 IF SOUND() CONT
30 PLAY "CAGFC2R2 CAGFD2R2"
35 IF SOUND() CONT
40 PLAY "DA+GF<CCCC DC>A+GFR<CR"
45 IF SOUND() CONT
50 PLAY "AAARAAAR A<C>F4.G8A2R2"
55 IF SOUND() CONT
60 PLAY "A+A+A+A+A+AAA AGGAGR<CR"
65 IF SOUND() CONT
70 PLAY "AAARAAAR A<C>F4.G8A2R2"
75 IF SOUND() CONT
80 PLAY "A+A+A+A+A+AAA <CC>A+GF2R2"

と、SOUND関数を使って、演奏終了まで待って次へ行くとよいです。
が、WAITで待つ方が手軽で、プログラムが短くて済みます。

フレーズを使って短縮、文字列指定

フレーズ毎に区切ってみると、10行と30行、50行と70行のフレーズは全く同じなのがわかります。
音楽の曲はこういう構成がよくあります。
この「ジングルベル」なら、フレーズが「A→B→A→C→D→E→D→F」の構成になっていて、実際のフレーズは6種類しかありません。
せっかくなので短縮・簡略化したい所です。

ここで、文字変数をうまく使ってみます。
IchigoJam BASICでは、文字列を変数に代入できます。

A="ABC"

この時、変数Aには何が入るかと言うと、文字列「ABC」が入っているメモリのアドレスが入ります。
(このようにメモリアドレスが入った変数を「ポインタ」と言います)
そして、PLAY命令も文字列だけでなく、文字変数(ポインタ)で音階を指定できます。例えば、

10 A="CDE"
20 PLAY A

で、「PLAY "CDE"」と同じく「ドレミ」が鳴ります。
この文字変数を使って、ジングルベルを演奏してみます。

10 A="CAGFC2R2 CAGFD2R2"
20 B="DA+GFE2R2 <CC>A+GA2R2"
30 C="DA+GF<CCCC DC>A+GFR<CR"
40 D="AAARAAAR A<C>F4.G8A2R2"
50 E="A+A+A+A+A+AAA AGGAGR<CR"
60 F="A+A+A+A+A+AAA <CC>A+GF2R2"
70 PLAY A:WAIT 470
80 PLAY B:WAIT 470
90 PLAY A:WAIT 470
100 PLAY C:WAIT 470
110 PLAY D:WAIT 470
120 PLAY E:WAIT 470
130 PLAY D:WAIT 470
140 PLAY F

MML(音符)を打つのが6フレーズ分で済みますし、演奏部分も順番がわかりやすいです。
が、同じような「PLAY」や「WAIT」を何度も打つのが面倒です。

配列変数を使う

実は文字変数(ポインタ)は配列変数でも使えます。
通常変数を配列変数に置き換えると、

10 [0]="CAGFC2R2 CAGFD2R2"
20 [1]="DA+GFE2R2 <CC>A+GA2R2"
30 [2]="DA+GF<CCCC DC>A+GFR<CR"
40 [3]="AAARAAAR A<C>F4.G8A2R2"
50 [4]="A+A+A+A+A+AAA AGGAGR<CR"
60 [5]="A+A+A+A+A+AAA <CC>A+GF2R2"
70 PLAY [0]:WAIT 470
80 PLAY [1]:WAIT 470
90 PLAY [0]:WAIT 470
100 PLAY [2]:WAIT 470
110 PLAY [3]:WAIT 470
120 PLAY [4]:WAIT 470
130 PLAY [3]:WAIT 470
140 PLAY [5]

MMLを配列変数8個に設定すれば、演奏部分を簡略化できます。

10 [0]="CAGFC2R2 CAGFD2R2"
20 [1]="DA+GFE2R2 <CC>A+GA2R2"
30 [2]=[0]
40 [3]="DA+GF<CCCC DC>A+GFR<CR"
50 [4]="AAARAAAR A<C>F4.G8A2R2"
60 [5]="A+A+A+A+A+AAA AGGAGR<CR"
70 [6]=[4]
80 [7]="A+A+A+A+A+AAA <CC>A+GF2R2"
90 FOR N=0 TO 7
100 PLAY [N]:WAIT 470
110 NEXT

これですっきりした演奏プログラムになりました。

WAITの代わりにSOUND関数を使えば、

10 [0]="CAGFC2R2 CAGFD2R2"
20 [1]="DA+GFE2R2 <CC>A+GA2R2"
30 [2]=[0]
40 [3]="DA+GF<CCCC DC>A+GFR<CR"
50 [4]="AAARAAAR A<C>F4.G8A2R2"
60 [5]="A+A+A+A+A+AAA AGGAGR<CR"
70 [6]=[4]
80 [7]="A+A+A+A+A+AAA <CC>A+GF2R2"
90 FOR N=0 TO 7
100 PLAY [N]
110 IF SOUND() CONT
120 NEXT

こうすると、各フレーズの長さが違う場合や、演奏テンポを変えた場合にも対応できます。

10 [0]="T140CAGFC2R2 CAGFD2R2"
20 [1]="T140DA+GFE2R2 <CC>A+GA2R2"
30 [2]=[0]
40 [3]="T140DA+GF<CCCC DC>A+GFR<CR"
50 [4]="T140AAARAAAR A<C>F4.G8A2R2"
60 [5]="T140A+A+A+A+A+AAA AGGAGR<CR"
70 [6]=[4]
80 [7]="T140A+A+A+A+A+AAA <CC>A+GF2R2"
90 FOR N=0 TO 7
100 PLAY [N]
110 IF SOUND() CONT
120 NEXT

テンポ140(T140)にして速くしてみました。
この方がジングルベルらしいです(^_^)