Cocos2dxフレームワークの SimpleAudioEngine や AudioEngine に機能不足やバージョンによってバグがあるため、CRIWAREやCricketを使っている企業が多いかと思います。今回は手が出しやすいCricketについて書きます。
http://www.crickettechnology.com/
今回試した環境は以下になります。
- Mac OSX 10.4
- Cocos2d-x v3.7
- Cricket Audio version 1.5.0
Criket Audioの特徴
Cricket Audioには2種類の再生方法があり、それぞれ以下のようになっています。
- Bank sounds
オンメモリ再生を行う形式。対応ファイル形式はwavもしくはaiffファイルのみ - Stream sounds
ストリーミング再生を行う形式。対応ファイル形式はwav/mp3/mp4/m4a*1
Bank soundsはSE、Stream soundsはBGM再生の用途で使うことになります。
それ以外の特徴としては、以下になります。
利用するために掛かる費用
ライセンス表記をアプリ上のどこかしらに表記し、Cricketへの利用報告する事で無料にて利用可能なようです。サポートを受けるには$99支払う必要があります。
もしクレジット表記やCriketへの利用報告(公式サイトへ利用アプリ掲載したくない)場合、ライセンス料を支払う事で免除されます。
http://www.crickettechnology.com/free_license
SDKのダウンロード
公式サイトのDownloadページから行えます。なお、DLにはアカウント作成が必要です。
http://www.crickettechnology.com/
DLファイル内の以下にドキュメントがあります。この後の説明で度々登場するので存在を覚えておいてください。
cricket-1.5.0/doc/Cricket.html
Bank soundsファイルの作成
オンメモリ上で再生するサウンドは .ckb ファイルとしてまとめての利用となります。
.ckbファイル作成用の設定ファイルの作成
利用対象の音声ファイルを設定ファイルに記述します。
サウンドファイルと同じディレクトリにて、.ckbxファイル(本エントリーでは samplesounds.ckbx)を以下のようにXML形式で作成します。
<?xml version="1.0" encoding="utf-8" ?> <bank name="samplesounds"> <sound name="se_click" source="se_click.wav" /> <sound name="se_cancel" source="se_cancel.wav" /> </bank>
bank name はファイル名と合わせると分り易くなります。sound name に1ファイルずつ記載する必要があります。
1つの要素に対し、属性に「変換フォーマット/pan/ループ回数/ループ開始・終了位置」等が設定可能です。詳しくは以下の「Sound attributes」項目を参照ください。
cricket-1.5.0/doc/manual/cktool.html
Stream soundsファイルの作成
ストリーミング再生するサウンドは1ファイルずつ独自形式に出力して使用するか、前述したmp3等のエンコード済みファイルをそのまま利用します。
独自形式に変換したい場合は以下のようにします。
$ cktool buildstream -format adpcm bgm_stage1.wav bgm_stage1.cks
iOSの環境設定
Xcodeへのファイル追加
以下をプロジェクトの任意ディレクトリへコピーし、Xcode上で追加しておきます。
- cricket-1.5.0/inc/ck
- cricket-1.5.0/lib/ios/Release/libck.a
TARGETS-Build Settingsの「Header Search Paths」に inc フォルダへのパスを追加し、「Library Search Paths」に lib フォルダへのパスを追加します。
framework追加
追加するframeworkは以下になります。
- CoreMedia.framework
- AVFoundation.framework
- MediaPlayer.framework
Androidの環境設定
Android.mkを以下のようにします。
LOCAL_PATH := $(call my-dir) #------------------------------------------------------------- # specify libck as a "prebuilt" static library include $(CLEAR_VARS) LOCAL_MODULE := ck ifeq ($(NDK_DEBUG),1) LOCAL_SRC_FILES := ../lib/cricker/$(TARGET_ARCH_ABI)/debug/libck.a else LOCAL_SRC_FILES := ../lib/cricker/$(TARGET_ARCH_ABI)/release/libck.a endif include $(PREBUILT_STATIC_LIBRARY) #------------------------------------------------------------- include $(CLEAR_VARS) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/external) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/cocos) LOCAL_MODULE += cocos2dcpp_shared LOCAL_MODULE_FILENAME := libcocos2dcpp LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../Classes/AppDelegate.cpp \ ../../Classes/HelloWorldScene.cpp \ ../../Classes/CricketAndroidJni.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../Classes/lib # _COCOS_HEADER_ANDROID_BEGIN # _COCOS_HEADER_ANDROID_END LOCAL_STATIC_LIBRARIES := cocos2dx_static LOCAL_STATIC_LIBRARIES += ck cpufeatures # _COCOS_LIB_ANDROID_BEGIN # _COCOS_LIB_ANDROID_END LOCAL_LDLIBS += -llog -landroid include $(BUILD_SHARED_LIBRARY) $(call import-module,.) $(call import-module,android/cpufeatures) # _COCOS_LIB_IMPORT_ANDROID_BEGIN # _COCOS_LIB_IMPORT_ANDROID_END
Cocos2dx v3.7 で新規作成した状態に、以下に記載されている内容を書いたものになっています。
cricket-1.5.0/doc/manual/building.html#building_for_android_ndk
C++での実装
公式のサンプルコードほぼそのままですが、以下のように実装します。
BGM/SEをそのまま流すだけの方法
見やすいようにグローバル変数にしていませんが、適当に読み替えてください。
#include "ck/ck.h" #include "ck/config.h" #include "ck/bank.h" #include "ck/sound.h" CkBank* _bank; CkSound* _soundEffect; CkSound* _music; ///////////////// 中略 ///////////////// /* 再生 */ #if CK_PLATFORM_ANDROID // Androidでの初期化はAppActivity.javaにて行っている #else CkConfig config; CkInit(&config); #endif // Bank sounds ファイルの再生 _bank = CkBank::newBank("samplesounds.ckb"); _soundEffect = CkSound::newBankSound(_bank, "se_click"); // 別関数にてckbxで設定したindex番号でも呼び出し可能 _soundEffect->play(); // Stream sounds ファイルの再生 _music = CkSound::newStreamSound("bgm_stage1.cks"); _music->setLoopCount(-1); _music->play(); ///////////////// 中略 ///////////////// void MainScene::update(float delta) { CkUpdate(); // Stream sounds再生を行うのに必須関数 } ///////////////// 中略 ///////////////// /* 解放 */ _soundEffect->destroy(); _music->destroy(); _bank->destroy(); CkShutdown();
Androidの初期化はContextが必要なのでAppActivity.javaに書きました。もしかしてら微妙な方法かもしれませんので、もっと良い方法があればコメントで教えて下さい。
public class AppActivity extends Cocos2dxActivity { private static native void initCricket(Context context); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppActivity.initCricket(this.getApplicationContext()); } }
// CricketAndroidJni.h #include <jni.h> #ifndef __ANDROID_JNI__ #define __ANDROID_JNI__ #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_initCricket(JNIEnv *, jobject obj, jobject thiz); #ifdef __cplusplus } #endif #endif __ANDROID_JNI__
// CricketAndroidJni.cpp #include "CricketAndroidJni.h" #include "ck/ck.h" #include "ck/config.h" JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_initCricket(JNIEnv *env, jobject obj, jobject thiz) { CkConfig config(env, thiz); CkInit(&config); }
サウンドのミックス処理
音声ファイル毎にグループを作り、特定条件下で指定グループの音量を調整する事が出来ます。
※前コードと重複する箇所は省略しています。
#include "ck/mixer.h" CkMixer* _mixer; ///////////////// 中略 ///////////////// // bgmグループを作成 _mixer = CkMixer::newMixer("bgm"); _mixer->setParent(CkMixer::getMaster()); _mixer->setVolume(1.0f); // 前コードで作成した_sound変数をbgmグループに所属させます _sound->setMixer(_mixer); ///////////////// 中略 ///////////////// // bgmグループの音量を下げる(他効果音を目立たせる使用例) _mixer->setVolume(0.2f); auto seSound = CkSound::newBankSound(_bank, "se_fire"); seSound->play(); ///////////////// 中略 ///////////////// // bgmグループの音量を何かしらのタイミングで戻します(今回は効果音再生完了後を契機とする) void MainScene::update(float delta) { if (!seSound->isPlaying()) { _mixer->setVolume(1.0f); } } ///////////////// 中略 ///////////////// /* 解放 */ _mixer->destroy();
CkSoundはsetMixerで何も設定していない場合、CkMixer::getMaster() に所属しています。MasterはMixerのrootであり、rootの下に作成したMixerをぶら下げて管理する事になります。
子Mixerは親Mixerの音量変更に対して影響する為、管理の際にはその点に注意が必要です。
サウンドのエフェクト処理
Bank/Stream Soundsに対してフィルターを掛ける事が出来ます。
CkEffect* _effect; ///////////////// 中略 ///////////////// // エフェクト _effect = CkEffect::newEffect(kCkEffectType_BiquadFilter); CkEffectBus* bus = CkEffectBus::newEffectBus(); bus->addEffect(_effect); _music->setEffectBus(bus); ///////////////// 中略 ///////////////// /* 解放 */ _effect->destroy()
kCkEffectTypeには4種類あり、それぞれ以下のようになっています。
kCkEffectType | 効果 |
---|---|
kCkEffectType_BiquadFilter | 音が篭って聞こえる |
kCkEffectType_BitCrusher | 8bitサウンドのように聞こえる(ノイズが入る) |
kCkEffectType_RingMod | リングモジュレーターを掛けます |
kCkEffectType_Distortion | ディストーションエフェクトを掛けます |