Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26145643 authored by Andy Hung's avatar Andy Hung
Browse files

Work around lack of pitch adjustment in Timestretcher

Change-Id: I3e057b97c250a826133248b6aa1ff9ed677d88df
parent c44111b2
Loading
Loading
Loading
Loading
+40 −12
Original line number Diff line number Diff line
@@ -56,6 +56,24 @@ static int64_t getNowUs()
    return convertTimespecToUs(tv);
}

// FIXME: we don't use the pitch setting in the time stretcher (not working);
// instead we emulate it using our sample rate converter.
static const bool kFixPitch = true; // enable pitch fix
static inline uint32_t adjustSampleRate(uint32_t sampleRate, float pitch)
{
    return kFixPitch ? (sampleRate * pitch + 0.5) : sampleRate;
}

static inline float adjustSpeed(float speed, float pitch)
{
    return kFixPitch ? (speed / pitch) : speed;
}

static inline float adjustPitch(float pitch)
{
    return kFixPitch ? AUDIO_TIMESTRETCH_PITCH_NORMAL : pitch;
}

// Must match similar computation in createTrack_l in Threads.cpp.
// TODO: Move to a common library
static size_t calculateMinFrameCount(
@@ -703,13 +721,15 @@ status_t AudioTrack::setSampleRate(uint32_t rate)
    if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) {
        return NO_INIT;
    }
    if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
    // pitch is emulated by adjusting speed and sampleRate
    const uint32_t effectiveSampleRate = adjustSampleRate(rate, mPitch);
    if (rate == 0 || effectiveSampleRate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
        return BAD_VALUE;
    }
    // TODO: Should we also check if the buffer size is compatible?

    mSampleRate = rate;
    mProxy->setSampleRate(rate);
    mProxy->setSampleRate(effectiveSampleRate);

    return NO_ERROR;
}
@@ -739,12 +759,6 @@ uint32_t AudioTrack::getSampleRate() const

status_t AudioTrack::setPlaybackRate(float speed, float pitch)
{
    if (speed < AUDIO_TIMESTRETCH_SPEED_MIN
            || speed > AUDIO_TIMESTRETCH_SPEED_MAX
            || pitch < AUDIO_TIMESTRETCH_PITCH_MIN
            || pitch > AUDIO_TIMESTRETCH_PITCH_MAX) {
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (speed == mSpeed && pitch == mPitch) {
        return NO_ERROR;
@@ -755,14 +769,25 @@ status_t AudioTrack::setPlaybackRate(float speed, float pitch)
    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
        return INVALID_OPERATION;
    }
    // pitch is emulated by adjusting speed and sampleRate
    const uint32_t effectiveRate = adjustSampleRate(mSampleRate, pitch);
    const float effectiveSpeed = adjustSpeed(speed, pitch);
    const float effectivePitch = adjustPitch(pitch);
    if (effectiveSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
            || effectiveSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
            || effectivePitch < AUDIO_TIMESTRETCH_PITCH_MIN
            || effectivePitch > AUDIO_TIMESTRETCH_PITCH_MAX) {
        return BAD_VALUE;
    }
    // Check if the buffer size is compatible.
    if (!isSampleRateSpeedAllowed_l(mSampleRate, speed)) {
    if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
        ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch);
        return BAD_VALUE;
    }
    mSpeed = speed;
    mPitch = pitch;
    mProxy->setPlaybackRate(speed, pitch);
    mProxy->setPlaybackRate(effectiveSpeed, effectivePitch);
    mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate
    return NO_ERROR;
}

@@ -1317,8 +1342,11 @@ status_t AudioTrack::createTrack_l()
            gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT])));

    mProxy->setSendLevel(mSendLevel);
    mProxy->setSampleRate(mSampleRate);
    mProxy->setPlaybackRate(mSpeed, mPitch);
    const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPitch);
    const float effectiveSpeed = adjustSpeed(mSpeed, mPitch);
    const float effectivePitch = adjustPitch(mPitch);
    mProxy->setSampleRate(effectiveSampleRate);
    mProxy->setPlaybackRate(effectiveSpeed, effectivePitch);
    mProxy->setMinimum(mNotificationFramesAct);

    mDeathNotifier = new DeathNotifier(this);