我正在尝试使用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;
}
一些注意事项:
decoder->samplesPerFrame
和numSamples
,但我无法获得令人满意的输出。1
,而将“音高偏移”设置为0
,则声音将无缝播放。 更新1:
经过更多的篡改并以不同的采样值值播放之后,我认为问题必然出在音频输出(DAC MAN)期望的采样数量与实际outputBuffers->nextSliceItem
的采样数量之间提供。
话虽如此,我可以想到一种缓解此问题的方法,那就是将outputBuffers->nextSliceItem
的输出附加到临时缓冲区,然后在达到阈值时将其定向到音频输出。
第二个问题:在C ++中是否可以将缓冲区追加到另一个缓冲区?
答案 0 :(得分:3)
您需要输出audioProcessing(int numberOfFrames)帧数。因此,在outputBuffers-> makeSlice中,您需要询问numberOfFrames,而不是outputBuffers-> sampleLength(基本上是在询问“ outputBuffers中的任何帧数”,而不是“ numberOfFrames”)。
然后您从float转换为int,然后又转换回float?这没有道理。您在timeStretchedAudio中获得了浮点音频,录音机可以立即对其进行处理。
那之后,在将一些浮点样本转换为音频后,您忘了将“音频”向前移动。
最后,您从outputBuffers中删除了所有音频,而只需要删除输出为“音频”的帧数。