サウンドを鳴らす@


ワンダースワンの音源
WonderSwan本体には、4チャンネルのPCM音源が搭載されています。それぞれのチャンネルには別の音源を設定でき、それらが合成された音が出力されます。
サウンドを鳴らすために必要なデータは波形データ、音量データ、使用チャンネルなどです。 波形データは4bit x 32step、16バイトのデータで表し、チャンネル毎に別な波形を設定できます。 また、チャンネル1以外の3つのチャンネルは、基本音源機能のほか、それぞれ個別の付加機能を持っています。

チャンネル別の付加機能
チャンネル1(なし)-----
チャンネル2ボイス8bitのサンプリングデータを直接出力する(切り替え)
WAVファイルなどのデータを変換して使用できます。
チャンネル3スイープ周波数を時間とともに一定の割合で変化させる機能です。
面白い効果音を設定できます。
チャンネル4ノイズ8種類の中から選択したタイプのノイズを発生させる(切り替え)

サウンドを鳴らす方法には@サウンド制御BIOSを使う、A付属のサウンドインダイレクトライブラリ (sound.il)を使うという2つの方法があります。@はBIOSを直接制御するため、実行ファイルのみ で動作しますが、Aは別に用意されたドライバを本体に転送して動作させます。

サウンド制御BIOSを使う

サウンド制御BIOSを使ってサウンドを出力する手順は次のようになります。

sound_init();サウンドBIOS初期化。

サウンドを全てオフにし、波形テーブルも0クリアします

sound_set_output( 0x01 );

bit 内容 説明
0 本体出力設定 本体モノラル・スピーカーからの出力可否を設定します。1のとき出力します。
2-1 本体出力スケール設定 サウンド出力データ11bit中、本体モノラル・スピーカーからの出力に用いる8bitの領域を選択します。音量の小さいサウンドデータを、大きなボリュームで出力する際には小さな値を、 音量の大きいサウンドデータを、小さなボリュームで出力する際には大きな値を設定します。

00 D0〜D7を出力
01 D1〜D8を出力
10 D2〜D9を出力
11 D3〜D10を出力

3 外部出力設定 外部ヘッドフォン・ステレオからの出力可否を設定します。1のとき出力します。
4-7 予約 システムで予約されています。必ず0を設定してください。

サウンドの出力先、本体出力時のスケーリングを設定します。

この例では本体スピーカ出力のみ設定しています。


unsigned char wave[] = {
  0xa8, 0xdc, 0xee, 0xef, 0xde, 0xbc, 0x9a, 0x89,
  0x67, 0x56, 0x34, 0x12, 0x01, 0x11, 0x32, 0x75,
};
……
……
    sound_set_wave( 0, wave );

       0       8       16       24       step
     F □□□□□□■□□□□□□□□□□□□□□□□□□□□□□□□□
     E □□□□■■□■■□□□□□□□□□□□□□□□□□□□□□□□
     D □□□■□□□□□■□□□□□□□□□□□□□□□□□□□□□□
     C □□■□□□□□□□■□□□□□□□□□□□□□□□□□□□□□
     B □□□□□□□□□□□■□□□□□□□□□□□□□□□□□□□□
     A □■□□□□□□□□□□■□□□□□□□□□□□□□□□□□□□
     9 □□□□□□□□□□□□□■■□□□□□□□□□□□□□□□□□
     8 ■□□□□□□□□□□□□□□■□□□□□□□□□□□□□□□□
     7 □□□□□□□□□□□□□□□□■□□□□□□□□□□□□□□■
     6 □□□□□□□□□□□□□□□□□■■□□□□□□□□□□□□□
     5 □□□□□□□□□□□□□□□□□□□■□□□□□□□□□□■□
     4 □□□□□□□□□□□□□□□□□□□□■□□□□□□□□□□□
     3 □□□□□□□□□□□□□□□□□□□□□■□□□□□□□■□□
     2 □□□□□□□□□□□□□□□□□□□□□□■□□□□□■□□□
     1 □□□□□□□□□□□□□□□□□□□□□□□■■□■■□□□□
     0 □□□□□□□□□□□□□□□□□□□□□□□□□■□□□□□□
   vol 8ACDEEFEEDCBA9987665432110112357 
波形データの設定を行います。

波形データを設定するチャンネル(0〜3(チャンネル1が0、チャンネル2が1、…))と、 設定する波形データの先頭アドレスを指定します。

波形データは、4bitx32step分を2step/1byteにパックし、16byteとした形式です。 各byteの下位4bitに偶数step、上位4bitに奇数stepのデータを格納します

左図ののような波形データを、例のように配列に初期設定し、それを指定します。

sound_set_volume( 0, 0x55 ); サウンド・チャンネルの出力音量を設定します。 音量を設定するチャンネル(0〜3(チャンネル1が0、チャンネル2が1、…))と、 左右の出力音量をそれぞれ4bitで指定します。
上位4bitが左チャンネル、下位4bitが右チャンネルの出力音量となります。

チャンネル2をボイス・モードで利用している際には、8bitを全て用いてボイス・データを与えます。

pitch=-(3072000L/(32*f)-2048);
sound_set_pitch( 0, pitch );



出力周波数 f は以下の式によって求められます。

f = 3.072x10の6乗 ÷ ((2048 - N) x 32 ) Hz

これを周波数fを与えて、Nを求める式に変換すると

N = -( 3072000L ÷ ( 32 * f ) - 2048 );

となります。

サウンド・チャンネル1〜4の出力周波数を設定します。
周波数を設定するチャンネル(0〜3(チャンネル1が0、チャンネル2が1、…))と、 下位11bitにSOUND_SET_WAVEで設定する32stepの波形の周波数を指定します。
チャンネル3にスウィープ・モードが設定されている場合、この機能によって設定 される周波数がスウィープ開始時の初期周波数となります。
sound_set_channel( 0x0001 );

bit 内容
0 チャンネル1の出力を設定します。1のとき出力します。
1 チャンネル2の出力を設定します。1のとき出力します。
チャンネル2がボイス・モードの場合、このビットの指定は無視されて必ず出力します。
2 チャンネル3の出力を設定します。1のとき出力します。
3 チャンネル4の出力を設定します。1のとき出力します。
4 システムで予約されています。必ず0を設定してください。
5 チャンネル2のボイス・モードを設定します。1のときボイス・モードになります。
6 チャンネル3のスウィープ機能を設定します。1のとき有効になります。
7 チャンネル4のノイズ・モードを設定します。1のときノイズ・モードになります。

チャンネルのモードを設定し、出力します。

この例では単に、チャンネル1の出力を指定しています。
これによりサウンドが発生され、 以後別のデータが出力されるまで、鳴り続けます。



周波数440Hz(ドの音)を出力するためのプログラムは次のようになります。

#include <sys/bios.h>

unsigned char wave[] = {
  0xa8, 0xdc, 0xee, 0xef, 0xde, 0xbc, 0x9a, 0x89, 波形データ
  0x67, 0x56, 0x34, 0x12, 0x01, 0x11, 0x32, 0x75,
};

void main()
{
   int pitch,f = 440;               周波数440Hz

    sound_init();                 @サウンド初期化
    sound_set_output( 0x01 );           Aサウンドの出力先設定(本体、外部)
    sound_set_wave( 0, wave );           B波形データの設定
    sound_set_volume( 0, 0x55 );          Cボューム(音量)の設定
    pitch=-(3072000L/(32*f)-2048);          周波数値を計算
    sound_set_pitch( 0, pitch );          D出力周波数を設定
    sound_set_channel( 0x0001 );          Eチャンネルのモードを設定し、出力

    key_wait();                  キー入力待ち
    sound_set_channel( 0x0000 );          サウンド出力をオフ
}


キー入力で周波数を変化させる
UP,DOWNキーで出力周波数を変化させます。

画面に周波数値を表示させています。
STARTキーで終了します。

#include <sys/bios.h>

unsigned char wave[] = {
  0xa8, 0xdc, 0xee, 0xef, 0xde, 0xbc, 0x9a, 0x89,
  0x67, 0x56, 0x34, 0x12, 0x01, 0x11, 0x32, 0x75,
};

void main()
{
   int pitch,f = 440;
   int k;

    text_screen_init();
    sound_init();
    sound_set_output( 0x01 );
    sound_set_wave( 0, wave );
    sound_set_volume( 0, 0x55 );
    sound_set_channel( 0x0001 );
    
    while( (k=key_wait()) != KEY_START ){
        switch(k){
            case KEY_UP1   : f++; break;
            case KEY_DOWN1 : f--; break;
        }  
        text_put_numeric( 1, 1, 4, 0, f );
        pitch=-(3072000L/(32*f)-2048);
        sound_set_pitch( 0, pitch );
    }
    sound_set_channel( 0x0000 );
}


スイープ(周波数連続変化)を使う

スイープはチャンネル3のみに割り当てられたの機能で、 指定するステップ・タイム毎に出力周波数に、設定した値連続的に加えていくものです。
効果音につかえそうな「ヒュ〜ゥゥン」といったサウンドを出力できます。
スイープの設定には sound_set_sweep関数を使います。
sound_set_sweep(スイープ値 , ステップタイム )
スイープ値  は 128(0x80)から+127(0x7F)の範囲
ステップタイムは 0〜31の範囲で  出力周波数が変化する時間間隔 T = 2.667 x (N + 1) ms のNで表されます。

この例題ではUP,DOWNキー単独で周波数変化、Aキーを押しながらでスイープ値変化、 Bキーを押しながらでステップタイム値を、それぞれ変化させます。STARTキーで終了します。

#include <sys/bios.h>

unsigned char wave[] = {
  0xa8, 0xdc, 0xee, 0xef, 0xde, 0xbc, 0x9a, 0x89,
  0x67, 0x56, 0x34, 0x12, 0x01, 0x11, 0x32, 0x75,
};

void main()
{
   int pitch,f = 440,sw = 0, st=1;
   int k;

    text_screen_init();
                       /*1234567890123456789012345*/
    text_put_string(1,1,"frequency  sweep  step");
    sound_init();
    sound_set_output( 0x01 );
    sound_set_wave( 2, wave );    /* channel3 */
    sound_set_volume( 2, 0x55 );
    sound_set_channel( 0x44 );    /* channel3 sweep on */
    
    while( (k=key_press_check()) != KEY_START ){
        switch(k){
            case KEY_UP1           : f++;                 break;
            case KEY_DOWN1         : f=f>1?f-1:1;         break;
            case KEY_A | KEY_UP1   : sw=sw<127?sw+1:127;  break;
            case KEY_A | KEY_DOWN1 : sw=sw>-128?sw-1:-128;break;
            case KEY_B | KEY_UP1   : st=st<31?st+1:31;    break;
            case KEY_B | KEY_DOWN1 : st=st>0?st-1:0;      break;
        }  
        if( k != 0 ){
            text_put_numeric( 3, 3, 4, 0, f );
            text_put_numeric(13, 3, 4, NUM_SIGNED, sw );
            text_put_numeric( 19, 3, 4, 0, st );
            text_put_numeric( 23, 3, 4, 0, 2.667*(st+1) );
            pitch=-(3072000L/(32*f)-2048);
            sound_set_pitch( 2, pitch );
            sound_set_sweep(sw, st); 
            sys_wait(5);
        }
    }
    sound_set_channel( 0x0000 );
}