Skip to content

Commit

Permalink
Generalize SonicAudioProcessor in AudioTrack into a PSTSAudioProcesso…
Browse files Browse the repository at this point in the history
…r. A custom audio processor that does pitch-shifting and time stretching needs to be passed as the LAST AudioProcessor to a MediaCodecAudioRenderer / AudioTrack for it to replace the default Sonic implementation.
  • Loading branch information
brAzzi64 committed Aug 13, 2017
1 parent 2f8c31d commit 521de57
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public InvalidAudioTrackTimestampException(String detailMessage) {
private static final int MIN_TIMESTAMP_SAMPLE_INTERVAL_US = 500000;

/**
* The minimum number of output bytes from {@link #sonicAudioProcessor} at which the speedup is
* The minimum number of output bytes from {@link #pstsAudioProcessor} at which the speedup is
* calculated using the input/output byte counts from the processor, rather than using the
* current playback parameters speed.
*/
Expand All @@ -279,7 +279,7 @@ public InvalidAudioTrackTimestampException(String detailMessage) {

private final AudioCapabilities audioCapabilities;
private final ChannelMappingAudioProcessor channelMappingAudioProcessor;
private final SonicAudioProcessor sonicAudioProcessor;
private final PSTSAudioProcessor pstsAudioProcessor;
private final AudioProcessor[] availableAudioProcessors;
private final Listener listener;
private final ConditionVariable releasingConditionVariable;
Expand Down Expand Up @@ -373,13 +373,33 @@ public AudioTrack(AudioCapabilities audioCapabilities, AudioProcessor[] audioPro
} else {
audioTrackUtil = new AudioTrackUtil();
}

// If the user wants one of their own processors to override Sonic as the
// Pitch Shifting & Time Stretching processor, they'll be passing it in the last position
PSTSAudioProcessor overridingPSTSProcessor = null;
if (audioProcessors.length > 0 && (audioProcessors[audioProcessors.length - 1] instanceof PSTSAudioProcessor)) {
overridingPSTSProcessor = (PSTSAudioProcessor) audioProcessors[audioProcessors.length - 1];
}

ResamplingAudioProcessor resamplingAudioProcessor = new ResamplingAudioProcessor();
channelMappingAudioProcessor = new ChannelMappingAudioProcessor();
sonicAudioProcessor = new SonicAudioProcessor();
availableAudioProcessors = new AudioProcessor[3 + audioProcessors.length];
availableAudioProcessors[0] = new ResamplingAudioProcessor();
availableAudioProcessors[1] = channelMappingAudioProcessor;
System.arraycopy(audioProcessors, 0, availableAudioProcessors, 2, audioProcessors.length);
availableAudioProcessors[2 + audioProcessors.length] = sonicAudioProcessor;

if (overridingPSTSProcessor == null) {
pstsAudioProcessor = new SonicAudioProcessor();
availableAudioProcessors = new AudioProcessor[3 + audioProcessors.length];
availableAudioProcessors[0] = resamplingAudioProcessor;
availableAudioProcessors[1] = channelMappingAudioProcessor;
System.arraycopy(audioProcessors, 0, availableAudioProcessors, 2, audioProcessors.length);
availableAudioProcessors[2 + audioProcessors.length] = pstsAudioProcessor;
} else {
pstsAudioProcessor = overridingPSTSProcessor;
availableAudioProcessors = new AudioProcessor[3 + audioProcessors.length - 1];
availableAudioProcessors[0] = resamplingAudioProcessor;
availableAudioProcessors[1] = channelMappingAudioProcessor;
System.arraycopy(audioProcessors, 0, availableAudioProcessors, 2, audioProcessors.length - 1);
availableAudioProcessors[2 + audioProcessors.length - 1] = pstsAudioProcessor; // copying it manually
}

playheadOffsets = new long[MAX_PLAYHEAD_OFFSET_COUNT];
volume = 1.0f;
startMediaTimeState = START_NOT_SET;
Expand Down Expand Up @@ -976,8 +996,8 @@ public PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParam
return this.playbackParameters;
}
playbackParameters = new PlaybackParameters(
sonicAudioProcessor.setSpeed(playbackParameters.speed),
sonicAudioProcessor.setPitch(playbackParameters.pitch));
pstsAudioProcessor.setSpeed(playbackParameters.speed),
pstsAudioProcessor.setPitch(playbackParameters.pitch));
PlaybackParameters lastSetPlaybackParameters =
drainingPlaybackParameters != null ? drainingPlaybackParameters
: !playbackParametersCheckpoints.isEmpty()
Expand Down Expand Up @@ -1219,10 +1239,10 @@ private long applySpeedup(long positionUs) {
}

if (playbackParametersCheckpoints.isEmpty()
&& sonicAudioProcessor.getOutputByteCount() >= SONIC_MIN_BYTES_FOR_SPEEDUP) {
&& pstsAudioProcessor.getOutputByteCount() >= SONIC_MIN_BYTES_FOR_SPEEDUP) {
return playbackParametersOffsetUs
+ Util.scaleLargeTimestamp(positionUs - playbackParametersPositionUs,
sonicAudioProcessor.getInputByteCount(), sonicAudioProcessor.getOutputByteCount());
pstsAudioProcessor.getInputByteCount(), pstsAudioProcessor.getOutputByteCount());
}

// We are playing drained data at a previous playback speed, or don't have enough bytes to
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.google.android.exoplayer2.audio;


public interface PSTSAudioProcessor extends AudioProcessor {

/**
* Sets the playback pitch. The new pitch will take effect after a call to {@link #flush()}.
*
* @param pitch The requested new pitch.
* @return The actual new pitch.
*/
float setPitch(float pitch);

/**
* Sets the playback speed. The new speed will take effect after a call to {@link #flush()}.
*
* @param speed The requested new playback speed.
* @return The actual new playback speed.
*/
float setSpeed(float speed);

/**
* Returns the number of bytes of input queued since the last call to {@link #flush()}.
*/
long getInputByteCount();

/**
* Returns the number of bytes of output dequeued since the last call to {@link #flush()}.
*/
long getOutputByteCount();
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
/**
* An {@link AudioProcessor} that uses the Sonic library to modify the speed/pitch of audio.
*/
public final class SonicAudioProcessor implements AudioProcessor {
public final class SonicAudioProcessor implements PSTSAudioProcessor {

/**
* The maximum allowed playback speed in {@link #setSpeed(float)}.
Expand Down Expand Up @@ -83,6 +83,7 @@ public SonicAudioProcessor() {
* @param speed The requested new playback speed.
* @return The actual new playback speed.
*/
@Override
public float setSpeed(float speed) {
this.speed = Util.constrainValue(speed, MINIMUM_SPEED, MAXIMUM_SPEED);
return this.speed;
Expand All @@ -94,6 +95,7 @@ public float setSpeed(float speed) {
* @param pitch The requested new pitch.
* @return The actual new pitch.
*/
@Override
public float setPitch(float pitch) {
this.pitch = Util.constrainValue(pitch, MINIMUM_PITCH, MAXIMUM_PITCH);
return pitch;
Expand All @@ -102,13 +104,15 @@ public float setPitch(float pitch) {
/**
* Returns the number of bytes of input queued since the last call to {@link #flush()}.
*/
@Override
public long getInputByteCount() {
return inputBytes;
}

/**
* Returns the number of bytes of output dequeued since the last call to {@link #flush()}.
*/
@Override
public long getOutputByteCount() {
return outputBytes;
}
Expand Down

0 comments on commit 521de57

Please sign in to comment.