【问题标题】:How to change audio pitch?如何更改音频音高?
【发布时间】:2020-03-30 16:37:27
【问题描述】:

我正在使用 Oboe C++ 库在我的 Android 应用程序中播放声音。 我想改变我的音频样本的音高。 因此,我开始创建“mPos”浮点值来保存当前播放的帧,并在每一步添加“mPitch”值。

似乎使用新的音高可以正确播放音频,但是当音高高(例如 1.2)并发出奇怪的噪音以及音高低(例如 0.212)时,它是自身的两倍。

这是我第一次做音频节目, 在发布这个问题之前,我做了很多研究。我什至直接向“双簧管”支持发送消息但没有响应。 有谁知道如何正确实施 Pitch?

streamLength 总是 192

channelCount 总是 2

代码:

void Player::renderAudio(float *stream, int32_t streamLength){

    const int32_t channelCount = mSound->getChannelCount();

    if (mIsPlaying){

        float framesToRenderFromData = streamLength ;
        float totalSourceFrames = mSound->getTotalFrames()/mPitch;
        const float *data = mSound->getData();

        // Check whether we're about to reach the end of the recording
        if (mPos + streamLength >= totalSourceFrames ){
            framesToRenderFromData = (totalSourceFrames - mPos);
            mIsPlaying = false;
        }
        for (int i = 0; i < framesToRenderFromData; ++i) {
            for (int j = 0; j < channelCount; ++j) {
                if(j % 2 == 0){
                    stream[(i*channelCount)+j] = (data[((size_t)mPos * channelCount)) + j] * mLeftVol) * mVol;
                }else{
                    stream[(i*channelCount)+j] = (data[((size_t)mPos * channelCount)) + j] * mRightVol) * mVol;
                }
            }
            mPos += mPitch;
            if(mPos >= totalSourceFrames){
                mPos = 0;
            }
        }
        if (framesToRenderFromData < streamLength){
            renderSilence(&stream[(size_t)framesToRenderFromData], streamLength * channelCount);
        }
    } else {
        renderSilence(stream, streamLength * channelCount);
    }
}

void Player::renderSilence(float *start, int32_t numSamples){
    for (int i = 0; i < numSamples; ++i) {
        start[i] = 0;
    }
}

void Player::setPitch(float pitchData){
    mPitch = pitchData;
};

【问题讨论】:

    标签: android c++ audio oboe


    【解决方案1】:

    当您将浮点变量 (mPos) 与整数类型变量 (channelCount) 相乘时,结果为浮点数。至少,您正在搞乱您的频道交错。而不是

    (size_t)(mPos * channelCount)
    

    试试

    ((size_t)mPos) * channelCount
    

    编辑: 到达结尾时,您有意循环源代码,if 语句导致mPos = 0;。您可以独立于音高计算源样本的数量,而不是这样做,但是当源样本用完时会跳出循环。此外,由于音高调整,您对源样本和目标样本的比较没有用处:

        float framesToRenderFromData = streamLength ;
        float totalSourceFrames = mSound->getTotalFrames();  // Note change here
        const float *data = mSound->getData();
    
        // Note: Only check here is whether mPos has reached the end from
        // a previous call
        if ( mPos >= totalSourceFrames ) {
            framesToRenderFromData = 0.0f;
        }
        for (int i = 0; i < framesToRenderFromData; ++i) {
           for (int j = 0; j < channelCount; ++j) {
               if(j % 2 == 0){
                    stream[(i*channelCount)+j] = (data[((size_t)mPos * channelCount)) + j] * mLeftVol) * mVol;
                }else{
                    stream[(i*channelCount)+j] = (data[((size_t)mPos * channelCount)) + j] * mRightVol) * mVol;
                }
            }
            mPos += mPitch;
            if ( ((size_t)mPos) >= totalSourceFrames ) {   // Replace this 'if' and its contents
                framesToRenderFromData = (size_t)mPos;
                mPos = 0.0f;
                break;
            }
        }
    

    但是,为了完整起见,请注意:对于任何严肃的应用,您真的不应该以这种方式完成音高变化 - 音质会很糟糕。有用于将音频重采样到任意目标速率的免费库;这些会将您的源样本转换为更多或更少数量的样本,并在以与源相同的速率重放时提供高质量的音调变化。

    【讨论】:

    • 谢谢,Charles,这确实解决了奇怪的噪音,但在某些示例中,当音高过高时,它会播放多次。也许我错过了 'if (mPos + streamLength >= totalSourceFrames ){' 行(检查我们是否即将到达录制的结尾)。
    • 谢谢,现在好多了!保持安全查尔斯:)
    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 2011-12-17
    相关资源
    最近更新 更多