【发布时间】:2019-03-24 16:17:44
【问题描述】:
我正在尝试使用Superpowered SDK 对正在播放和同时录制的 mp3 文件应用实时时间拉伸和音高转换。问题是,无论我做什么,输出的声音质量都很糟糕(到了失真的地步)。
我怀疑这是由于每个帧号的样本冲突。这是我的cpp文件的完整源代码:
static SuperpoweredAndroidAudioIO *audioIO;
static SuperpoweredTimeStretching *stretching;
static SuperpoweredAudiopointerList *outputBuffers;
static SuperpoweredDecoder *decoder;
static SuperpoweredRecorder *recorder;
const char *outFilePath;
const char *tempFilePath;
static short int *intBuffer;
static float *playerBuffer;
bool audioInitialized = false;
bool playing = false;
static bool audioProcessing(
void *__unused clientData, // custom pointer
short int *audio, // buffer of interleaved samples
int numberOfFrames, // number of frames to process
int __unused sampleRate // sampling rate
) {
if (playing) {
unsigned int samplesDecoded = decoder->samplesPerFrame;
if (decoder->decode(intBuffer, &samplesDecoded) == SUPERPOWEREDDECODER_ERROR) return false;
if (samplesDecoded < 1) {
playing = false;
return false;
}
SuperpoweredAudiobufferlistElement inputBuffer;
inputBuffer.samplePosition = decoder->samplePosition;
inputBuffer.startSample = 0;
inputBuffer.samplesUsed = 0;
inputBuffer.endSample = samplesDecoded;
inputBuffer.buffers[0] = SuperpoweredAudiobufferPool::getBuffer(samplesDecoded * 8 + 64);
inputBuffer.buffers[1] = inputBuffer.buffers[2] = inputBuffer.buffers[3] = NULL;
SuperpoweredShortIntToFloat(intBuffer, (float *) inputBuffer.buffers[0], samplesDecoded);
stretching->process(&inputBuffer, outputBuffers);
if (outputBuffers->makeSlice(0, outputBuffers->sampleLength)) {
while (true) {
int numSamples = 0;
float *timeStretchedAudio = (float *) outputBuffers->nextSliceItem(&numSamples);
if (!timeStretchedAudio) break;
SuperpoweredFloatToShortInt(timeStretchedAudio, intBuffer,
(unsigned int) numSamples);
SuperpoweredShortIntToFloat(intBuffer, playerBuffer, (unsigned int) numSamples);
recorder->process(playerBuffer, (unsigned int) numSamples);
SuperpoweredFloatToShortInt(playerBuffer, audio, (unsigned int) numSamples);
};
outputBuffers->clear();
return true;
};
}
return false;
}
extern "C" JNIEXPORT void
Java_com_example_activities_DubsmashActivity_InitAudio(
JNIEnv __unused *env,
jobject __unused obj,
jint bufferSize,
jint sampleRate,
jstring outputPath,
jstring tempPath
) {
decoder = new SuperpoweredDecoder();
outputBuffers = new SuperpoweredAudiopointerList(8, 16);
outFilePath = env->GetStringUTFChars(outputPath, 0);
tempFilePath = env->GetStringUTFChars(tempPath, 0);
}
extern "C" JNIEXPORT jdouble
Java_com_example_activities_DubsmashActivity_OpenFile(
JNIEnv *env,
jobject __unused obj,
jstring filePath) {
const char *path = env->GetStringUTFChars(filePath, 0);
decoder->open(path);
intBuffer = (short int *) malloc(decoder->samplesPerFrame * 2 * sizeof(short int) + 32768);
playerBuffer = (float *) malloc(decoder->samplesPerFrame * 2 * sizeof(short int) + 32768);
audioIO = new SuperpoweredAndroidAudioIO(
decoder->samplerate,
decoder->samplesPerFrame,
false,
true,
audioProcessing,
NULL,
-1, -1,
decoder->samplesPerFrame * 2
);
stretching = new SuperpoweredTimeStretching(decoder->samplerate);
stretching->setRateAndPitchShift(1, 0);
recorder = new SuperpoweredRecorder(
tempFilePath,
decoder->samplerate,
1,
2,
false,
recorderStopped,
NULL
);
return 0;
}
需要考虑的一些注意事项:
- 这不是 this question 的副本,因为该线程中的解决方案对我不起作用
- 我尝试过使用
decoder->samplesPerFrame和numSamples,但我无法获得不错的输出。 - 如果我将 Time Stretching 设置为
1并将 Pitch Shift 设置为0,声音会无缝播放。
更新 1:
在对样本数量进行了更多篡改和使用不同值之后,我认为问题一定出在音频输出 (DAC MAN) 期望的样本数量与 outputBuffers->nextSliceItem 实际提供的数量之间的差异。
话虽如此,我可以想出一种方法来缓解这个问题,那就是将outputBuffers->nextSliceItem 的输出附加到一个临时缓冲区,然后当它达到阈值时,将其定向到音频输出。
因此我的第二个问题是:C++ 中有没有办法将缓冲区附加到另一个缓冲区?
【问题讨论】:
-
那是很多的代码。你有没有机会把它减少到 minimal reproducible example / SSCCE ?
-
@JesperJuhl,好的,刚刚从示例中删除了所有冗余代码。它现在应该更具可读性。
-
为什么在 C++ 程序中使用
malloc?除了明显的“手动内存管理是代码异味”注释之外,它(可能)从与new不同的堆分配,如果您比较指针或类似的东西,您只是为将来的问题做好准备。但是,已经使用智能指针了......所有这些原始指针真的很痛苦;永远不会通过(我的)代码审查。 -
@JesperJuhl,那是因为我不是 C++ 程序员,老实说我不知道你在说什么。我只是按照SDK作者发布的示例进行的。
-
@JesperJuhl "从不同的堆分配" ????只有一个堆......智能指针肯定不会通过我的代码审查,因为实时音频需要精确控制内存分配(因为阻塞),而老式分配提供了查看究竟发生了什么的最佳方法。
标签: android c++ android-ndk signal-processing superpowered