CRI ADXで音の高さを変えずに再生速度を変える・再生速度を変えずに音の高さを変える（タイムストレッチとピッチシフト）

# はじめに 「CRI ADX」について
「CRI ADX」はゲーム・XRコンテンツ開発用のサウンドライブラリとツールを同梱したSDKです。
サウンドの再生負荷軽減やAndroid端末における遅延軽減、イントロ付きループ再生やインタラクティブ・ミュージックなどのゲーム向けの音声・楽曲再生システムを持ちます。
有償のフル機能版と、小規模事業者・インディー向けの無償版があります（性能差はありません）。
ちなみに2021年に「ADX2」から「ADX」にブランド名称が変わりました。製品構成は一緒です。

- 統合型サウンドミドルウェアCRI ADX
https://game.criware.jp/products/adx/

- 無償版サウンドミドルウェアCRI ADX LE
https://game.criware.jp/products/adx-le/

はじめてADX / ADX LEを触る方は、以下の導入手順をご確認ください。

 - Unity編

https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

 - UE4編

https://qiita.com/SigRem/items/4250925f6d66a4fd287a

本エントリではUnityの場合の実装を紹介しますが、Unreal Engine 4でも同様の設定が可能です。

# 音高を変えずに再生速度を変化させる
ゲーム開発においてキャラクターのセリフを早送りしたり、逆にスローにするなどの演出をしたいと考えることは多いでしょう。
アドベンチャーパートの早送り演出ですとか、イベントのスキップ演出、重たい攻撃を食らったときなど、活用タイミングは多そうです。

サウンドデータは、何も考えずに再生速度を上げるとピッチ（音の高さ）が上がってしまい、高音になります。
そこでADXでは、「タイムストレッチ機能」（またはインサーションDSP）という、音の高さを変えずに早送り or スローにする機能があります。

## 「ボイス」概念について
タイムストレッチ機能の導入の前に、「ボイス」という概念について説明します。

ADXは音声データのデコードや音声の出力を"ボイス"という単位で処理します。ライブラリの初期化時に、あらかじめ再生する音声データに対応したボイス群を"ボイスプール"として作成します。

Unityプラグインにおいては、CriWareLibraryInitializerが自動的にボイスプールを作成してくれます。CriWareLibraryInitializerのインスペクタで、「Standard Voice Pool Config」という項目がありますが、ここで設定された値に従ってボイスプールが作成されます。

![ADXTimeStreachTest - SampleScene - Windows, Mac, L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/30d64830-15c1-be7e-8a11-d890d91ad84a.png)

これで「Standard Voice Pool (メモリ再生用）」ボイスプールが16個のボイスを持って生成されます。「Standard Voice Pool (ストリーミング再生用）」ボイスプールは8個のボイスです。

この設定で、メモリ再生をする際は最大16音まで同時に鳴らすことができ、ストリーミング再生の場合は最大8個です。オブジェクトプールと同じで、再生用スロットをあらかじめ作成しておいて、空いているものを使っていくイメージです。

## 再生速度を変えるためのボイスを作る
ADXにおいて、早送りやスロー再生はこの「ボイスプール」単位で処理されるため、専用のボイスプールを新しく生成する必要があります。
処理の流れは、

 1. 新しいボイスプールを作成する
 2. そのボイスプールにタイムストレッチ機能の設定をする
 3. CriAtomSourceに生成したボイスプールを使うように設定する
 4. 再生

となります。
なお、HCA-MX圧縮の音声には処理の都合上タイムストレッチを適用することができません。
プロジェクト全般でHCA-MXを使っている場合は、タイムストレッチを適用する音だけHCA圧縮にして使用するようにしてください。

CriAtomExVoicePool クラスについてのマニュアルは次の通りです。
https://game.criware.jp/manual/unity_plugin/latest/contents/classCriAtomExVoicePool.html

## タイムストレッチのサンプルコード
```TimeStretch.cs
public class TimeStretch : MonoBehaviour
{
    public CriAtomSource atomSource; //再生に使用するAtomSourceをアタッチ
    private CriAtomExVoicePool voicePool; //これから作るボイスプールの参照、フィールドで持ち続ける

    void Start()
    {
        //ボイスプールの作成
        //ボイス数1、2ch、再生する最大サンプリングレートの倍数（今回は48,000Hz x 2）、メモリ再生、idはとりあえず100
        voicePool = new CriAtomExStandardVoicePool(1, 2, 96000, false, 100);

        //DSPタイムストレッチをアタッチ
        voicePool.AttachDspTimeStretch();
        
        //作成したボイスプールをAtomSourceに指定
        atomSource.player.SetVoicePoolIdentifier(voicePool.identifier);
        
        //0.5 = 1/2速設定にする
        atomSource.player.SetDspTimeStretchRatio (0.5f);
        
        //再生
        atomSource.Play();
    }

    private void OnDestroy()
    {
        //ボイスプールの破棄
        voicePool.Dispose();
    }
}
```

複数の音声データを同時に流したい場合は、CriAtomExStandardVoicePoolクラス生成時の最初の引数に数を設定してください。
タイムストレッチ機能を使用する場合は、ボイスプール生成時の最大サンプリングレートを2倍にしておく必要があります。

再生速度として設定できる範囲は0.5f ～ 2.0fです。

なお、音声再生中に実行すると、音途切れ等の不具合が発生する可能性があります。シーン読み込み時など、負荷変動を許容できるタイミングで行う必要があります。

# 再生速度を変えずに音の高さを変更する
タイムシフトは、音の高さを変えずに再生速度を変化させるものです。逆に、再生速度を維持したまま音の高さを変更させることもできます。
これを「ピッチシフト」といい、ほぼ同じ手順で導入できます。

## ピッチシフトのサンプルコード
```PitchShift.cs
public class PitchShift: MonoBehaviour
{
    public CriAtomSource atomSource;
    private CriAtomExVoicePool voicePool;

    void Start()
    {
        //ボイスプールの作成
        //ボイス数１、2ch、サンプリングレートは48000Hz、メモリ再生、idはとりあえず100
        voicePool = new CriAtomExStandardVoicePool(1, 2, 48000, false, 100);

        //DSPピッチシフトをボーカルモードでアタッチ
        voicePool.AttachDspPitchShifter(CriAtomExVoicePool.PitchShifterMode.Speech);
        
        //作成したボイスプールをAtomSourceに指定
        atomSource.player.SetVoicePoolIdentifier(voicePool.identifier);
        
        //単位セント。1200で約2倍の高さ
        atomSource.player.SetDspPitchShifterPitch(1200);
        
        //再生
        atomSource.Play();
    }

    private void OnDestroy()
    {
        //ボイスプールは必ず破棄
        voicePool.Dispose();
    }
}
```

SetDspTimeStretchRatio
https://game.criware.jp/manual/unity_plugin/latest/contents/classCriAtomExPlayer.html#ae618ebdc03e17d628efd9c976dbfecdc

ピッチシフトの単位はセントです。設定可能な値の範囲は -2400 ～ 2400 までで、原音と比べて 1200 で 2倍、-1200 で 1/2倍 のピッチシフトになります。
ピッチシフトにはモード選択があり、セリフ用のSpeech、楽曲用のmusic、ボーカル用のVocal、効果音用のSoundEffectがあります。

また、ピッチシフトはAtom Craft側でDSPバスに設定することも可能です。
https://game.criware.jp/manual/adx2_tool/latest/criatom_tools_atomcraft_dsp_effect_pitch_shifter.html