如何改变音频音调?
How to change audio pitch?
我正在使用 Oboe C++ 库在我的 android 应用程序中播放声音。
我想改变我的音频样本的音高。
所以,我开始创建“mPos”浮点值来保存当前播放的帧,并在每一步添加“mPitch”值。
使用新音高似乎可以正确播放音频,但当音高较高(例如 1.2)时它本身会加倍并发出奇怪的噪音,而当音高较低时(例如 0.212)。
这是我第一次做音频节目,
在 post 这个问题之前,我做了很多研究。我什至直接向 "Oboe" 支持人员发送消息,但没有回复。
有谁知道如何正确实施 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;
};
当您将浮点变量 (mPos) 乘以整数类型变量 (channelCount) 时,结果是浮点数。至少,您弄乱了频道交错。而不是
(size_t)(mPos * channelCount)
尝试
((size_t)mPos) * channelCount
编辑:
您在到达结尾时故意循环源代码,使用导致 mPos = 0;
的 if 语句。您可以独立于音高计算源样本的数量,而不是这样做,但是当您的源样本用完时跳出循环。此外,由于音高调整,您对源样本和目标样本的比较没有用:
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;
}
}
但是,为了完整起见,请注意:对于任何严肃的应用程序,您真的不应该以这种方式完成音高变化——音质会很糟糕。有免费的库可以将音频重采样到任意目标速率;这些会将您的源样本转换为更多或更少数量的样本,并在以与源相同的速率重放时提供高质量的音高变化。
我正在使用 Oboe C++ 库在我的 android 应用程序中播放声音。 我想改变我的音频样本的音高。 所以,我开始创建“mPos”浮点值来保存当前播放的帧,并在每一步添加“mPitch”值。
使用新音高似乎可以正确播放音频,但当音高较高(例如 1.2)时它本身会加倍并发出奇怪的噪音,而当音高较低时(例如 0.212)。
这是我第一次做音频节目, 在 post 这个问题之前,我做了很多研究。我什至直接向 "Oboe" 支持人员发送消息,但没有回复。 有谁知道如何正确实施 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;
};
当您将浮点变量 (mPos) 乘以整数类型变量 (channelCount) 时,结果是浮点数。至少,您弄乱了频道交错。而不是
(size_t)(mPos * channelCount)
尝试
((size_t)mPos) * channelCount
编辑:
您在到达结尾时故意循环源代码,使用导致 mPos = 0;
的 if 语句。您可以独立于音高计算源样本的数量,而不是这样做,但是当您的源样本用完时跳出循环。此外,由于音高调整,您对源样本和目标样本的比较没有用:
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;
}
}
但是,为了完整起见,请注意:对于任何严肃的应用程序,您真的不应该以这种方式完成音高变化——音质会很糟糕。有免费的库可以将音频重采样到任意目标速率;这些会将您的源样本转换为更多或更少数量的样本,并在以与源相同的速率重放时提供高质量的音高变化。