cocos2d-x + ADX2でインタラクティブミュージックに挑戦する(前編)

  • 18
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

こんにちは@giginetです。Cocos2d-x Advent Calendar 2014の5日目を担当させて頂きます。よろしくお願いします。

追記 : 後編書きました C++ - cocos2d-x + ADX2でインタラクティブミュージックに挑戦する(後編) - Qiita

cocos2d-xでインタラクティブミュージックに挑戦

先月11月14日、株式会社CRI・ミドルウェアさんからオーディオライブラリ『ADX2』の無償版、『ADX2 LE』のcocos2d-x対応版の配付が開始されました。

cocos2d-xは音周りが非常に弱く、SimpleAudioEngineでの表現には限界があり、クロスプラットフォーム化の敷居も高かったです。

しかし、ADX2 LEを利用することで多才な音楽表現が簡単に扱えるようになりました。

また、従来ADX2を使うには多額のライセンス料を支払う必要がありましたが、今後は個人利用に限れば無償で利用することができるようになりました。

この記事では、cocos2d-xでADX2 LEを利用する方法を紹介します。また、ADX2の特徴的な機能であるブロック再生機能を使い、プログラム側から動的にメロディを遷移させてみます。

また、本記事ではcocos2d-x 3.2の利用を前提にしています。

詳しく知りたい方は

この記事では、ADX2 LE向けのGUIツールである『CRI Atom Craft』の詳しい使い方や、Androidへの組み込み方などを割愛しています。

もし、さらに詳しい情報が知りたい場合は、12月25日頃発売予定の拙著『cocos2d-xではじめるスマートフォンゲーム開発 [cocos2d-x Ver.3対応] for iOS/Android』をご覧ください。

Amazon.co.jp: cocos2d-xではじめるスマートフォンゲーム開発 [cocos2d-x Ver.3対応] for iOS/Android: 三木 康暉: 本

こちらの書籍では、開発元のCRI・ミドルウェアさんご協力の下、『ADX2 LE for cocos2d-x』の組み込み方と利用例を紹介しています。

ADX2とは何か

以下をご覧ください

CRI ADX2 LE とは - CRI Middleware

ADX2のサンプルプロジェクトをビルドする

ダウンロード - CRI Middleware

こちらからADX2 LE for cocos2d-xをダウンロードしてください。

ADX2 LEにはcocos2d-x向けの簡単なサンプルプロジェクトが含まれており、以下の手順でビルドすることができます。

  1. cocos newコマンドで新規プロジェクトを作成する
  2. 新規プロジェクトのcocos2dディレクトリをコピーする
  3. 解凍したZIPのcocos2dx/samples/criatom/programs/AtomSamplescocos2dディレクトリをペーストする
  4. proj.ios_mac/AtomSamples.xcodeprojを開き、ビルドする

これでiOS用のサンプルプロジェクトがビルドできます。

これでADX2の基本的な動きを知ることができます。

ADX2 LEを自分のプロジェクトに組み込む

初期設定

今度はADX2 LEを自分のプロジェクトに組み込んでみましょう。

基本的にサンプルプロジェクトのソースコードを読めば組み込めるはずですが、初期化処理などが冗長で組み込むのが大変なので、説明の簡略化のため、簡単に利用できるラッパークラスをご用意しました。

giginet/CCADX2Manager

以下の手順に従って組み込んでください。

  1. ダウンロードしたcri/cocos2dx以下のincludelibsを自分のプロジェクト化に組み込む(ここではClasses/adx2以下に置いた)
  2. プロジェクト設定のHeader Search PathLibrary Search Pathに上記のディレクトリへのパスを登録する(下記参照)
  3. Build Phases > Link Binary With Librariesにlibs以下のlibcri_ware_ios_LE.aを追加する
  4. 上記リポジトリから、ADX2Manager.hManage.h/cppCueSheet.h/cppをプロジェクトに組み込み、ビルド対象にする
  5. .acf, acb, .awbをResources以下に組み込む。今回はcri/cocos2dx/samples/criatom/programs/AtomSamples/Resources以下に含まれている物をそのまま使用する

それぞれのパスは以下のように設定すれば良いはず。

Header Search Path

$(SRCROOT)/../Classes/adx2/include/ios

Library Search Path

$(SRCROOT)/../Classes/adx2/libs/ios

コードを書く

ADX2Managerを利用してコードを書きます。

AppDelegate.cpp
#include "ADX2Manager.h"

USING_NS_CC;

AppDelegate::AppDelegate() {
    // ADX2を初期化します
    CriAtomExStandardVoicePoolConfig vp_config;
    criAtomExVoicePool_SetDefaultConfigForStandardVoicePool(&vp_config);
    vp_config.num_voices = 8;
    vp_config.player_config.streaming_flag = CRI_TRUE;
    vp_config.player_config.max_sampling_rate = 48000 << 1;

    CriAtomExPlayerConfig pf_config;
    criAtomExPlayer_SetDefaultConfig(&pf_config);
    pf_config.max_path_strings = 1;
    pf_config.max_path = 256;

    ADX2::Manager::initialize(pf_config, vp_config);
}

AppDelegate::~AppDelegate() 
{
    ADX2::Manager::finalize();
}
HelloWorldScene.h
#include "cocos2d.h"
#include "ADX2Manager.h"

class HelloWorld : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    HelloWorld();
    virtual ~HelloWorld();

    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);

    // implement the "static create()" method manually
    // CueSheetをメンバに持たせる
    CC_SYNTHESIZE_RETAIN(ADX2::CueSheet *, _cueSheet, CueSheet);
    CREATE_FUNC(HelloWorld);
};
HelloWorldScene.cpp
bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    // acf, acb, awbからCueSheetを読み込んでいる
    auto cueSheet = ADX2::CueSheet::create("ADX2_samples.acf", 
                                           "Basic.acb", 
                                           "Basic.awb");
    this->setCueSheet(cueSheet);
    // 「お誕生日おめでとうございます」を再生してる
    _cueSheet->playCueByID(2);

    return true;
}

HelloWorld::HelloWorld()
: _cueSheet(nullptr)
{
}

HelloWorld::~HelloWorld()
{
    CC_SAFE_RELEASE_NULL(_cueSheet);
}

これで可愛い女の子がお誕生日を祝ってくれると思います。うれしい!

繰り返しになりますが、ADX2Managerは俺俺クラスなので、自分で実装できる方は一から処理を書いた方が良いと思います。

CRI Atom Craftで音声データを作成する

ここではAdvent Calendarの内容を大きく逸脱してしまうため、これ以上の解説は扱いません。
以下のいずれかを参考にしてみてください。

追記:CRIの中の人の@Takaaki_Ichijoさんが解説記事を執筆してくださいました。詳細はこちらをご覧ください。

Unity - CRI Atom Craftで音声データを作成する - Qiita

ADX2 LEのブロック再生を使ってインタラクティブミュージックを実現する

という話を書こうと思ったのですが、一度に書くのに疲れてしまったし、全然準備もできてないので続きは後編で!

日がしばらく空きますが、12/16のAdvent Calendarで後編を投稿しようと思います。よろしくお願いします。

C++ - cocos2d-x + ADX2でインタラクティブミュージックに挑戦する(後編) - Qiita