サウンドを鳴らすA


インダイレクトライブラリを使う

サウンドインダイレクトライブラリ(soundIL)はHBLANK割り込みを利用して、演奏データに基づいた音楽演奏を行うドライバです。SoundILの使用法についてはワンダーウィッチのマニュアルに詳しい説明がありますが、ここでは実際のプログラミング例を紹介します。

インダイレクトライブラリ使用の準備

サウンドインダイレクトライブラリを使うためには次の準備が必要です。
@WWitch/il/soundディレクトリにある SoundIL本体(sound.il)をワンダースワン本体へ転送する。
AWWitch/il/soundディレクトリにある il_sound.h を include ディレクトリへコピーする。

MML(Music Macro Language)データを鳴らす

サウンドインダイレクトライブラリでは携帯電話の着メロデータとしても使われている、MML(Music Macro Language)で記述したシーケンスデータをBGM(4トラック)、効果音(2トラック) として 出力することができます。

ドレミファソラシ(CDEFGAB)をBGMとして繰り返し(PLAY_LOOP)演奏させる例を示します。
#include <sys/bios.h>
#include <il_sound.h>
    
SoundIL soundIL;
static BYTE buf[1000];                     /* データ用バッファ */
   
void main()
{
    if ( open_sound_il(&soundIL) != E_FS_SUCCESS ) {
        return;                              /* ドライバ存在せず */
    }
    sounddrv_init();            /* ドライバ用ワークの確保 */
    sound_open();                           /* HBLANK割り込みを開始 */ 
     
    parse_mml( buf, "#1CDEFGAB", 0 );       /* バッファへ演奏データを格納 */
    bgm_play( buf, PLAY_LOOP );             /* BGM演奏開始(ループ) */

    key_wait();                             /* キー入力待ち */
        
    sound_close();                          /* HBLANK割り込み停止 */
    sounddrv_release();                     /* ドライバ用ワークの開放 */
}

#include <il_sound.h>
SoundIL soundIL;

static BYTE buf[1000];
サウンドドライバを使うプログラムは、il_sound.h をインクルードします。
SoundIL の関数テーブルとなるグローバル変数を定義します
サウンドドライバの関数は、il_sound.h でマクロ定義されており、実際には soundILの関数テーブルを介して呼び出されます

演奏データのためのバッファを確保します。

if ( open_sound_il(&soundIL) != E_FS_SUCCESS ) {
    return;   
}
サウンドドライバをオープンします。ドライバが存在しなければ(本体ROM内になければ) プログラムを終了(return)します。
sounddrv_init();

sound_open();
サウンドドライバ用のワーク(256+16バイト)をIRAMへ確保。既に確保済みの場合は、何もしません。

HBLANKタイマー割り込みを設定し、演奏可能にします。 sounddrv_init()が未実行の場合は、内部でsounddrv_init()を呼びます。

parse_mml( buf, "#1CDEFGAB", 0 );
MMLテキストを解析してシーケンスリソースに変換し、バッファへ格納します。
最後の値は、0=BGM, 0以外=効果音の最大数を示します。 この例では#1(チャンネル1)にドレミファソラシの音を設定しています。
bgm_play( buf, PLAY_LOOP );
BGMの演奏を開始します。PLAY_LOOPは演奏モードで、0で1回のみ演奏、1で繰り返し演奏となります。
sound_close();

sounddrv_release();
HBLANKタイマー割り込みを停止します。 sound_open()が重複して呼ばれている場合は、sound_close()を同じ回数呼ばなければなりません。

サウンドドライバ用のワークを開放します。

効果音を鳴らす

次の例ではキーを押すことにより、簡単な効果音(MML)を鳴らします。
効果音はチャンネル3に設定し、se_play関数で出力します。2つめの値は 登録してある効果音の番号 (0〜効果音の数-1)です。
#include <sys/bios.h>
#include <il_sound.h>

static	BYTE buf[1000];

SoundIL		soundIL;

void main(void)
{
    if ( open_sound_il( &soundIL ) != E_FS_SUCCESS )
        return;

    sounddrv_init();
    sound_open();

    parse_mml( buf, "#3C40B40", 1 );  /* 効果音を1つ登録 */

    while(key_wait() != KEY_START ){    /* キーが押されたら */
        se_play(buf, 0);           /* 0番の効果音 */
    }
    sound_close();
    sounddrv_release();
}

BGMを演奏しながら効果音を鳴らす

次のプログラムははBGMを演奏しながら、効果音を鳴らす例です。
#include <sys/bios.h>
#include <il_sound.h>

static	BYTE bgmbuf[500],sebuf[500];

SoundIL		soundIL;

void main(void)
{
    if ( open_sound_il( &soundIL ) != E_FS_SUCCESS )
        return;

    sounddrv_init();
    sound_open();

    parse_mml( bgmbuf, "#1CDEFGAB", 0 ); /* バッファへBGMデータを格納 */
    parse_mml( sebuf, "#3C40B40", 1 );  /* バッファへ効果音データを格納 */

    bgm_play( bgmbuf, PLAY_LOOP );       /* BGM演奏開始(ループ) */

    while(key_wait() != KEY_START ){     /* キーが押されたら */
        se_play(sebuf, 0);               /*効果音を鳴らす*/
    }
    sound_close();
    sounddrv_release();
}

Waveファイルをリソースファイルに変換して鳴らす

リソースファイルを読みこんで鳴らすプログラムです。
Waveファイルはサウンドレコーダーなどでワンダースワンで使える形式『8bit,サンプリング12KHz』 にし、付属ツールのSndcnvを使ってリソースファイル(.fr)に変換します。
作成したリソースファイルはあらかじめワンダースワンへ転送しておきます。

#include "il_sound.h"
#include "sys/bios.h"
#include "stdio.h"

static BYTE buf[20000];
SoundIL soundIL;

void main(void)
{
    int iFd;

    if ( open_sound_il( &soundIL ) != E_FS_SUCCESS )
        return;

    sounddrv_init();
    sound_open();

    if((iFd = open("abu.fr", FMODE_R, 0)) >= 0) {
        read(iFd ,buf , 20000 );   /* リソースファイルを開く */ 
        close(iFd);
    }

    while(key_wait() != KEY_START) {
        voice_play (buf, 0);            /* PCMボイス再生 */
    }                                       /* パラメータ0は未使用 */

    sound_close();
    sounddrv_release();
}


音を鳴らしながらスクロール
『スクリーンの機能』で紹介した「宇宙飛行」のサンプルにサウンドを付けてみました。 ただ繰り返し演奏させているだけですが、けっこう雰囲気がでています。
#include "sys/bios.h"
#include "stdlib.h"
#include "il_sound.h"

static	BYTE bgmbuf[500];

SoundIL		soundIL;

#include "star0.h"
#include "star1.h"
unsigned star0[]={2};
unsigned star1[]={3};
#include "rocket.h"

unsigned char bmp_black[]={ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

void main()
{
    int x,y,i,j,k;

    display_control( DCM_SCR2 | DCM_SPR );

    font_set_monodata( 1, 1, bmp_black);                    /* 背景の黒 */
    font_set_colordata( 2, 1, bmp_star0);                   /* 小さな星 */
    font_set_colordata( 3, 1, bmp_star1);                   /* 大きな星 */

    font_set_colordata(4, 4*4, bmp_rocket);                /* ロケット */
    for(i=0;i<16;i++) 
        sprite_set_char(i,(i+4) | 4<<9 | CFM_SPR_UPPER);
    sprite_set_range( 0, 16 );

    screen_fill_char(SCREEN2, 0, 0, 32, 32, 1);             /* 全てを黒に */

    for(i=0;i<200;i++){                                    
        x = rand() % 31;
        y = rand() % 31;
        star0[0]= 2 | (rand()%3)<<14;
        if(i<180)
            screen_set_char(SCREEN2, x, y, 1 , 1 , star0); /* 小さな星を表示 */
        else
            screen_set_char(SCREEN2, x, y, 1 , 1 , star1); /* 大きな星を表示 */
    }

    x=30; y=56;                                          /* ロケットを表示 */
    for ( i=0; i<4; i++ ) {
        for ( j=0; j<4; j++ ) {
            sprite_set_location( i*4+j, x+j*8, y+i*8 );
        }
    }

    if ( open_sound_il( &soundIL ) != E_FS_SUCCESS )
        return;

    sounddrv_init();
    sound_open();                             /* バッファへ演奏データを格納 */
    parse_mml( bgmbuf, "#1f12f12f12a+2>f4d+12d12c12a+2f4
                        d+12d12c12a+2f4d+12d12d+12c2r6", 0 );
    bgm_play( bgmbuf, PLAY_LOOP );                /* BGM演奏開始(ループ) */

    x=0; y=0;
    while( (k=key_press_check() ) != KEY_START ){ /* STARTボタンで終了 */
	    switch (k) {
	        case KEY_RIGHT2:x+=1; break;      /* キー入力でスクロール */
	        case KEY_DOWN2: y+=1; break;
	        case KEY_UP2:   y-=1; break;
	    }
        x+=1;                                 /* 常に前進するようスクロール */
        screen_set_scroll(SCREEN2, x, y);
        sys_wait(2);                              /* タイムディレイ */
    }
    sound_close();
    sounddrv_release();
}