サウンド - 連続再生など ― 2013/11/22
サウンドプレイヤーにに以下の機能を追加してみます。
・連続再生
・assetsファイル指定再生
連続再生
1つのサウンドデータを鳴らし終わった後に、続けて別のサウンドデータを鳴らす機能です。アプリ側で再生終了を監視して次のデータを再生するという手もありますが、ラグがあったり面倒だったりしますのでサウンドプレイヤーで処理するようにします。
BGMをイントロ部分と、メインのループ部分に分けて鳴らすようなときに使います。
ファイル指定再生
メモリに常駐するまでもない一時的なサウンドを、ファイルから読み込んで再生します。
ファイル上のサウンドデータを鳴らすだけならば、アプリ側でメモリに読み込んで再生すれば良いのですが、再生終了時にメモリを解放する必要があります。アプリ側で終了を監視するのはこれまた面倒なので、プレイヤーで処理します。
Sound.h
連続再生の予約で複数のサウンドデータを持つ必要があるため、サウンドデータを構造体 SoundDataで管理します。
再生終了時に解放するデータは、再生用データとは別に指定します。
Sound.cpp
再生準備関数 prepare内です。
assetsファイルを再生する場合は、_dataにファイル名文字列、_sizeに定数 sys::SoundPlayer::FILE_ASSETを指定します。
データ・サイズ等を管理する SoundDataを作成して sound_dataに保存します。
連続再生設定関数です。
再生準備と同様に SoundDataを作成して sound_dataの後ろにくっつけておきます。
再生コールバックです。
再生終了時に次のデータがあった場合は sound_dataを入れ替えて、再びキューにデータを送って再生を続けます。
終了したデータは deleteされ、このときファイルから読み込んだデータは SoundDataのデストラクタで解放されます。
この他、停止関数やデストラクタでもsound_dataの解放を行います。
サンプルのBGM再生部分です。
AppMain.cpp
"bgm.wav"を3回鳴らした後に、"bgm2.wav"を1回鳴らしています。
プロジェクト一式は、こちらから。
・連続再生
・assetsファイル指定再生
連続再生
1つのサウンドデータを鳴らし終わった後に、続けて別のサウンドデータを鳴らす機能です。アプリ側で再生終了を監視して次のデータを再生するという手もありますが、ラグがあったり面倒だったりしますのでサウンドプレイヤーで処理するようにします。
BGMをイントロ部分と、メインのループ部分に分けて鳴らすようなときに使います。
ファイル指定再生
メモリに常駐するまでもない一時的なサウンドを、ファイルから読み込んで再生します。
ファイル上のサウンドデータを鳴らすだけならば、アプリ側でメモリに読み込んで再生すれば良いのですが、再生終了時にメモリを解放する必要があります。アプリ側で終了を監視するのはこれまた面倒なので、プレイヤーで処理します。
Sound.h
/******************** サウンドデータ ********************/ struct SoundData { char* data; // データ u32 size; // データサイズ int loop; // ループカウンタ void* file_data; // 終了時に解放するデータ SoundData* next; // 次のデータ SoundData(char* _data, u32 _size, int _loop, void* _file = NULL) // コンストラクタ { data = _data; size = _size; loop = _loop; file_data = _file; next = NULL; } ~SoundData() // デストラクタ { if ( file_data ) { free(file_data); } if ( next ) { delete next; } } void set_next(SoundData* _next) // 次のデータを設定 { if ( next ) { next->set_next(_next); } else { next = _next; } } };
連続再生の予約で複数のサウンドデータを持つ必要があるため、サウンドデータを構造体 SoundDataで管理します。
再生終了時に解放するデータは、再生用データとは別に指定します。
Sound.cpp
void* _file_data; switch ( _size ) { case FILE_ASSET : // assetファイル _file_data = load_asset((char*)_data, &_size); _data = _file_data; break; default : // メモリ _file_data = NULL; break; }
WaveFormat* _info = (WaveFormat*)_data; format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = (SLuint32)_info->channel; format_pcm.samplesPerSec = (SLuint32)_info->rate*1000; format_pcm.bitsPerSample = (SLuint32)_info->bit; format_pcm.containerSize = (SLuint32)_info->bit; format_pcm.channelMask = (_info->channel == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; sound_data = new SoundData((char*)((u32)_data + sizeof(WaveFormat)), _info->data_size, _loop, _file_data);
再生準備関数 prepare内です。
assetsファイルを再生する場合は、_dataにファイル名文字列、_sizeに定数 sys::SoundPlayer::FILE_ASSETを指定します。
データ・サイズ等を管理する SoundDataを作成して sound_dataに保存します。
/**************************************************** 連続再生設定 引数 _data = サウンドデータ _size = サウンドデータサイズ _loop = ループ回数(0:無限ループ) ****************************************************/ void SoundPlayer::set_next(const void* _data, u32 _size, int _loop) { if ( sound_data == NULL ) { // すでに鳴り終わっている可能性 play(_data, _size, _loop); return; } void* _file_data; switch ( _size ) { case FILE_ASSET : // assetファイル _file_data = load_asset((char*)_data, &_size); _data = _file_data; break; default : // メモリ _file_data = NULL; break; } WaveFormat* _info = (WaveFormat*)_data; sound_data->set_next(new SoundData((char*)((u32)_data + sizeof(WaveFormat)), _info->data_size, _loop, _file_data)); }
連続再生設定関数です。
再生準備と同様に SoundDataを作成して sound_dataの後ろにくっつけておきます。
void SoundPlayer::callback_wav(void) { if ( sound_data->loop == 1 ) { if ( sound_data ) { if ( sound_data->next == NULL ) { // 終了 delete sound_data; sound_data = NULL; } else { // 連続再生 SoundData* _next = sound_data->next; sound_data->next = NULL; delete sound_data; sound_data = _next; (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, sound_data->data, (SLuint32)sound_data->size); return; } } (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); // 停止 state = STOPPED; return; } if ( sound_data->loop > 1 ) { sound_data->loop--; } (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, sound_data->data, (SLuint32)sound_data->size); // 再生開始 }
再生コールバックです。
再生終了時に次のデータがあった場合は sound_dataを入れ替えて、再びキューにデータを送って再生を続けます。
終了したデータは deleteされ、このときファイルから読み込んだデータは SoundDataのデストラクタで解放されます。
この他、停止関数やデストラクタでもsound_dataの解放を行います。
サンプルのBGM再生部分です。
AppMain.cpp
sound_player[4].play("bgm.wav", sys::SoundPlayer::FILE_ASSET, 3); // BGM再生開始 sound_player[4].set_next("bgm2.wav", sys::SoundPlayer::FILE_ASSET, 1); // 連続再生設定
"bgm.wav"を3回鳴らした後に、"bgm2.wav"を1回鳴らしています。
プロジェクト一式は、こちらから。
最近のコメント