ワークメモリ上の波形データをPCMストリームを利用して再生するサンプル

1998. 9.29更新

サンプルについて

 このサンプルはワークメモリ既にある波形データをPCMストリームを利用して再生を行うプログラムです.


サンプルの流れ

 サウンドライブラリ・ドライバの初期化を行い,440Hzの音を再生する.

 処理の流れとしては

  1. PCMストリームポートのハンドルの取得sdPstmOpenPortPort

  2. 使用するチャンネル分のメモリハンドルの取得sdMemBlkCreate

  3. あらかじめある程度の波形データをサウンドメモリに転送sdPstmTransfer

  4. PCMストリームの再生開始sdPstmPlay

  5. 残りの波形データをサウンドメモリに転送sdPstmTransfer

  6. 後処理

となります.


注意点

 本サンプルには下記の注意事項があります.

  1. あらかじめ転送しておく波形データのサイズの修正
     あらかじめ転送しておく波形データのサイズをPRE_TRANS_SZに設定しておく.

  2. 残りの波形データの転送するサイズの修正
     残りの波形データを転送するサイズをTRANS_SZに設定しておく.


実際のコーディング

 実際のコーディングを下記に提示する.なお,このサンプルはエラーチェックをかなり省いています.

簡単なワークメモリ上の波形データのPCMストリームのサンプル
/*********************************************************
 *
 *    Sound Library Sample
 *
 *    ワークメモリ上の波形データをPCMストリームで再生する.
 *
 *********************************************************/


#include <sd_sg.h>

/*  前もって転送しておく波形サイズ(単位はバイト)  */
#define PRE_TRANS_SZ (0x4000)

/*  再生中に転送する波形サイズ(単位はバイト)  */
#define TRANS_SZ (0x1000)

SDE_ERR OnMemoryPCMStream(
Sint8 ch_num, チャンネル数(モノラルは0,ステレオは1)
SDE_PCM_TYPE src_type, 波形データのタイプ.
Uint16 src_freq, サンプリング周波数(本当にサンプリング周波数が入っているわけではない)
Void *ch0_src_adr, チャンネル0(ステレオの場合は左チャンネル)の再生波形の先頭アドレス.
Void *ch1_src_adr, 左チャンネルの再生波形の先頭アドレス(ステレオの場合のみ有功.モノラルの時は無視される)
Sint32 src_sz) 波形サイズ(単位はバイト)
{
SDPSTM pstm_handle = NULL;
Sint32 seek_sz, ch;
Sint8 *seek_adr[ SDD_PSTM_CH_MAX];
SDMEMBLK memblk[ SDD_PSTM_CH_MAX];
Sint32 i;

/*
 *  ローカル変数の初期化
 */

for ( i = 0; i < [ SDD_PSTM_CH_MAX]; i++)
{
memblk[ i] = NULL;
}
seek_adr[ 0] = ch0_src_adr;
seek_adr[ 1] = ch1_src_adr;

/*
 *  PCMストリームポートのハンドルを取得する
 */

#if PCM_CH==1
/*
 *  モノラルの場合
 */

/*  リングバッファは0番使用する  */
if ( sdPstmOpenPort( &pstm_handle, PSTM_CH, 0) != SDE_ERR_NOTHING)
#elif PCM_CH==2
/*
 *  ステレオの場合
 */

/*  リングバッファは0番と1番を使用する  */
if ( sdPstmOpenPort( &pstm_handle, PSTM_CH, 0, 1) != SDE_ERR_NOTHING)
#else
#error PCMチャンネルは1もしくは2のみ指定可能.
#endif /*  PCM_CH==1  */
{
/*  エラーが起こった  */
goto exit;
}

/*
 *  メモリブロックハンドルの取得
 */

for ( ch = 0; ch < ch_num; ch++)
{
if ( sdMemBlkCreate( &memblk[ ch]) != SDE_ERR_NOTHING)
{
/*  エラーが起こった  */
goto exit;
}
}

/*
 *  まずあらかじめリングバッファを少し埋めておく
 */

for ( ch = 0; ch < ch_num; ch++)
{
Bool flg;

/*  念の為転送していいかどうか調べてみる  */
do {
sdPstmIsTransfer( pstm_handle, ch, PRE_TRANS_SZ, &flg);
} while ( flg != true);


/*  実際に転送  */
sdMemBlkSetPrm( memblk[ ch], seek_adr[ ch], PRE_TRANS_SZ, SDD_MEMBLK_SYNC_FUNC, NULL);
sdPstmTransfer( pstm_handle, memblk[ ch]);
/*  シーク位置の移動  */
seek_adr[ ch] = &seek_adr[ ch][ PRE_TRANS_SZ];
}

/*
 *  PCMストリーム再生開始
 */

if ( sdPstmPlay( pcm_handle, src_type, src_freq, 0) != SDE_ERR_NOTHING) {
/*  エラーが起こった  */
goto exit;
}

/*
 *  必要分だけ波形データを逐次転送する
 */

for ( seek_sz = PRE_TRANS_SZ; seek_sz < src_sz; seek_sz += TRANS_SZ)
{
for ( ch = 0; ch < ch_num; ch++)
{
Bool flg;

/*  念の為転送していいかどうか調べてみる  */
do {
sdPstmIsTransfer( pstm_handle, ch, TRANS_SZ, &flg);
} while ( flg != true);


/*  実際に転送  */
sdMemBlkSetPrm( memblk[ ch], seek_adr[ ch], TRANS_SZ, SDD_MEMBLK_SYNC_FUNC, NULL);
sdPstmTransfer( pstm_handle, memblk[ ch]);
/*  シーク位置の移動  */
seek_adr[ ch] = &seek_adr[ ch][ TRANS_SZ];
}
}

exit:
if ( pstm_handle != NULL)
{
/*  PSTMポートの再生停止  */
sdPstmStop( pcm_handle);
/*  PSTMポートのハンドルの破棄  */
sdPstmClosePort( pstm_handle);
}
for ( i = 0; i < ch_num; i++)
{
if ( memblk[ i] != NULL)
{
sdMemBlkDestory( memblk[ i]);
}
}

}

/*EOF*/

サンプルの応用

 現在メモリブロックハンドルにのコールバック関数SDD_MEMBLK_SYNC_FUNCを使用していますが,独自でコールバック関数を用意することで波形データの転送終了を待たずに別の処理をすることが可能になります(その場合上記のサンプルよりかなり複雑な処理になります)