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


こんにちは[@giginet](http://twitter.com/giginet/)です。[Cocos2d-x Advent Calendar 2014](http://qiita.com/advent-calendar/2014/cocos2d-x)の5日目を担当させて頂きます。よろしくお願いします。

<strong>追記</strong> : 後編書きました [C++ - cocos2d-x + ADX2でインタラクティブミュージックに挑戦する（後編） - Qiita](http://qiita.com/giginet/items/3b372be5c68b55e029f2)


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

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

![](http://gyazo.com/d65e3f86cc2e703367c1a760fa8a3c34.png)

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: 三木 康暉: 本](http://www.amazon.co.jp/exec/obidos/ASIN/4774170550/hatena-blog-22/)

![](http://gyazo.com/27b0338f516237024bf1fbaeb3ae1195.png)

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

## ADX2とは何か

以下をご覧ください

[CRI ADX2 LE とは - CRI Middleware](http://www.adx2le.com/product/index.html)


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

[ダウンロード - CRI Middleware](http://www.adx2le.com/download/index.html)

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


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

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



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

![](http://gyazo.com/58c99bc8aa62a0040228d96cbfb81eb4.png)

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

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

### 初期設定

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

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

[giginet/CCADX2Manager](https://github.com/giginet/CCADX2Manager)

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

1. ダウンロードした`cri/cocos2dx`以下の`include`と`libs`を自分のプロジェクト化に組み込む（ここでは`Classes/adx2`以下に置いた）
2. プロジェクト設定の`Header Search Path`と`Library Search Path`に上記のディレクトリへのパスを登録する（下記参照）
3. Build Phases > Link Binary With Librariesに`libs`以下の`libcri_ware_ios_LE.a`を追加する
4. 上記リポジトリから、`ADX2Manager.h`、`Manage.h/cpp`、`CueSheet.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`を利用してコードを書きます。

```cpp: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();
}
```

```cpp: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);
};
```

```cpp: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](http://qiita.com/Takaaki_Ichijo/items/705f8d3447f7c869df9d)


- [Amazon.co.jp: cocos2d-xではじめるスマートフォンゲーム開発 [cocos2d-x Ver.3対応] for iOS/Android: 三木 康暉: 本](http://www.amazon.co.jp/exec/obidos/ASIN/4774170550/hatena-blog-22/)
- [Amazon.co.jp: CD付 CRI ADX2で作るゲームサウンド制作ガイド: 内田 哉, 株式会社CRI・ミドルウェア: 本](http://www.amazon.co.jp/ADX2%E3%81%A7%E4%BD%9C%E3%82%8B%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%B5%E3%82%A6%E3%83%B3%E3%83%89%E5%88%B6%E4%BD%9C%E3%82%AC%E3%82%A4%E3%83%89-ADX2%E5%85%AC%E5%BC%8F%E3%82%AC%E3%82%A4%E3%83%89-Smart-Game-Developer/dp/479813208X)
- [CRIMiddleware - YouTube](https://www.youtube.com/user/CRIMiddleware/videos)
- [サウンド助け合い所 @ ウィキ - ADX2LE超初心者](http://www53.atwiki.jp/soundtasukeai/pages/25.html)

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

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

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

[C++ - cocos2d-x + ADX2でインタラクティブミュージックに挑戦する（後編） - Qiita](http://qiita.com/giginet/items/3b372be5c68b55e029f2)