使用 Superpowered Audio Kit 在音轨之间正确转换
Proper transition between audio tracks using Superpowered Audio Kit
我成功实现了音频播放,但经常出现一个问题,即从 JAVA 单击 "next song" 时会出现尖锐的听觉故障。这个声音故障大约过去了。大约 100 毫秒。并且在下一首歌曲开始播放之前更频繁地出现。
请务必注意:
我在每次播放结束时对每个变量 class 和 "free" 立体缓冲区 (setdestroyallthreads) 调用 "delete",然后在每次播放开始前调用 "process"(process) 方法。
从 Java 开始,过渡序列如下所示;
PlayerClass.setDestroyAllThreads( );
PlayerClass.open("new_path", sampleRate, bufferSize );
PlayerClass.play( );
这是我的片段;
static void playerEventCallbackA(void *clientData, SuperpoweredAdvancedAudioPlayerEvent event, void * __unused value) {
if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess) {
SuperpoweredAdvancedAudioPlayer *player = *((SuperpoweredAdvancedAudioPlayer **)clientData);
}else if (event == SuperpoweredAdvancedAudioPlayerEvent_EOF) {
playerBass->pause();
playerB->pause();
finishedPlaying = true;
}else if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadError) {
};
}
static bool audioProcessing(void *clientdata, short int *audioIO, int numberOfSamples, int __unused samplerate) {
return ((Eve *)clientdata)->process(audioIO, (unsigned int)numberOfSamples);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
Eve::Eve(const char *path,unsigned int samplerate,unsigned int buffersize) : activeFx(0), crossValue(0.0f), volBass(1.0f * headroom), volB(1.0f * headroom) {
stereoBuffer = (float *)memalign(16,(buffersize + 16) * sizeof(float) * 2);
playerBass = new SuperpoweredAdvancedAudioPlayer(&playerBass , playerEventCallbackA, samplerate, 0);
playerB = new SuperpoweredAdvancedAudioPlayer(&playerB, playerEventCallbackB, samplerate, 0);
filterb = new SuperpoweredFilter(SuperpoweredFilter_Resonant_Lowpass, samplerate*0.98);
spatializer = new SuperpoweredSpatializer(samplerate);
playerBass->open(path);
playerB->open(path);
finishedPlaying = false;
playerBass->syncMode = playerB->syncMode = SuperpoweredAdvancedAudioPlayerSyncMode_TempoAndBeat;
audioSystem = new SuperpoweredAndroidAudioIO(samplerate, buffersize, false, true, audioProcessing, this, -1, SL_ANDROID_STREAM_MEDIA, buffersize * 2);
}
Eve::~Eve() {
delete playerBass;
delete playerB;
delete spatializer;
delete filterb;
delete audioSystem;
finishedPlaying = false, playingNow = false, pausedNow = false, processed = false, hd = false;
}
void Eve::onPlay() {
playerBass->play(false);
playerB->play(false);
playingNow = true;
}
void Eve::setBassValue(int bass) {
filterb->setResonantParameters(floatToFrequency(0.2f),ebass);
filterb->enable(true);
}
void Eve::setDestroyAllThreads(){
delete playerBass;
delete playerB;
delete spatializer;
delete filterb;
delete audioSystem;
finishedPlaying = false, playingNow = false, pausedNow = false, processed = false, hd = false;
}
bool Eve::process(short int *output, unsigned int numberOfSamples) {
bool masterIsA = (crossValue <= 0.5f);
double masterBpm = masterIsA ? playerBass->currentBpm : playerB->currentBpm;
double msElapsedSinceLastBeatA = playerBass->msElapsedSinceLastBeat;
bool silence = !playerBass->process(stereoBuffer, false, numberOfSamples*1, volBass, masterBpm, playerB->msElapsedSinceLastBeat);
processed = true;
filterb->process(stereoBuffer, stereoBuffer, numberOfSamples);
if (playerB->process(stereoBuffer, !silence, numberOfSamples, volB, masterBpm, msElapsedSinceLastBeatA)) silence = false;
spatializer->process(stereoBuffer, stereoBuffer, (float*)output, (float*)output, numberOfSamples, true);
SuperpoweredFloatToShortInt(stereoBuffer, output, numberOfSamples);
return !silence;
}
static Eve *eve = NULL;
extern "C" JNIEXPORT void Java_com_EvePlayer_Eve(JNIEnv *javaEnvironment, jobject self, jstring songPath, jint samplerate, jint buffersize) {
const char *path = javaEnvironment->GetStringUTFChars(songPath, JNI_FALSE);
eve = new Eve(path,(unsigned int)samplerate,(unsigned int)buffersize);
javaEnvironment->ReleaseStringUTFChars(songPath, path);
}
extern "C" JNIEXPORT void Java_com_EvePlayer_SetTempFolder(JNIEnv *javaEnvironment, jobject __unused obj, jstring path) {
const char *str = javaEnvironment->GetStringUTFChars(path, 0);
SuperpoweredAdvancedAudioPlayer::setTempFolder(str);
javaEnvironment->ReleaseStringUTFChars(path, str);
}
extern "C" JNIEXPORT void Java_com_EvePlayer_evePlay(JNIEnv *javaEnvironment, jobject self){
eve->onPlay();
}
extern "C" JNIEXPORT void Java_com_EvePlayer_setDestroyAllThreads(JNIEnv *javaEnvironment, jobject self) {
eve->setDestroyAllThreads();
}
首先销毁音频 I/O(在您的代码中为 "audioSystem")。音频I/O会周期性调用你的音频处理回调,所以需要先销毁它,否则会使用删除的对象。
我成功实现了音频播放,但经常出现一个问题,即从 JAVA 单击 "next song" 时会出现尖锐的听觉故障。这个声音故障大约过去了。大约 100 毫秒。并且在下一首歌曲开始播放之前更频繁地出现。
请务必注意: 我在每次播放结束时对每个变量 class 和 "free" 立体缓冲区 (setdestroyallthreads) 调用 "delete",然后在每次播放开始前调用 "process"(process) 方法。
从 Java 开始,过渡序列如下所示;
PlayerClass.setDestroyAllThreads( );
PlayerClass.open("new_path", sampleRate, bufferSize );
PlayerClass.play( );
这是我的片段;
static void playerEventCallbackA(void *clientData, SuperpoweredAdvancedAudioPlayerEvent event, void * __unused value) {
if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess) {
SuperpoweredAdvancedAudioPlayer *player = *((SuperpoweredAdvancedAudioPlayer **)clientData);
}else if (event == SuperpoweredAdvancedAudioPlayerEvent_EOF) {
playerBass->pause();
playerB->pause();
finishedPlaying = true;
}else if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadError) {
};
}
static bool audioProcessing(void *clientdata, short int *audioIO, int numberOfSamples, int __unused samplerate) {
return ((Eve *)clientdata)->process(audioIO, (unsigned int)numberOfSamples);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
Eve::Eve(const char *path,unsigned int samplerate,unsigned int buffersize) : activeFx(0), crossValue(0.0f), volBass(1.0f * headroom), volB(1.0f * headroom) {
stereoBuffer = (float *)memalign(16,(buffersize + 16) * sizeof(float) * 2);
playerBass = new SuperpoweredAdvancedAudioPlayer(&playerBass , playerEventCallbackA, samplerate, 0);
playerB = new SuperpoweredAdvancedAudioPlayer(&playerB, playerEventCallbackB, samplerate, 0);
filterb = new SuperpoweredFilter(SuperpoweredFilter_Resonant_Lowpass, samplerate*0.98);
spatializer = new SuperpoweredSpatializer(samplerate);
playerBass->open(path);
playerB->open(path);
finishedPlaying = false;
playerBass->syncMode = playerB->syncMode = SuperpoweredAdvancedAudioPlayerSyncMode_TempoAndBeat;
audioSystem = new SuperpoweredAndroidAudioIO(samplerate, buffersize, false, true, audioProcessing, this, -1, SL_ANDROID_STREAM_MEDIA, buffersize * 2);
}
Eve::~Eve() {
delete playerBass;
delete playerB;
delete spatializer;
delete filterb;
delete audioSystem;
finishedPlaying = false, playingNow = false, pausedNow = false, processed = false, hd = false;
}
void Eve::onPlay() {
playerBass->play(false);
playerB->play(false);
playingNow = true;
}
void Eve::setBassValue(int bass) {
filterb->setResonantParameters(floatToFrequency(0.2f),ebass);
filterb->enable(true);
}
void Eve::setDestroyAllThreads(){
delete playerBass;
delete playerB;
delete spatializer;
delete filterb;
delete audioSystem;
finishedPlaying = false, playingNow = false, pausedNow = false, processed = false, hd = false;
}
bool Eve::process(short int *output, unsigned int numberOfSamples) {
bool masterIsA = (crossValue <= 0.5f);
double masterBpm = masterIsA ? playerBass->currentBpm : playerB->currentBpm;
double msElapsedSinceLastBeatA = playerBass->msElapsedSinceLastBeat;
bool silence = !playerBass->process(stereoBuffer, false, numberOfSamples*1, volBass, masterBpm, playerB->msElapsedSinceLastBeat);
processed = true;
filterb->process(stereoBuffer, stereoBuffer, numberOfSamples);
if (playerB->process(stereoBuffer, !silence, numberOfSamples, volB, masterBpm, msElapsedSinceLastBeatA)) silence = false;
spatializer->process(stereoBuffer, stereoBuffer, (float*)output, (float*)output, numberOfSamples, true);
SuperpoweredFloatToShortInt(stereoBuffer, output, numberOfSamples);
return !silence;
}
static Eve *eve = NULL;
extern "C" JNIEXPORT void Java_com_EvePlayer_Eve(JNIEnv *javaEnvironment, jobject self, jstring songPath, jint samplerate, jint buffersize) {
const char *path = javaEnvironment->GetStringUTFChars(songPath, JNI_FALSE);
eve = new Eve(path,(unsigned int)samplerate,(unsigned int)buffersize);
javaEnvironment->ReleaseStringUTFChars(songPath, path);
}
extern "C" JNIEXPORT void Java_com_EvePlayer_SetTempFolder(JNIEnv *javaEnvironment, jobject __unused obj, jstring path) {
const char *str = javaEnvironment->GetStringUTFChars(path, 0);
SuperpoweredAdvancedAudioPlayer::setTempFolder(str);
javaEnvironment->ReleaseStringUTFChars(path, str);
}
extern "C" JNIEXPORT void Java_com_EvePlayer_evePlay(JNIEnv *javaEnvironment, jobject self){
eve->onPlay();
}
extern "C" JNIEXPORT void Java_com_EvePlayer_setDestroyAllThreads(JNIEnv *javaEnvironment, jobject self) {
eve->setDestroyAllThreads();
}
首先销毁音频 I/O(在您的代码中为 "audioSystem")。音频I/O会周期性调用你的音频处理回调,所以需要先销毁它,否则会使用删除的对象。