PIC AVR 工作室->TopPage->実験くん->マイコンでFM音源

マイコンでFM音源の再生

ハードウェアPWMを内蔵したマイコン…今回はAT-MEGA48シリーズ…を使って、マイコン1個で FM音源機能を実現してしまおうという実験です。

FM音源とは

矩形波出力とFM音源

マイコンを使って(音階を持った)音楽を鳴らす方法として、比較的簡単に実現できて応用例も多いのは PWM機能を用いた矩形波出力でしょう。

矩形波出力と言ってもピンと来ない人もいらっしゃると思いますが、初代ファミコンの音などを思い浮かべて いただければ「あぁ、ああいう音ね」とご理解いただけるのではないでしょうか?あの音は、ICからスピーカーに 対してONとOFFの信号を連続して送ることで振動を発生し、スピーカーの振動が空気を震わせ、音として 聞こえるというわけです。

PWM内蔵のマイコンであれば、音程に相当する数値を内蔵PWMに指定するだけで自動的にONとOFFの信号を出すことが出来、 しかも一旦周波数を設定しておけば手放しで音程を出しつづけてくれるので、ソフトウェア側の処理負荷が軽くてお手軽です。 プログラム的にはPWMの発振周波数を20Hz~20000Hz程度に設定するだけで音程が表現できます。

一方この矩形波出力は「音色」がいつも一緒。音色を選ぶことが出来ません。ICの出力ピンをオン/オフに 切り替えるながら長方形の波形を出力し、その長方形の長さで音程を、長方形の高さで音量を制御する簡便な方式です。 ファミコンの音楽はどれも同じ音色しか出なかったのは、この矩形波の宿命というやつです。

つまり、矩形波出力では簡単な音楽を鳴らすことはできても本格的な音楽を鳴らすには表現力が乏しいということです。 ちょっとしたオルゴール的な用途にしか使えません。「音楽の演奏」というには矩形波ではちょっと役不足です。

音の3要素とFM音源

「音」は3つの要素から構成さます。「音量」「音程」「音色」がそれに相当します。

矩形波出力方式ではこのうち前の2者まではなんとか作り出すことができるのですが、「音色」はコントロールすることが出来ません。 FM音源というのは、コンピューター内部でこの「音色」まで造り出す音源です。

FM音源は、YMOはじめテクノ系音楽で用いられるようになり、伝説のキーボードシンセ=YAMAHAのDX-7 などたくさんのシンセサイザー機器に内蔵され、80年代にはPCやゲーム機にも効果音生成用に内蔵された結果 「ゲームミュージック」なる新たなサブカルチャーを作り出したりした、一時代を築いた音源です。

現在は、音源といえばサンプリング音源(PCM)が主流になってしまった感がありますが、今でも携帯電話の着メロ用などで 相変わらず使われつづけています。サンプリング音源の代表といえばCD、つまりコンパクトディスク。 音声を時系列に細分して数値化し、それをコード化してROM上に格納しておき、再生時には このデータを順にアナログ変換して出力する方法です。この方法はCDを見るとお判りのとおり大量のデータが必要になります。 1時間で約650MB程度でしょうか。

一方FM音源は再生時に「計算式」を元に音色を作り出しながら鳴らす方式なので、データ量の点でははるかに少なくて済むとう メリットがあります。それゆえに携帯電話にでもサクッと入ってしまうわけです。

そしてデータ量が少なくても大丈夫なので、容量の小さいマイコン程度でも比較的簡単に実現が可能かと思います。

「音色」について

音色って、一体なんなのでしょうか?

音色は、一言で言うと複数の波を重ね合わせたものです。

楽器や人間の声などの音色は、ベースになる波の周波数に対して、その整数倍となる周波数の波=「倍音成分」を重ね合わせることで 得ることが出来ます。

例えば、ピアノの鍵盤で「ド」のキーを叩くとおよそ262Hzの波形(基音)に加え、その整数倍の波形(倍音)が 出力されることになります。「ド」の場合、倍音成分の周波数は524Hz、768Hz、1048Hz、1310Hz… といった具合です(ちょっと不正確な値ですが)。

人間の耳はこの基音と倍音を足し合わせて出来上がった波形を「音色を持った一つの音」として聞く事ができるわけです。 楽器によって異なる音色は、この倍音成分の量や比率に起因します。2倍音が少なめだったり3倍音が多めだったり、 4倍音が少なめだったり…という違いが個々の楽器によって変わるわけです。

文字だと解り難いと思うので、少し可視化してみます。

先ほどの図です。これはFM音源生成の計算式を元にコンピューター画面上で波形をシミュレートしてみたグラフの例です。 音の1波形分に相当します。

このフニャフニャした波形が、基音と倍音を足し合わせて出来た一つの「音」の波形というわけです。

出力された波形は、上述のとおり「基音」と「倍音」を足し合わせたものなので、こんなイメージです↓。

なので、この波形を逆にスペクトル分析してみると、およそ以下のように基音と倍音が一定周期で現れることになります。 (グラフは正確ではありません。イメージです)

赤い線は基音成分、青い線は倍音成分です。基音成分が1本あり、その右側に倍音成分がたくさん並んでいるのが お判りいただけるかと思います。倍音成分は基音の周波数に対して整数倍の周波数(2倍、3倍、4倍…と続いていく)になっています。

これら赤い線、青い線の一つ一つは独立した正弦波ですが、これらのたくさんの正弦波を足し合わせたものが「音色を持った一つの音」として 聞こえるというわけです。この青い線が、部分的に長かったり短かったりすることで、色々な音色になって聞こえることになります。

こんな風に書くと、「FM音源ってちょっと難しそう」とか「FM音源ってこうやって正弦波を足し合わせる処理やるの?」とか思われる かもしれませんが、そうではありません。実際の動作原理、計算方法は驚くほど簡単です。このFM音源をマイコンを使って ソフトウェアで実際に鳴らしてみちゃおうというのがこのページの主旨です。

FM音源はYAMAHAがライセンスを持っているらしいのですが、ライセンスなどに関する詳しいことは wikipediaなどに載っているので省きます。 まぁ、商用に作るわけではなく自宅でサクッと実験する範囲ならライセンスも関係ないので、実験材料としては面白いのではないでしょうか。

当面のゴールについて

目指すところ

とにかく周波数変調を使って音を出すことだけを目指します。

ひとまず実験レベルってことでやってみたので、まずは簡単に音を鳴らすことを最優先とし、応用範囲については劣後させました。 というわけでまずは実際に音を出してみたのでその成果を先に挙げておきます。この音を出すことをこのページのゴールとします。

ひとまずキャリアとモジュレータの周波数比をそれぞれ1~7に設定し、変調の度合いを中くらいにしたものを録音してみました。 周波数比とはナンゾヤ?等といったお話については後述しますが、周波数比や変調度合い(モジュレータの出力レベル)は 自由に制御できるようにしました。

見送るところ

色んなアルゴリズムとか、エンベロープとか、LFOなどは見送ります。(用語の説明は後ほど)

多々あるアルゴリズム(キャリアとモジュレータの組み合わせ方…より複雑な音色を作れる)や エンベロープパターン(ギターやピアノの音が徐々に減衰していく等の表現)については組み込めてません。 キャリア=1個、モジュレータ=1個の最も単純なアルゴリズムだけとし、この周波数比と変調レベルを 変えながら音声合成します。倍音成分(つまり音質)を自由に変化させられるということを目指しました。和音もまだ出来ません。

またエンベロープとも絡みますが、トレモロやビブラートといったLFO機能なども未登載です。

あと、今回は4つの音程…「ド」「ミ」「ソ」「1オクターブ上のド」の4音を連続していますが、プログラムのロジック中に そのメロディー自体を組み込んであるため、今のままではそれ以外のメロディーは出せません。 まぁ、ここまで実現できていれば、この後の拡張は比較的簡単に行うことができるでしょう。

なにしろ、受動的に動作する「音源機能」とするか、それとも譜面(メロディー)データを内蔵して能動的に音を発する 「オルゴール的」とするかによって設計の方向性が大きく分かれてしまうので、その一歩手前までに留めました。

FM音源の原理

「基音+倍音」によって「音色」を造り出すということを上記で触れました。では、マイコンで延々と続く倍音を計算して 基音に重ね合わせていくのがFM音源かというと、そうではありません。そもそも倍音成分は有限個というわけではないので、 延々と重ね合わせるためには、無限大の処理速度が必要になってしまいますし。

そこで周波数変調(FM)というものを使うわけです。

FM音源とFMラジオ? 周波数変調について

残念ながら私は周波数変調についての専門家でもなく、かつ数学なんて「じんましん」がでて痒くて痒くてわしゃかーなわんので、 あまり正確な説明にならないかもしれませんが、私の頭の中にある周波数変調についてザックリまとめてみたいと思います。

FMといって一番最初に思い浮かべるのはなんと言ってもFMラジオの「FM」という言葉かと思います。そう。 FM音源の「FM」はFMラジオの「FM」と同じです。(同じというのは、変調の方式が一緒ということであって、 用途が同じという意味ではありません)

FM放送の電波

解り易いように、FMラジオの電波を可視化してみたいと思います。以下のプログラムを実行すると、FMラジオの電波として 送信されている波形のイメージが表示されます。…この時代にBASIC言語というのもイマイチですが、 この手の短いプログラムには使い勝手がいいのでご勘弁…

   10 CLS 3
   20 LINE (100,100)-(100,300),7
   30 LINE (100,200)-(450,200),7
   40 FOR R=0 TO 3.142*40 STEP 0.001
   50 Y = - SIN(R + 8*SIN(0.1*R)) * 100 + 200
   60 X = R /3.142 /40 * 300 + 100
   70 PSET (X,Y)
   80 NEXT

短いプログラムですが、こんな短いプログラムの中に周波数変調の処理が組み込めてしまっているわけです。しかもそのメインとなる 部分はこの中のたった1行。

   50 Y = - SIN(R + 8*SIN(0.1*R)) * 100 + 200

ここだけ。もっというと、Y = SIN(R + 8*SIN(0.1*R)) これだけ。

FM放送の電波では、この図ように波が密なところ(周波数が高い)と疎のところ(周波数が低い)を作って音声を送信しています。 その密度によって信号の高低を表現するのがFMラジオで使われている「周波数変調」という方式です。密ならHIGH、疎ならLOWなどと 決めておけば、受信側ではその周波数の高低から元の信号のHIGH、LOWを再生することができます。

周波数変調のキーポイントはこのプログラム中に隠されています。それは、sin関数の引数内にもう一つ入れ子構造になった sin関数です。

この内側のsin関数が無ければ、外側のsin関数は単純に正弦波を出力することになりますよね? 引数にsin関数を加えていること、 これが周波数変調のキーとなる部分です。内側のsin関数と外側のsin関数の各引数を見ていただくと、 その基本周波数を決めている変数「R」の係数が違っています。内側のsin関数は周波数が0.1倍されているのがお判り いただけるかと思います。外のsin関数よりも内側のsin関数の方がゆっくりとした波になっています。(この場合なら0.1倍…つまり10倍ゆっくり)

なお、この数値は視覚的に特徴が表れやすいように設定した数値なので、実際のFM放送でこの定数が 用いられているわけではありません。FM放送の周波数では外側のsin関数に78Mhzとか79.5Mhzなどを用い、 内側のsin関数の替わりに音声信号(20~20Khz程度)を使っているわけです。0.1倍どころではありませんが、 とにかく外側のSIN関数より内側のsin関数の周期の方がゆっくりした周波数だということがFM放送の方式のポイントです。

ラジオ放送の電波にFM(周波数変調)を用いるのは、上の図のように常に振幅が一定にできることがメリットになるからです。 AMラジオの場合、信号の強弱がそのまま音声の強弱になるわけですが、受信した電波の強弱は本当に元の音声信号の強弱なのか、 それとも電波の受信状態が悪いのか判断が付きません。FMの場合、振幅ではなく周波数の間隔の変化が音声信号の強弱となるので、 このような受信状態に起因するノイズや減衰を受けずに済む訳です。

FM音源の周波数変調

FM音源の周波数変調も、考え方は一緒です。大きく違うのは、さっきのプログラムで0.1倍となっていた係数の所です。

FM音源の場合、この係数のところに「1以上の整数」が用いられます。つまり外側のsin関数より内側のsin関数の方が 周期が短いということになります。しかも整数倍です。実際にサンプルプログラムを動かして見ます。

   10 CLS 3
   20 LINE (100,100)-(100,300),7
   30 LINE (100,200)-(450,200),7
   40 FOR R=0 TO 3.142*2 STEP 0.001
   50 Y = - SIN(R + 0.5*SIN(3*R)) * 100 + 200
   60 X = R /3.142 /2 * 300 + 100
   70 PSET (X,Y)
   80 NEXT

すると冒頭の図になるわけですね。内側の「R」の係数部分を見ると今度は「3」になっています。外側のsin関数と 内側のsin関数の周波数の比を設定しているところですが、「周波数比=3倍」を設定しているということを意味しています。

このようにすると、FM放送の変調方式とFM音源の処理方式は同じ事がわかります。もちろん、その目的は異なりますが。 計算式中の定数がちょっと違うだけなのですが、グラフ上では結構な違いになって現れて面白いところです。

さて、どうしてsin関数の内側にもう一個sin関数を入れると「倍音成分」が乗るのかについては、 数学の苦手な私には理論立てた説明がし切れません。詳しく知りたいと言う方は、 wikipediaなどを別途ご覧ください。 フーリエ変換すると、どうやら整数比の周波数を持ったsin関数の集合体になるっぽいです。

後もう一つ。なぜ音色は整数比の正弦波の集まりで構成されるのか…。詳説はしませんが、これは「定常波」とか「共鳴」 というキーワードで調べて頂くとピンと来るかもしれません。例えばギターの弦に生じる定常波…それぞれの波が必然的に整数倍となるはずかと。 ご興味のある方は是非検索してみてください。(1/2倍波なんていうのもあるんですが、その話は省きます)

数式について補足

先ほどのBISICプログラム中の数式の意味を、もう少し可視化して見えるように動画を作ってみました。 通常のsin関数の読み出しと、周波数変調でのsin関数の読み出しという観点で比較してみます。

上の図は通常のsin関数の読み出し方。下の図は周波数変調を掛けた場合の読み出し方です。

縦の線がsin関数を読み出す引数だと思ってください。sin関数の引数内に入れ子状態のsin関数があるので、 このとおり行ったり戻ったりしながら読み出すことになり、ふにゃふにゃした曲線が読み出されることになります。

要は、マイコンにこれと同じ処理をさせればFM音源の音声合成処理ができちゃうわけです。

原理のまとめ

上記のとおり、周波数変調の原理について図と動画にまとめてみました。

周波数変調は、sin関数の引数にsin関数を加算することで元の波形に変調を掛ける方式で、特にFM音源の場合は 内側のsin関数の周波数を外側の整数倍にすることで行う、ということができるかと思います。 実際に今回MEGA48用に作ったファームウェアもこの計算方式そのままです。

まぁ、本格的なFM音源となると、内側のsin関数が1個だけというわけではなく2個、3個…と使われていたり、さらには sin関数の中のsin関数の中にさらにsin関数が…と直列的に変調を掛けて、物凄く複雑な変調を掛けることも行われます。 後述しますが、こういうsin関数同士の組み合わせ方を「アルゴリズム」と呼びます。楽器のタイプによってマッチするアルゴリズムを 選んだりして音作りをします。

また、一番外側のsin関数を「キャリア」、それより内側のsin関数をすべて「モジュレータ」といい、これらの「キャリア」と 「モジュレータ」をあわせて「オペレータ」といいます。(キャリアもモジュレータも、単機能としてはsin関数…つまり正弦波を 出力するだけという点では変わりなく、実際にFM音源のicの中ではどちらもオペレータという同一機能として組み込まれています)

言い換えると、アルゴリズムはオペレータの組み合わせ方法と同義です。

今回は音を出すことを最優先にするので、複雑なアルゴリズムは用いず、キャリア1個、モジュレータ1個という最も簡単な パターンだけに絞ります。

(後編に続きます)