VolumeShaper로 진폭 제어

오디오 앱에서 VolumeShaper를 사용하여 페이드 인, 페이드 아웃, 크로스 페이드, 더킹 및 기타 짧은 자동 볼륨 전환을 실행할 수 있습니다. VolumeShaper 클래스는 Android 8.0(API 레벨 26) 이상에서 사용할 수 있습니다.

AudioTrack 또는 MediaPlayer 인스턴스에서 createVolumeShaper()를 호출하여 VolumeShaper를 만듭니다. VolumeShaper는 이 클래스를 만든 AudioTrack 또는 MediaPlayer에서 생성된 오디오에만 영향을 줍니다.

VolumeShaper.Configuration

VolumeShaper의 동작은 VolumeShaper.Configuration에 의해 정의됩니다. 이 구성에 따라 *볼륨 곡선, 보간기 유형 지속 시간*이 지정됩니다.

볼륨 곡선

볼륨 곡선은 시간에 따른 진폭 변화를 나타냅니다. 볼륨 곡선은 일련의 제어점을 정의하는 한 쌍의 부동소수점 배열, x [] 및 y []로 정의됩니다. 각 (x, y) 쌍은 시간과 볼륨을 나타냅니다. 배열은 길이가 같고 최소 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()
    

자바

    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)
    

자바

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

단일 트랙 또는 미디어 플레이어에 셰이퍼를 여러 개 연결할 수 있고 각 셰이퍼를 따로따로 조정할 수 있습니다. 트랙 또는 플레이어의 모든 셰이퍼 출력은 함께 곱해집니다. AudioTracks 간에 또는 MediaPlayers 간에 VolumeShaper를 공유할 수는 없지만 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() 메서드를 호출할 때까지 셰이프는 곡선을 따라 진행되지 않습니다. 셰이퍼를 만든 후 셰이퍼를 시작하려면 첫 번째 PLAY 호출에 apply() 연산을 지정해야 합니다. 그러면 첫 번째 제어점에서 마지막 제어점까지 곡선이 실행됩니다.

Kotlin

    shaper.apply(VolumeShaper.Operation.PLAY)
    

자바

    shaper.apply(VolumeShaper.Operation.PLAY);
    

셰이퍼가 실행되는 동안 REVERSE 연산과 PLAY 연산을 지정하는 apply() 호출을 번갈아 실행할 수 있습니다. 이렇게 하면 매번 제어점의 판독 방향이 바뀝니다.

셰이퍼는 만료될까지 지속적으로 볼륨을 조정하고 모든 제어점을 통과합니다. 만료는 셰이퍼가 곡선의 마지막 제어점(PLAY 연산의 경우) 또는 첫 번째 제어점(REVERSE 연산의 경우)에 도달하면 발생합니다.

셰이퍼가 만료되면 볼륨은 마지막 설정, 즉 첫 번째 또는 마지막 제어점으로 유지됩니다. 언제든지 VolumeShaper.getVolume()을 호출하여 현재 볼륨 수준을 획득할 수 있습니다.

셰이퍼가 만료되면 apply() 호출을 한 번 더 실행하여 곡선을 반대 방향으로 실행할 수 있습니다. 예를 들어 PLAY 실행 중에 셰이퍼가 만료된 경우 그다음 apply()는 반드시 REVERSE여야 합니다. PLAY가 만료된 후에 PLAY를 호출하거나 REVERSE가 만료된 후에 REVERSE를 호출하는 것은 아무런 효과가 없습니다.

PLAYREVERSE 연산을 번갈아 수행해야 합니다. 곡선을 첫 번째 제어점에서 마지막 제어점까지 재생한 다음 첫 번째 제어점에서 다시 시작하는 방법은 없습니다. 다음 섹션에 설명된 replace() 메서드를 사용하여 곡선을 그 곡선의 사본으로 대체할 수는 있습니다. 그러면 셰이퍼가 재설정되고 PLAY 연산에 곡선을 다시 시작하도록 요구됩니다.

곡선 변경

VolumeShaper의 곡선을 변경하려면 replace() 메서드를 사용합니다. 이 메서드는 구성, 연산, 조인 매개변수를 취합니다. 셰이퍼가 실행 중이거나 만료되면 언제든지 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)
    

자바

    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()를 호출하면 셰이프는 첫 번째 제어점으로 지정된 수준에서 곡선을 시작합니다. 이로 인해 볼륨이 불연속적일 수 있습니다. 이를 방지하려면 replace()로 설정한 상태에서 join = true를 호출하면 됩니다. 그러면 새 곡선의 첫 번째 제어점이 셰이퍼의 현재 수준으로 설정되고, 첫 번째 제어점과 마지막 제어점 사이의 모든 제어점의 볼륨이 새 곡선의 상대적인 형태를 유지하도록 조정됩니다(마지막 제어점은 변하지 않음). 조정 연산으로 셰이퍼의 새 곡선에 있는 제어점이 영구히 변경됩니다.

VolumeShaper 제거

AudioTrack 또는 MediaPlayer가 해제되거나 더 이상 사용되지 않으면 시스템이 종료되고 가비지가 VolumeShaper를 수집합니다. 셰이퍼에 close() 메서드를 호출하여 셰이퍼를 즉시 제거할 수 있습니다. 셰이퍼는 약 20밀리초 이내에 오디오 파이프라인에서 삭제됩니다. 오디오 재생 중에 VolumeShaper를 닫을 때는 유의하세요. 셰이퍼의 볼륨이 1.0 미만일 때 close()를 호출하면 셰이퍼의 볼륨 스케일이 1.0으로 변경됩니다. 따라서 볼륨이 갑자기 커질 수 있습니다.