サウンドをチャンネルで管理 ― 2013/11/25
サウンドプレイヤーは最低限、同時再生の数だけ必要ですが、通常そんなものはたかがしれています。
システム側でプレイヤーをチャンネルとして管理、アプリ側はチャンネル番号を指定して再生などのサウンド処理を行うようにしてみます。
Sound.h
サウンド管理クラス sys::SoundManagerです。
メンバ関数は基本的に sys::SoundPlayerの関数の先頭の引数にチャンネル番号をくっつけたものとなっています。
Sound.cpp
初期化・終了処理です。
プレイヤーのインスタンスの確保・解放を行います。また、sys::SoundPlayerの初期化・終了処理もここで呼んでしまいます。
チャンネル数 SOUND_CHANNEL_MAXは、def.hで定義しています。
再生等の処理です。
指定されたチャンネルのプレイヤーの処理を呼んでます。
停止等の処理でチャンネルを指定しない場合は、すべてのチャンネルのプレイヤーで処理を行うようになっています。
マスター音量設定時の各プレイヤーの音量の再設定はここで行いますので、アプリ側で行う必要はなくなりました。
一時停止・再開の処理も基本的には同じですが、サスペンド・レジュームによる処理をシステム側で行うことにします。
アプリ側で行う一時停止もシステム側で行う一時停止も OpenSLのプレイヤーの処理としては変わりませんが、サウンド管理ではこの二つは分ける必要があります。
例えば、
・メニューを開く、等でBGMを一時停止(アプリ側)
・サスペンドでサウンドを一時停止(システム側)
・レジュームでサウンド再開(システム側)
のときに、アプリ側で一時停止されたBGMを再開させてはいけません。
ここではサスペンドによる一時停止のときはプレイヤーの状態変数を PLAYINGのまま変えず、レジューム時に状態が PLAYINGのプレイヤーだけ再開するようにしています。アプリ側で一時停止されたプレイヤーの状態は PAUSEDになっていますので、このときには再開されません。
サンプル
AppMain.cpp
チャンネル指定でサウンドの再生を行っています。
また、
・プレイヤーのインスタンス確保、解放
・サスペンド、レジューム時のサウンド処理
が削除されています。
プロジェクト一式は、こちらから。
システム側でプレイヤーをチャンネルとして管理、アプリ側はチャンネル番号を指定して再生などのサウンド処理を行うようにしてみます。
Sound.h
/******************
サウンド管理
******************/
class SoundManager
{
static SoundPlayer* player; // プレイヤー
public :
static void init(void); // 初期化
static void quit(void); // 終了
static void play(int, const void*, u32, int _loop = 1, float _vol = 1.0f); // 再生
static void play(int);
static void prepare(int, const void*, u32, int _loop = 1, float _vol = 1.0f); // 再生準備
static void play(void); // 全て再生
static void stop(int); // 停止
static void stop(void); // 全て停止
static void set_volume(int, float); // 音量設定
static void set_master_volume(float); // マスター音量設定
static void set_next(int, const void*, u32, int _loop = 1); // 連続再生設定
static void pause(int); // 一時停止
static void pause(void); // 全て一時停止
static void pause_system(void); // システムによる一時停止
static void resume(int); // 再開
static void resume(void); // 全て再開
static void resume_system(void); // システムによる再開
};
サウンド管理クラス sys::SoundManagerです。
メンバ関数は基本的に sys::SoundPlayerの関数の先頭の引数にチャンネル番号をくっつけたものとなっています。
Sound.cpp
SoundPlayer* SoundManager::player = NULL; // プレイヤー
/************************
サウンド管理初期化
************************/
void SoundManager::init(void)
{
SoundPlayer::init_engine(); // サウンドエンジン初期化
player = new SoundPlayer[SOUND_CHANNEL_MAX]; // プレイヤー
}
/**********
終了
**********/
void SoundManager::quit(void)
{
if ( player ) {
delete[] player;
player = NULL;
}
SoundPlayer::quit_engine(); // サウンドエンジン終了
}
初期化・終了処理です。
プレイヤーのインスタンスの確保・解放を行います。また、sys::SoundPlayerの初期化・終了処理もここで呼んでしまいます。
チャンネル数 SOUND_CHANNEL_MAXは、def.hで定義しています。
/********************************************************
再生
引数 _channel = チャンネル番号
_data = サウンドデータ
_size = サウンドデータサイズ
_loop = ループ回数(0:無限ループ)
_vol = 音量
*******************************************************/
void SoundManager::prepare(int _channel, const void* _data, u32 _size, int _loop, float _vol)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].prepare(_data, _size, _loop, _vol);
}
void SoundManager::play(int _channel)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].play();
}
void SoundManager::play(int _channel, const void* _data, u32 _size, int _loop, float _vol)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].prepare(_data, _size, _loop, _vol);
player[_channel].play();
}
void SoundManager::play(void)
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) { // 全て再生開始
player[i].play();
}
}
/*******************************************
停止
引数 _channel = チャンネル番号
*******************************************/
void SoundManager::stop(int _channel)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].stop();
}
void SoundManager::stop(void)
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) { // 全て停止
player[i].stop();
}
}
/*********************************************************
音量設定
引数 _channel = チャンネル番号
_vol = 音量(0.0:最小 ~ 1.0:最大)
*********************************************************/
void SoundManager::set_volume(int _channel, float _vol)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].set_volume(_vol);
}
/*****************************************************
マスター音量設定
引数 _vol = 音量(0.0:最小 ~ 1.0:最大)
*****************************************************/
void SoundManager::set_master_volume(float _vol)
{
if ( SoundPlayer::set_master_volume(_vol) ) {
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {
player[i].set_volume(); // 音量再設定
}
}
}
/*******************************************************
連続再生設定
引数 _channel = チャンネル番号
_data = サウンドデータ
_size = サウンドデータサイズ
_loop = ループ回数(0:無限ループ)
*******************************************************/
void SoundManager::set_next(int _channel, const void* _data, u32 _size, int _loop)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].set_next(_data, _size, _loop);
}
再生等の処理です。
指定されたチャンネルのプレイヤーの処理を呼んでます。
停止等の処理でチャンネルを指定しない場合は、すべてのチャンネルのプレイヤーで処理を行うようになっています。
マスター音量設定時の各プレイヤーの音量の再設定はここで行いますので、アプリ側で行う必要はなくなりました。
/*********************************************
一時停止
引数 _f = 状態フラグを変更するか
*********************************************/
void SoundPlayer::pause(Bool _f)
{
if ( state == PLAYING ) { // 再生中
if ( bqPlayerObject ) {
(*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED); // 一時停止状態
}
if ( _f ) {
state = PAUSED;
}
}
}
/*********************************************
一時停止
引数 _channel = チャンネル番号
*********************************************/
void SoundManager::pause(int _channel)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].pause(TRUE);
}
void SoundManager::pause(void)
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) { // 全て一時停止
player[i].pause(TRUE);
}
}
void SoundManager::pause_system(void) // システムによる一時停止
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) { // 全て一時停止
player[i].pause(FALSE);
}
}
/*********************************************
再開
引数 _channel = チャンネル番号
*********************************************/
void SoundManager::resume(int _channel)
{
assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));
player[_channel].resume();
}
void SoundManager::resume(void)
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) { // 全て再開
player[i].resume();
}
}
void SoundManager::resume_system(void) // システムによる再開
{
for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {
if ( player[i].get_state() == SoundPlayer::PLAYING ) {
player[i].play();
}
}
}
一時停止・再開の処理も基本的には同じですが、サスペンド・レジュームによる処理をシステム側で行うことにします。
アプリ側で行う一時停止もシステム側で行う一時停止も OpenSLのプレイヤーの処理としては変わりませんが、サウンド管理ではこの二つは分ける必要があります。
例えば、
・メニューを開く、等でBGMを一時停止(アプリ側)
・サスペンドでサウンドを一時停止(システム側)
・レジュームでサウンド再開(システム側)
のときに、アプリ側で一時停止されたBGMを再開させてはいけません。
ここではサスペンドによる一時停止のときはプレイヤーの状態変数を PLAYINGのまま変えず、レジューム時に状態が PLAYINGのプレイヤーだけ再開するようにしています。アプリ側で一時停止されたプレイヤーの状態は PAUSEDになっていますので、このときには再開されません。
サンプル
AppMain.cpp
sys::SoundManager::play(4, "bgm.ogg", sys::SoundPlayer::FILE_ASSET, 0); // BGM再生開始
if ( sys::TouchPanel[0].flag & sys::TouchManager::TRIGGER ) {
sys::SoundManager::play(se_track, sound_data[SOUND_SE], sound_size[SOUND_SE]); // SE再生
se_track = ++se_track % 4;
}
チャンネル指定でサウンドの再生を行っています。
また、
・プレイヤーのインスタンス確保、解放
・サスペンド、レジューム時のサウンド処理
が削除されています。
プロジェクト一式は、こちらから。
最近のコメント