« MPLAB IDE V8.0インストール(後編) | メイン | 有機ELカラーグラフィック表示器μOLED-128(4) »

超Low-EndマイコンRS08を使おう - MC9RS08KA2で音楽を奏でる (14)


音楽を奏でるプログラムの解説(1)

 前回掲載したソース・コードを数回にわたって解説していきます。

楽譜構造体の宣言について

 音符、小節および楽譜を表現するデータ構造は、 先に説明したように二重の配列で構成しています。 ここでは、それぞれの構造について typedefによって型を宣言しています。

//==============================================================
//  楽譜構造体の宣言
//==============================================================
typedef struct {
    const byte                 length;  // 音符の長さ
    const byte                 period;  // MTIMMODに与える音程
}                              Sono;    // 音符構造体
typedef const Sono   * __paged SonoP;   // 音符へのポインタ

typedef SonoP                  Phrase;  // 小節の構造
typedef const Phrase * __paged PhraseP; // 小節へのポインタ


typedef PhraseP                Music;   // 楽譜の構造
typedef const Music  * __paged MusicP;  // 楽譜へのポインタ

 ほとんどすべての型に const__pagedの 指示子がついています。 constを付けると、 その配列はROMに配置されます。 また、__pagedを付けると、 ページング・ウィンドウを使用したメモリ・アクセスを行う プログラムを作成してくれます。

音程データの宣言について

 音程は、MTIMMODレジスタに与えられる値が そのまま記入されます。 これらの値を定数配列に直接書き込んでもかまいませんが、 値を直接書き込むといくつか問題が起こります。

  • 記入した数値が誤っていても気づきにくい。

    記入された数値がちょっと間違っていても 数として正しければコンパイラはエラーも警告も出しません。 したがって、人間が数値を一つ一つ検証しなくてはなりません。

  • 数値の書き換えに手間がかかる。

    楽譜データに記入した音程データは、 MTIMモジュールのクロック周波数250kHzを基にした 値です。 そのため、ほかのアプリケーションで違う周波数を使いたくなった場合には、 数値を書き直す必要があります。 数値が直接記入してあった場合、書き換えにかかる手間は膨大になります。

 このような理由から、 このプログラムでは音程データをいったん定数変数として宣言しておいて、 楽譜データでは、この定数変数を使用することとしました。

//==============================================================
//  音程データの宣言
//  MTIMモジュールのクロックとして周波数250kHz、周期4usecの
//  クロックを使用します。下限周波数は、489Hzです。
//==============================================================
const long P_base   = 250000L / 2;     // 250kHz
const byte P_H2     = (P_base/ 494)-1; //  494Hz
const byte P_D3s    = (P_base/ 622)-1; //  622Hz
const byte P_E3     = (P_base/ 659)-1; //  659Hz
const byte P_F3s    = (P_base/ 740)-1; //  740Hz
const byte P_G3s    = (P_base/ 831)-1; //  831Hz
const byte P_A3     = (P_base/ 880)-1; //  880Hz
const byte P_H3     = (P_base/ 988)-1; //  988Hz
const byte P_C4s    = (P_base/1109)-1; // 1109Hz
const byte P_D4s    = (P_base/1245)-1; // 1245Hz
const byte P_E4     = (P_base/1319)-1; // 1319Hz
const byte P_F4s    = (P_base/1480)-1; // 1480Hz
const byte P_G4s    = (P_base/1661)-1; // 1661Hz

 変数名は、下のようなルールに従って命名されています。

音程データの命名ルール

 これらの定数変数は、 コンパイラによってプログラムの中に直接埋め込まれてしまうので、 「変数」という名前は付いていますが、 どこかのアドレスに配置されるわけではありません。

楽譜データについて

 楽譜データのサンプルとして、 ショパンによる「別れの曲」を用意しました。

#pragma CONST_SEG __PAGED_SEG PAGED_ROM
//==============================================================
//  楽譜データ
//  ショパン「別れの曲」
//==============================================================
const byte TEMPO    =  9;               // 曲のテンポ

const Sono phrase_adieu1[] = {
    8*TEMPO, P_H2,
    8*TEMPO, P_E3,  // 1
    4*TEMPO, P_D3s,
    4*TEMPO, P_E3,
    0,0
};

const Sono phrase_adieu2[] = {
   20*TEMPO, P_F3s, // 2;10
    4*TEMPO, P_G3s,
    4*TEMPO, P_G3s,
    4*TEMPO, P_F3s,
   20*TEMPO, P_G3s, // 3;11
   :
const Sono phrase_adieu3[] = {
   :
const Sono phrase_adieu4[] = {
   :
const Sono phrase_adieu5[] = {
   :
   16*TEMPO, P_G3s,  // 20
    8*TEMPO, P_G3s,
   0,0
};

const Phrase music_adieu[] = {
   phrase_adieu1,
   phrase_adieu2,
   phrase_adieu3,
   phrase_adieu2,
   phrase_adieu4,
   phrase_adieu5,
   (Phrase)0
};

 上のプログラムは、一部省略しています。 冒頭でTEMPOという定数変数が定義されていますが、 この変数は曲のテンポを決めている変数です。 楽譜データのすべての音の長さデータは、 この倍数になっているので、 TEMPOの値を変えるだけで 曲全体のテンポを調整することができます。 この楽譜データでは、 8分音符を8*TEMPOと定義しています。

 原曲は、一分間に8分音符が100個並ぶテンポなので、 TEMPOに与えるべき値は、

   60sec÷100÷8msec÷8 = 9.375

と計算されます。 ここから、TEMPOは9と定義しています。

 曲中、小節phrase_adieu2は二回使われています。 このように、曲中に繰り返しなどがあった場合には、 二段構成の配列にしておくと定数配列容量を減らすことができるという メリットもあります。


 次回もプログラムの解説を続けます。

田中範明

カテゴリ:

トラックバック

このエントリーのトラックバックURL:
http://www.eleki-jack.com/mt/mt-tb.cgi/730

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

カテゴリ

会社案内
情報セキュリティおよび個人情報の取り扱いについて

コメントとトラックバックは、spamを予防するために、編集担当が公開の作業をするまで非公開になっています。
コメントはそれぞれ投稿した人のものです。

Powered by
Movable Type 4.1