サウンド処理は非同期で その32013/11/30

サウンド管理でコマンドを javaに送る処理、そしてキューの中身を受け取ってサウンドプレイヤーの処理を実行する部分を作成します。これでサウンドの非同期処理の実装完了となります。


Sound.cpp
/**********
    終了
 **********/
void	SoundManager::quit(void)
{
	{				// コマンド停止
		JNIEnv*		env;
		Bool		attach_flag = FALSE;

		if ( g_JavaVM->GetEnv((void**)&env, JNI_VERSION_1_6) < 0 ) {
			if ( g_JavaVM->AttachCurrentThread(&env, NULL) < 0 ) {
				goto error;
			}
			attach_flag = TRUE;
		}

		jclass	clazz = env->FindClass("sys/SoundManager");

		if ( clazz ) {
			jmethodID	mid = env->GetStaticMethodID(clazz, "stop_command", "()V");

			if ( mid ) {
				env->CallStaticVoidMethod(clazz, mid);
			}
		}
		if ( attach_flag ) {
			g_JavaVM->DetachCurrentThread();
		}
	}

error :
	if ( player ) {
		delete[]	player;
		player = NULL;
	}
	SoundPlayer::quit_engine();							// サウンドエンジン終了
}

サウンド管理終了時、まだキューにコマンドが残っている可能性がありますので java側の関数を呼んでクリアしています。

// サウンドコマンド
enum
{
	COMMAND_UPDATE,			// 稼働
	COMMAND_PREPARE,		// 準備
	COMMAND_PLAY,			// 再生・再開
	COMMAND_STOP,			// 停止
	COMMAND_VOLUME,			// 音量設定
	COMMAND_NEXT,			// 連続再生設定
	COMMAND_PAUSE,			// 一時停止
	COMMAND_PAUSE_SYS,
	COMMAND_RESUME,			// 再開
	COMMAND_RESUME_SYS,
};

/**********
    稼働
 **********/
void	SoundManager::update(void)
{
	set_command(-1, COMMAND_UPDATE);
}

/********************************************************
    再生
		引数	_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));

	set_command(_channel, COMMAND_PREPARE, _data, _size, _loop, _vol);
}

void	SoundManager::play(int _channel)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_PLAY);
}

void	SoundManager::play(int _channel, const void* _data, u32 _size, int _loop, float _vol)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_PLAY, _data, _size, _loop, _vol);
}

void	SoundManager::play(void)
{
	set_command(-1, COMMAND_PLAY);				// 全て再生開始
}

/*******************************************
    停止
		引数	_channel = チャンネル番号
				_cnt     = フェード時間
 *******************************************/
void	SoundManager::stop(int _channel, int _cnt)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_STOP, NULL, (u32)_cnt);
}

void	SoundManager::stop(void)
{
	set_command(-1, COMMAND_STOP);				// 全て停止
}

/*********************************************************
    音量設定
		引数	_channel = チャンネル番号
				_vol     = 音量(0.0:最小 ~ 1.0:最大)
 *********************************************************/
void	SoundManager::set_volume(int _channel, float _vol)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_VOLUME, NULL, 0, 0, _vol);
}

/*****************************************************
    マスター音量設定
		引数	_vol = 音量(0.0:最小 ~ 1.0:最大)
 *****************************************************/
void	SoundManager::set_master_volume(float _vol)
{
	set_command(-1, COMMAND_VOLUME, NULL, 0, 0, _vol);
}

/*******************************************************
    連続再生設定
		引数	_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));

	set_command(_channel, COMMAND_NEXT, _data, _size, _loop);
}

/*********************************************
    一時停止
		引数	_channel = チャンネル番号
 *********************************************/
void	SoundManager::pause(int _channel)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_PAUSE);
}

void	SoundManager::pause(void)
{
	set_command(-1, COMMAND_PAUSE);				// 全て一時停止
}

void	SoundManager::pause_system(void)		// システムによる一時停止
{
	set_command(-1, COMMAND_PAUSE_SYS);
}

/*********************************************
    再開
		引数	_channel = チャンネル番号
 *********************************************/
void	SoundManager::resume(int _channel)
{
	assert((0 <= _channel) && (_channel < SOUND_CHANNEL_MAX));

	set_command(_channel, COMMAND_RESUME);
}

void	SoundManager::resume(void)
{
	set_command(-1, COMMAND_RESUME);			// 全て再開
}

void	SoundManager::resume_system(void)		// システムによる再開
{
	set_command(-1, COMMAND_RESUME_SYS);
}

再生などサウンドのコマンドを受け取る処理です。
直接サウンドプレイヤーの処理を呼んでいたのを、キューにコマンドを送るように変更しています。

/********************************
    Javaからコマンドを受け取る
 ********************************/
extern "C"
{
JNIEXPORT void JNICALL	Java_sys_SoundManager_sendSoundCommand(JNIEnv*, jobject, jshort, jshort, jint, jint, jshort, jfloat);
}

JNIEXPORT void JNICALL	Java_sys_SoundManager_sendSoundCommand(JNIEnv*, jobject,
								jshort _channel, jshort _command, jint _data, jint _size, jshort _loop, jfloat _volume)
{
	SoundManager::get_command((int)_channel, (int)_command, (void*)_data, (u32)_size, (int)_loop, (float)_volume);
}

void	SoundManager::get_command(int _channel, int _command, void* _data, u32 _size, int _loop, float _volume)
{
	switch ( _command ) {
	  case COMMAND_UPDATE :
		for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {
			player[i].update();
		}
		break;

	  case COMMAND_PREPARE :
		player[_channel].prepare(_data, _size, _loop, _volume);
		break;

	  case COMMAND_PLAY :
		if ( _channel >= 0 ) {
			if ( _size ) {
				player[_channel].prepare(_data, _size, _loop, _volume);
			}
			player[_channel].play();
		}
		else {
			for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {			// 全て再開
				player[i].play();
			}
		}
		break;

	  case COMMAND_STOP :
		if ( _channel >= 0 ) {
			player[_channel].stop((int)_size);
		}
		else {
			for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {			// 全て停止
				player[i].stop();
			}
		}
		break;

	  case COMMAND_VOLUME :
		if ( _channel >= 0 ) {
			player[_channel].set_volume(_volume);
		}
		else if ( SoundPlayer::set_master_volume(_volume) ) {		// マスター音量設定
			for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {
				player[i].set_volume();								// 音量再設定
			}
		}
		break;

	  case COMMAND_NEXT :
		player[_channel].set_next(_data, _size, _loop);
		break;

	  case COMMAND_PAUSE :
		if ( _channel >= 0 ) {
			player[_channel].pause(TRUE);
		}
		else {
			for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {			// 全て一時停止
				player[i].pause(TRUE);
			}
		}
		break;

	  case COMMAND_PAUSE_SYS :
		for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {				// システムによる再開
			player[i].pause(FALSE);
		}
		break;

	  case COMMAND_RESUME :
		if ( _channel >= 0 ) {
			player[_channel].resume();
		}
		else if ( _size ) {
			for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {			// 全て再開
				player[i].resume();
			}
		}
		break;

	  case COMMAND_RESUME_SYS :
		for (int i = 0; i < SOUND_CHANNEL_MAX; i++) {				// システムによる再開
			player[i].resume(SoundPlayer::PLAYING);
		}
		break;
	}
}

javaからコマンドを受け取って実行する部分です。
コマンドの値に従ってサウンドプレイヤーの関数を呼び出しています。

再生・停止など命令がいろいろあるので処理は多いですが、どれもやっていることは同じです。


サウンドの命令自体は同じなので、サンプルに変更はありません。

プロジェクト一式は、こちらから。