掲題の通りです。
cocos2d-xにはAudioEngineとSimpleAudioEngineという二つのオーディオ制御モジュールが存在しますが、いずれもそれぞれ機能として不十分に感じたため、軽い制約で無料で使用できるCriket Audioを導入することにしてみたので、導入までの備忘としてメモしておきます。
なお、この記事は以下のサイトを参考にしてます。とても詳しく解説してくれてますし、この記事はそれをただぼくの環境用に(本当に備忘として)書き換えてるだけなので、こちらを参考にする方がいいかもです。
Cocos2dxで Cricket Audio を使ってみる
とりあえずぼくの環境とか
環境によってビルド方法とか変わるとも思うんで、先に載せておきます。
- OS:Mac OS X
- PC:MacBook Pro (13-inch, Mid 2012)
- 前提:cocos2d-x v3のプロジェクトが既に作成済
また、フォルダ構成は以下のようにします。
/Users/[アカウント名] └-> dist └-> cocos2dprojects | -> 3.10 | └-> 今回のプロジェクト | └-> cocos2d-xのプロジェクト | | -> proj.ios_mac | | -> proj.android-studio | └> 以下省略 └-> tools └> Criket Audioを解凍したフォルダ
Criketのアカウント作成&ダウンロード
以下からダウンロードできます。
http://www.crickettechnology.com/free_license
使用する際の規約が載ってますが、ざっくり言うと(きっと)以下のことが書かれてます。
- (アプリのクレジット画面なんかに) このエンジン使ってること書いてよね!
- べっ別にこのsvg画像やpng画像使ってくれてもいいんだからね///
- 他の人に無断配布しちゃダメなんだからね!
- 他のSDKとかに無断で入れちゃダメだよ!そういうライセンスじゃないんだからね! (もし追加のライセンスオプションがほしいなら…問い合わせしてよね!)
- アプリリリースする時はここに載せたいからちゃんと報告してよね!
- もっもしクレジット出したくないならちゃんとお金払ってよね!
この2番目、3番目の理由でcocos2d-xには入ってないんでしょうね。
で、ダウンロードページは一番下のリンクにあります。
アカウント登録も必要なので、登録してダウンロードします。
ZIPファイルを解凍
ダウンロードしたZIPファイルを解凍すると、以下のようなフォルダ構成になってます。
- binフォルダーーcktoolという専用オーディオファイルを作成するツールを格納
- buildフォルダーーなんだろね(きっとbuildするフォルダだろうね)
- docフォルダーードキュメントが入ってます
- incフォルダーーSDKのヘッダファイルが入ってます
- libフォルダーー実際に使用するプログラムが入ってます
- srcフォルダーーサンプルプログラムが入ってます
主に使うのは「bin」「inc」「lib」フォルダです。
とりあえず上記に書いたように配置し、binフォルダにはパスを通しておきます。
// .bash_profile export CRIKET_ROOT=/Users/[アカウント]/dist/cocos2dprojects/tools/criket-1.6.1/bin/macosx export PATH=$CRIKET_ROOT:$PATH
iOS側の設定
Frameworkの追加
General -> 「Linked Frameworks and Libraries」から追加します。
追加するものは以下の通りです。
- CoreMedia.framework
- AVFoundation.framework
- MediaPlayer.framework
Header Search Pathsを追加
Build Settings -> Header Search Pathsに、解凍したファイルの「inc」フォルダまでのパスを追加します。
Library Search Paths内にモジュールを追加
同様に、Build Settings -> Library Search Paths 内に、以下のパスを追加します。
【Debug】「Clicket Audioフォルダ/lib/ios/Debug」
【Release】「Clicket Audioフォルダ/lib/ios/Release」
Other Linker Flagsの設定
Build Settings -> Linking -> Other Linker Flags内に以下を追加します。
「-lck」
とりあえずこの時点でビルドしてみて、特にエラーにならなければ(たぶん)大丈夫です。
Android側の設定(Android Studio)
こういう類の設定でいつもめんどっちいのがAndroid側ですね。
今回もその例に漏れずにめんどくさいのですが、サンプルもあるのでそれを見ながらだとたぶんできると思います。
JNIファイルの作成
以下のようなファイルを作成します。
#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__
#include "CriketJni.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); }
Java側との連携
proj.android-studio/app/src/org/cocos2dx/cpp/AppActivity.java内に以下のように記述します。
package org.cocos2dx.cpp; import android.os.Bundle; import android.content.Context; import org.cocos2dx.lib.Cocos2dxActivity; 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()); } }
Android.mkの修正
続いて、android-studio側の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 := ../../../../../../tools/cricket-1.6.1/lib/android/ndk/$(TARGET_ARCH_ABI)/debug/libck.a else LOCAL_SRC_FILES := ../../../../../../tools/cricket-1.6.1/lib/android/ndk/$(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) $(call import-add-path,$(LOCAL_PATH)/../../../Classes) $(call import-add-path,$(LOCAL_PATH)/../../../Classes/common/libs) $(call import-add-path,$(LOCAL_PATH)/../../../../../../tools) LOCAL_MODULE := cocos2dcpp_shared LOCAL_MODULE_FILENAME := libcocos2dcpp CPP_FILES := $(shell find $(LOCAL_PATH)/../../../Classes -name *.cpp) CPP_FILES += $(shell find $(LOCAL_PATH)/../../../Classes -name *.c) LOCAL_SRC_FILES := hellocpp/main.cpp LOCAL_SRC_FILES += $(CPP_FILES:$(LOCAL_PATH)/%=%) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../Classes/common/libs LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../../../tools/cricket-1.6.1/inc # _COCOS_HEADER_ANDROID_BEGIN # _COCOS_HEADER_ANDROID_END LOCAL_STATIC_LIBRARIES := cocos2dx_static LOCAL_STATIC_LIBRARIES += crypto ssl LOCAL_STATIC_LIBRARIES += ck cpufeatures # _COCOS_LIB_ANDROID_BEGIN # _COCOS_LIB_ANDROID_END include $(BUILD_SHARED_LIBRARY) $(call import-module,.) $(call import-module,openssl/Android) $(call import-module,android/cpufeatures) # _COCOS_LIB_IMPORT_ANDROID_BEGIN # _COCOS_LIB_IMPORT_ANDROID_END
ハイライト部分がCriketとの連携用の記述です。
やたらと「../」が多いですが、それは上に書いたようなフォルダ構成にしてるからです。
はっきり言ってわかりづらいのでこんなフォルダ構成にはしないほうがよさげですね。バージョン管理もしづらそうだし。
あとは、ビルドしてみてエラーにならなければたぶんうまくいってます。
cktoolでcriket用の音楽ファイルを作成してみる。
とりあえず、環境ができたら次はリソースを作ってみます。
基本的にはwavファイルしか対応してないみたいですので、以下のソフトを使ってmp3などは先にwavファイルに変換します。
http://www.audacityteam.org/
(素材を使う場合は加工OKかどうか確かめてからね)
効果音の作成
複数の音楽ファイルを一つにして使うみたいです。
音楽ファイルと同様の部分に、XMLファイル(拡張子:ckbx)を作成します。
<?xml vertion="1.0" encoding="utf-8" ?> <bank name="soundEffect"> <sound name="shot" source="ファイル名.wav"/> </bank>
あとは、ビルドします。
$ cktool buildbank soundeffects.ckbx
すると、soundeffects.ckbというファイルが出来上がります。これが利用するリソースになります。
BGM用ファイルの作成
こちらはひとつずつやるみたいです。
こちらもwabに変換してから行います。
$ cktool buildstream -format adpcm bgm1.wav bgm1.cks
ただ、BGM(ストリーム再生)用のは、そのままmp3などの状態でも使用できるみたいです。
使ってみる
さて、ここまできたら後は使うだけですね。
初期化とか
AppDelegate等に以下のように入れます。
#include "ck/bank.h" #include "ck/ck.h" #include "ck/config.h" #include "ck/sound.h" // その他は省略 bool AppDelegate::applicationDidFinishLaunching() { // (省略) #if CK_PLATFORM_ANDROID // Androig側はAppActivityにて実施 #else // CkConfig config; CkInit(&config); #endif // (省略) // 毎回Updateを呼び出す // これを呼び出さないと再生とかされません。 auto schedule = Director::getInstance()->getScheduler(); schedule->schedule([](float f) { CkUpdate(); }, this, 0.016, CC_REPEAT_FOREVER, 0.0, false, "sounds"); } void AppDelegate::applicationDidEnterBackground() { Director::getInstance()->stopAnimation(); // 全てのサウンドを止める CkSuspend(); } void AppDelegate::applicationWillEnterForeground() { Director::getInstance()->startAnimation(); // 全てのサウンドを再開 CkResume(); } AppDelegate::~AppDelegate() { // シャットダウン。 // 実際はここではなくアプリ終了するメソッドなどを作成してやる方がいいと思ふ。 CkShutdown(); }
実際に使う
こんな感じに使います。
// 効果音の初期化 CKBank* bank = CkBank::newBank("soundeffects.ckb"); // 効果音を出す CKSound* sound = CkSound::newBankSound(m_bank, "shot"); sound->play(); // BGMを流す CKSound* bgm = CkSound::newStreamSound("bgm.cks"); bgm->play(); bgm->setLoopCount(-1);
なお、使い終わったらそれぞれ自分で解放する必要があります。
// 解放する bgm->destroy(); sound->destroy(); bank->destroy();
このようにメモリ管理も自分でしないといけないので、
AudioManagerクラスみたいにそれぞれのインスタンスを管理するクラスを作成したほうがいいですね。