VolumeShaper で振幅を制御する

オーディオ アプリで VolumeShaper を使用すると、フェードイン、フェードアウト、クロスフェード、ダッキングなどの短時間の自動音量切り替えを行うことができます。VolumeShaper クラスは Android 8.0(API レベル 26)以降で使用できます。

VolumeShaper を作成するには、AudioTrack または MediaPlayer のインスタンスに対して createVolumeShaper() を呼び出します。VolumeShaper は AudioTrack または MediaPlayer で作成された音声にのみ作用します。

VolumeShaper.Configuration

VolumeShaper の動作はその VolumeShaper.Configuration で定義します。この設定では、「音量カーブ、補間タイプ、および時間」を指定します。

音量カーブ

音量カーブは、振幅(音量)の経時的な変化を表します。一連のコントロール ポイントを定義する float 型配列 x[] と y[] のペアで音量カーブが定義されます。(x, y) の各ペアはそれぞれ時間と音量を表します。2 つの配列は同じ長さで、2~16 個の値を含める必要があります(カーブの最大長は getMaximumCurvePoints() で規定されます)。

時間座標の区間は [0.0, 1.0] です。最初の時点が 0.0、最後の時点が 1.0 で、時間の値は単調増加します。

音量座標は、区間 [0.0, 1.0] にわたって等間隔で指定します。

補間タイプ

音量カーブは指定されたコントロール ポイントを必ず通ります。コントロール ポイント間の値は、設定されている補間タイプに応じたスプラインによって計算されます。VolumeShaper 補間タイプとして指定可能な 4 つの定数は以下のとおりです。

  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_STEP
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC_MONOTONIC

時間

区間 [0.0, 1.0] で指定された時間座標は、ミリ秒で指定する実際の時間にスケーリングされます。これにより、シェイパーが実行中に音量カーブを音声出力に適用するときの、そのカーブの実際の長さが決まります。

VolumeShaper を使用する

設定を作成する

VolumeShaper を構築する前に VolumeShaper.Configuration のインスタンスを作成する必要があります。それには VolumeShaper.Configuration.Builder() を使用します。

Kotlin

    val config: VolumeShaper.Configuration = VolumeShaper.Configuration.Builder()
            .setDuration(3000)
            .setCurve(floatArrayOf(0f, 1f), floatArrayOf(0f, 1f))
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
            .build()
    

Java

    VolumeShaper.Configuration config =
      new VolumeShaper.Configuration.Builder()
          .setDuration(3000)
          .setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f})
          .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
          .build();
    

引数がない場合、VolumeShaper.Configuration.Builder コンストラクタは、デフォルト設定を使って設定を作成するビルダーを返します。デフォルト設定は、INTERPOLATOR_TYPE_CUBIC、長さは 1 秒、カーブはなしです。build() を呼び出す前にビルダーにカーブを指定する必要があります。

このフレームワークには、あらかじめ作成されたカーブを使用する設定用に以下の定数があり、長さはそれぞれ 1 秒です。

  • VolumeShaper.Configuration.LINEAR_RAMP
  • VolumeShaper.Configuration.CUBIC_RAMP
  • VolumeShaper.Configuration.SINE_RAMP
  • VolumeShaper.Configuration.SCURVE_RAMP

VolumeShaper を作成する

VolumeShaper を作成するには、該当するクラスのインスタンスで createVolumeShaper() を呼び出して、VolumeShaper.Configuration を渡します。

Kotlin

    volumeShaper = myMediaPlayer.createVolumeShaper(config)
    volumeShaper = myAudioTrack.createVolumeShaper(config)
    

Java

    volumeShaper = myMediaPlayer.createVolumeShaper(config);
    volumeShaper = myAudioTrack.createVolumeShaper(config);
    

1 つのトラックまたはメディア プレーヤーに多数のシェイパーを指定でき、各シェイパーを個別にコントロールできます。1 つのトラックまたはプレーヤーのすべてのシェイパーの出力が多重化されます。VolumeShaper を複数の AudioTracks または MediaPlayers で共有することはできませんが、createVolumeShaper への呼び出しに同じ設定を使って、複数の AudioTracks または MediaPlayers 上に同等のシェイパーを作成できます。

シェイパーを作成するには、始点のコントロール ポイント(t = 0)を音声ストリームに適用します。初期値が 1.0 ではなく、その作成時にアプリがコンテンツを再生中の場合、音量が急に変わることがあります。おすすめの方法としては、無音状態から音声の再生を開始し、VolumeShaper を使って音声の開始時にフェードインを実装します。音量が 0 から開始してフェードアップする VolumeShaper を作成します。たとえば次のように指定します。

setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f})
    

再生とこのシェイパーを同時に開始します。これにより、無音状態から再生が始まり、音量が最大まで徐々に大きくなります。これについては次のセクションで説明します。

VolumeShaper を実行する

シェイパーが作成されるとすぐに、始点のコントロール ポイントの音量が音声パスに適用されますが、VolumeShaper.Operation.PLAY を指定して apply() メソッドを呼び出すまで、シェイパーがカーブに沿って進行することはありません。シェイパーを作成した後、シェイパーを開始するために、apply() の最初の呼び出しで PLAY オペレーションを指定する必要があります。それにより、カーブの始点のコントロール ポイントから終点のコントロール ポイントまで実行されます。

Kotlin

    shaper.apply(VolumeShaper.Operation.PLAY)
    

Java

    shaper.apply(VolumeShaper.Operation.PLAY);
    

シェイパーの実行中に、REVERSE オペレーションまたは PLAY オペレーションを指定して実行を変更する apply() を呼び出すことができます。そのたびに、コントロール ポイントを読み出す方向が変わります。

シェイパーは音量を連続して調整し、すべてのコントロール ポイントを最後まで通過します。最後は、シェイパーがカーブの終点(PLAY オペレーションの場合)または始点(REVERSE オペレーションの場合)のコントロール ポイントに達したときです。

シェイパーが最後に達した後、音量は最後の設定のまま(始点または終点のコントロール ポイントの音量)になります。いつでも VolumeShaper.getVolume() を呼び出して現時点の音量を取得できます。

シェイパーが最後に達した後に再度 apply() を呼び出して、反対方向にカーブを実行できます。たとえば、PLAY でシェイパーが最後に達した場合は、次の apply()REVERSE にする必要があります。PLAY の後に PLAY を呼び出したり、REVERSE の後に REVERSE を呼び出したりしても、効果はありません。

PLAY オペレーションと REVERSE オペレーションは交互に行う必要があります。始点のコントロール ポイントから終点のコントロール ポイントまでカーブを再生した後に、また始点のコントロール ポイントから再開する方法はありません。次のセクションで説明する replace() メソッドを使って、カーブをそのコピーと置き換えることができます。これによりシェイパーがリセットされるので、もう一度開始するには、PLAY オペレーションが必要です。

カーブを変更する

VolumeShaper のカーブを変更するには、replace() メソッドを使用します。このメソッドには、設定、オペレーション、join パラメータを指定します。replace() メソッドは、シェイパーの実行中か、終了後にいつでも呼び出せます。

Kotlin

    val newConfig = VolumeShaper.Configuration.Builder()
            .setDuration(1000)
            .setCurve(floatArrayOf(0f, 0.5f), floatArrayOf(0f, 1f))
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
            .build()
    val join = true
    shaper.replace(newConfig, VolumeShaper.Operation.PLAY, join)
    

Java

    VolumeShaper.Configuration newConfig =
      new VolumeShaper.Configuration.Builder()
        .setDuration(1000)
        .setCurve(new float[] {0.f, 0.5f}, new float[] {0.f, 1.f})
        .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
        .build();
    boolean join = true;
    shaper.replace(newConfig, VolumeShaper.Operation.PLAY, join);
    

シェイパーの実行中に replace() を呼び出すと、音量の変更は停止し、現在の値のままになります。次に、シェイパーは新しいカーブを始点のコントロール ポイントから開始します。つまり、シェイパーのオペレーション引数が、呼び出し後にシェイパーを実行するかどうかをコントロールします。PLAY を指定すると、新しいカーブがすぐに開始されます。REVERSE を指定すると、シェイパーは新しいカーブの始点のコントロール ポイントの音量で停止します。このシェイパーは後で apply(VolumeShaper.Operation.PLAY) によって開始できます。

join = false を指定して replace() を呼び出すと、シェイパーは始点のコントロール ポイントで指定された音量でカーブを開始します。これにより、音量が不連続になることがあります。これを避けるには、join = true を指定して replace() を呼び出します。これにより、新しいカーブの始点のコントロール ポイントはシェイパーの現在の音量に設定されます。さらに、始点から終点の間にあるすべてのコントロール ポイントの音量がスケーリングされ、新しいカーブの相対的な形は維持されます(終点のコントロール ポイントは変更されません)。このスケーリング オペレーションによって、シェイパーの新しいカーブのコントロール ポイントは永続的に変更されます。

VolumeShaper を削除する

AudioTrack または MediaPlayer が解放されるか、使用されなくなると、システムは VolumeShaper を終了してガベージ コレクションを行います。シェイパーをすぐに破棄するには、close() メソッドを呼び出します。システムは約 20 ms 以内にオーディオ パイプラインからシェイパーを削除します。音声の再生中に VolumeShaper を終了する際には注意してください。シェイパーの音量が 1.0 より小さい場合、close() を呼び出すとシェイパーの音量スケールは 1.0 に変わります。それによって、音量が急激に大きくなることがあります。