如何使用 Superpowered 同时玩多个玩家
How to play multiple players simultaneously with Superpowered
我正在尝试制作一个基本的混音器应用程序,最多可同时播放 4 种声音。
这是我用来实现此目的的class:
#define log_print __android_log_print
static SuperpoweredAndroidAudioIO *audioIO;
static SuperpoweredAdvancedAudioPlayer *playerA, *playerB, *playerC, *playerD;
static float *floatBuffer;
// This is called periodically by the audio engine.
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(playerA->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerB->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerC->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerD->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
} else {
return false;
}
}
// Called by the playerA.
static void playerEventCallbackA (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerA->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackB (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerB->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackC (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerC->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackD (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerD->seek(0); // loop track
break;
default:;
};
}
// StartAudio - Start audio engine and initialize playerA.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_StartAudio (
JNIEnv * __unused env,
jobject __unused obj,
jint samplerate,
jint buffersize
) {
SuperpoweredInitialize(
"ExampleLicenseKey-WillExpire-OnNextUpdate",
false, // enableAudioAnalysis (using SuperpoweredAnalyzer, SuperpoweredLiveAnalyzer, SuperpoweredWaveform or SuperpoweredBandpassFilterbank)
false, // enableFFTAndFrequencyDomain (using SuperpoweredFrequencyDomain, SuperpoweredFFTComplex, SuperpoweredFFTReal or SuperpoweredPolarFFT)
false, // enableAudioTimeStretching (using SuperpoweredTimeStretching)
false, // enableAudioEffects (using any SuperpoweredFX class)
true, // enableAudioPlayerAndDecoder (using SuperpoweredAdvancedAudioPlayer or SuperpoweredDecoder)
false, // enableCryptographics (using Superpowered::RSAPublicKey, Superpowered::RSAPrivateKey, Superpowered::hasher or Superpowered::AES)
false // enableNetworking (using Superpowered::httpRequest)
);
// Allocate audio buffer.
floatBuffer = (float *)malloc(sizeof(float) * 2 * buffersize);
// Initialize playerA and pass callback function.
playerA = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerB = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerC = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerD = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize audio with audio callback function.
audioIO = new SuperpoweredAndroidAudioIO (
samplerate, // sampling rate
buffersize, // buffer size
false, // enableInput
true, // enableOutput
audioProcessing, // process callback function
NULL, // clientData
-1, // inputStreamType (-1 = default)
SL_ANDROID_STREAM_MEDIA // outputStreamType (-1 = default)
);
}
// OpenFile - Open file in playerA, specifying offset and length.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_OpenFile (
JNIEnv *env,
jobject __unused obj,
jstring path, // path to APK file
jint channelID // which player to use
) {
log_print(ANDROID_LOG_INFO, "Player", "~~CHECKPOINT: %d", channelID);
const char *str = env->GetStringUTFChars(path, 0);
switch (channelID) {
case 0:
playerA->open(str);
log_print(ANDROID_LOG_INFO, "Player", "~~Opening: %s", str);
break;
case 1:
playerB->open(str);
log_print(ANDROID_LOG_INFO, "Player", "~~Opening: %s", str);
break;
case 2:
playerC->open(str);
break;
case 3:
playerD->open(str);
break;
default: ;
}
env->ReleaseStringUTFChars(path, str);
}
// TogglePlayback - Toggle Play/Pause state of the playerA.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_TogglePlayback (
JNIEnv * __unused env,
jobject __unused obj,
jint channelID,
jboolean playing
) {
switch (channelID) {
case -1:
if(playing){
log_print(ANDROID_LOG_INFO, "Player", "~~PLAYING ALL: %d", channelID);
playerA->play(true);
playerB->play(true);
playerC->play(true);
playerD->play(true);
SuperpoweredCPU::setSustainedPerformanceMode(playerA->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerB->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerC->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerD->playing); // prevent dropouts
} else {
playerA->pause();
playerA->seek(0);
playerB->pause();
playerB->seek(0);
playerC->pause();
playerC->seek(0);
playerD->pause();
playerD->seek(0);
}
break;
case 0:
if(playing){
playerA->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerA->playing); // prevent dropouts
} else {
playerA->pause();
playerA->seek(0);
}
break;
case 1:
if(playing){
playerB->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerB->playing); // prevent dropouts
} else playerB->pause();
break;
case 2:
if(playing){
playerC->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerC->playing); // prevent dropouts
} else playerC->pause();
break;
case 3:
if(playing){
playerD->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerD->playing); // prevent dropouts
} else playerD->pause();
break;
default:;
}
}
// onBackground - Put audio processing to sleep.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_onBackground(
JNIEnv *__unused env,
jobject __unused obj
) {
audioIO->onBackground();
}
// onForeground - Resume audio processing.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_onForeground(
JNIEnv *__unused env,
jobject __unused obj
) {
audioIO->onForeground();
}
// Cleanup - Free resources.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_Cleanup(
JNIEnv *__unused env,
jobject __unused obj
) {
delete audioIO;
delete playerA;
delete playerB;
delete playerC;
delete playerD;
free(floatBuffer);
}
它对一首曲目非常有效。我可以录制声音,在播放器中打开它,让它播放和循环播放。但是,如果我在另一首曲目上录制并开始播放播放器 B,那么我从播放器 B 中听不到任何声音。我一次只能听到一首曲目。我知道我必须以某种方式将这些玩家合并到一个缓冲区中,但我不确定如何去做。现在它只是在每个背靠背上调用 player->play(false)。
我应该如何更改此代码以允许多个玩家同时 运行?
解决方案尝试 1
我没有对每个单元格中的 bufferAdd 值使用 true/false,而是简单地将调用本身用于另一个玩家。这些对 player->process() 的调用将 return 一个布尔值,它将被设置为下一次调用的 bufferAdd 值
if((playerD->process(floatBuffer, playerC->process(floatBuffer, playerB->process(floatBuffer, playerA->process(floatBuffer, false, (unsigned int)numberOfFrames), (unsigned int)numberOfFrames), (unsigned int)numberOfFrames) , (unsigned int)numberOfFrames)))
{
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
}
解决方案尝试 2
检查每个播放器的状态,如果正在处理则处理其他 3
if(playerA->process(floatBuffer, false, (unsigned int)numberOfFrames))
{
playerB->process(floatBuffer, true, (unsigned int)numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int)numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int)numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
} else if(playerB->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else if(playerC->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerB->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else if(playerD->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerB->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else return false;
- 在调用播放器[ABCD]->process() 的audioProcessing 函数中,始终调用每个播放器的process() 函数,无论处于何种状态。 (在您当前的代码中,如果前一个过程返回 true,则 || (OR) 运算符不会调用下一个 process()。)
- player->process的第二个参数叫做"bufferAdd"。如果为真,它将添加到缓冲区中的音频,如果为假,它将替换缓冲区的内容。 (在您当前的代码中它是 false,因此播放器不会混合在一起。)如果之前的任何播放器确实输出音频(从 process() 返回 true),则将 "bufferAdd" 设置为 true。因此只有第一个玩家的 bufferAdd 可以固定为 false,因为没有 "previous" 个玩家。
更优雅的解决方案可以是:
bool silence = playerA->process(floatBuffer, false, ...);
silence |= playerB->process(floatBuffer, !silence, ...);
silence |= playerC->process(floatBuffer, !silence, ...);
silence |= playerD->process(floatBuffer, !silence, ...);
@ConnorS 这是一个片段,它适用于 4 个玩家和一个 StereoMixer:
bool CrossExample::process(short int *output, unsigned int numberOfFrames, unsigned int samplerate) {
player1->outputSamplerate = player2->outputSamplerate = player3->outputSamplerate = player4->outputSamplerate;
// Get audio from the players into a buffer on the stack.
float outputBuffer[numberOfFrames * 2];
bool silence = player1->processStereo(outputBuffer, false, numberOfFrames, volA);
if (player2->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
if (player3->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
if (player4->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
mixer->process(outputBuffer,
NULL,
NULL,
NULL,
outputBuffer,
numberOfFrames);
};
// The output buffer is ready now, let's write the finished audio into the requested buffer.
if (!silence) Superpowered::FloatToShortInt(outputBuffer, output, numberOfFrames);
return !silence; //this equals true
}
我正在尝试制作一个基本的混音器应用程序,最多可同时播放 4 种声音。
这是我用来实现此目的的class:
#define log_print __android_log_print
static SuperpoweredAndroidAudioIO *audioIO;
static SuperpoweredAdvancedAudioPlayer *playerA, *playerB, *playerC, *playerD;
static float *floatBuffer;
// This is called periodically by the audio engine.
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(playerA->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerB->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerC->process(floatBuffer, false, (unsigned int)numberOfFrames)
|| playerD->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
} else {
return false;
}
}
// Called by the playerA.
static void playerEventCallbackA (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerA->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackB (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerB->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackC (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerC->seek(0); // loop track
break;
default:;
};
}
static void playerEventCallbackD (
void * __unused clientData,
SuperpoweredAdvancedAudioPlayerEvent event,
void *value
) {
switch (event) {
case SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess:
break;
case SuperpoweredAdvancedAudioPlayerEvent_LoadError:
log_print(ANDROID_LOG_ERROR, "Player", "Open error: %s", (char *)value);
break;
case SuperpoweredAdvancedAudioPlayerEvent_EOF:
playerD->seek(0); // loop track
break;
default:;
};
}
// StartAudio - Start audio engine and initialize playerA.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_StartAudio (
JNIEnv * __unused env,
jobject __unused obj,
jint samplerate,
jint buffersize
) {
SuperpoweredInitialize(
"ExampleLicenseKey-WillExpire-OnNextUpdate",
false, // enableAudioAnalysis (using SuperpoweredAnalyzer, SuperpoweredLiveAnalyzer, SuperpoweredWaveform or SuperpoweredBandpassFilterbank)
false, // enableFFTAndFrequencyDomain (using SuperpoweredFrequencyDomain, SuperpoweredFFTComplex, SuperpoweredFFTReal or SuperpoweredPolarFFT)
false, // enableAudioTimeStretching (using SuperpoweredTimeStretching)
false, // enableAudioEffects (using any SuperpoweredFX class)
true, // enableAudioPlayerAndDecoder (using SuperpoweredAdvancedAudioPlayer or SuperpoweredDecoder)
false, // enableCryptographics (using Superpowered::RSAPublicKey, Superpowered::RSAPrivateKey, Superpowered::hasher or Superpowered::AES)
false // enableNetworking (using Superpowered::httpRequest)
);
// Allocate audio buffer.
floatBuffer = (float *)malloc(sizeof(float) * 2 * buffersize);
// Initialize playerA and pass callback function.
playerA = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerB = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerC = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize playerA and pass callback function.
playerD = new SuperpoweredAdvancedAudioPlayer (
NULL, // clientData
playerEventCallbackA, // callback function
(unsigned int)samplerate, // sampling rate
0 // cachedPointCount
);
// Initialize audio with audio callback function.
audioIO = new SuperpoweredAndroidAudioIO (
samplerate, // sampling rate
buffersize, // buffer size
false, // enableInput
true, // enableOutput
audioProcessing, // process callback function
NULL, // clientData
-1, // inputStreamType (-1 = default)
SL_ANDROID_STREAM_MEDIA // outputStreamType (-1 = default)
);
}
// OpenFile - Open file in playerA, specifying offset and length.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_OpenFile (
JNIEnv *env,
jobject __unused obj,
jstring path, // path to APK file
jint channelID // which player to use
) {
log_print(ANDROID_LOG_INFO, "Player", "~~CHECKPOINT: %d", channelID);
const char *str = env->GetStringUTFChars(path, 0);
switch (channelID) {
case 0:
playerA->open(str);
log_print(ANDROID_LOG_INFO, "Player", "~~Opening: %s", str);
break;
case 1:
playerB->open(str);
log_print(ANDROID_LOG_INFO, "Player", "~~Opening: %s", str);
break;
case 2:
playerC->open(str);
break;
case 3:
playerD->open(str);
break;
default: ;
}
env->ReleaseStringUTFChars(path, str);
}
// TogglePlayback - Toggle Play/Pause state of the playerA.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_TogglePlayback (
JNIEnv * __unused env,
jobject __unused obj,
jint channelID,
jboolean playing
) {
switch (channelID) {
case -1:
if(playing){
log_print(ANDROID_LOG_INFO, "Player", "~~PLAYING ALL: %d", channelID);
playerA->play(true);
playerB->play(true);
playerC->play(true);
playerD->play(true);
SuperpoweredCPU::setSustainedPerformanceMode(playerA->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerB->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerC->playing); // prevent dropouts
SuperpoweredCPU::setSustainedPerformanceMode(playerD->playing); // prevent dropouts
} else {
playerA->pause();
playerA->seek(0);
playerB->pause();
playerB->seek(0);
playerC->pause();
playerC->seek(0);
playerD->pause();
playerD->seek(0);
}
break;
case 0:
if(playing){
playerA->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerA->playing); // prevent dropouts
} else {
playerA->pause();
playerA->seek(0);
}
break;
case 1:
if(playing){
playerB->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerB->playing); // prevent dropouts
} else playerB->pause();
break;
case 2:
if(playing){
playerC->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerC->playing); // prevent dropouts
} else playerC->pause();
break;
case 3:
if(playing){
playerD->play(false);
SuperpoweredCPU::setSustainedPerformanceMode(playerD->playing); // prevent dropouts
} else playerD->pause();
break;
default:;
}
}
// onBackground - Put audio processing to sleep.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_onBackground(
JNIEnv *__unused env,
jobject __unused obj
) {
audioIO->onBackground();
}
// onForeground - Resume audio processing.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_onForeground(
JNIEnv *__unused env,
jobject __unused obj
) {
audioIO->onForeground();
}
// Cleanup - Free resources.
extern "C" JNIEXPORT void
Java_com_connorschwing_CustomAudioManager_Cleanup(
JNIEnv *__unused env,
jobject __unused obj
) {
delete audioIO;
delete playerA;
delete playerB;
delete playerC;
delete playerD;
free(floatBuffer);
}
它对一首曲目非常有效。我可以录制声音,在播放器中打开它,让它播放和循环播放。但是,如果我在另一首曲目上录制并开始播放播放器 B,那么我从播放器 B 中听不到任何声音。我一次只能听到一首曲目。我知道我必须以某种方式将这些玩家合并到一个缓冲区中,但我不确定如何去做。现在它只是在每个背靠背上调用 player->play(false)。
我应该如何更改此代码以允许多个玩家同时 运行?
解决方案尝试 1 我没有对每个单元格中的 bufferAdd 值使用 true/false,而是简单地将调用本身用于另一个玩家。这些对 player->process() 的调用将 return 一个布尔值,它将被设置为下一次调用的 bufferAdd 值
if((playerD->process(floatBuffer, playerC->process(floatBuffer, playerB->process(floatBuffer, playerA->process(floatBuffer, false, (unsigned int)numberOfFrames), (unsigned int)numberOfFrames), (unsigned int)numberOfFrames) , (unsigned int)numberOfFrames)))
{
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
}
解决方案尝试 2 检查每个播放器的状态,如果正在处理则处理其他 3
if(playerA->process(floatBuffer, false, (unsigned int)numberOfFrames))
{
playerB->process(floatBuffer, true, (unsigned int)numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int)numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int)numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int)numberOfFrames);
return true;
} else if(playerB->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else if(playerC->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerB->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerD->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else if(playerD->process(floatBuffer, false, (unsigned int)numberOfFrames)) {
playerB->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerC->process(floatBuffer, true, (unsigned int) numberOfFrames);
playerA->process(floatBuffer, true, (unsigned int) numberOfFrames);
SuperpoweredFloatToShortInt(floatBuffer, audio, (unsigned int) numberOfFrames);
return true;
} else return false;
- 在调用播放器[ABCD]->process() 的audioProcessing 函数中,始终调用每个播放器的process() 函数,无论处于何种状态。 (在您当前的代码中,如果前一个过程返回 true,则 || (OR) 运算符不会调用下一个 process()。)
- player->process的第二个参数叫做"bufferAdd"。如果为真,它将添加到缓冲区中的音频,如果为假,它将替换缓冲区的内容。 (在您当前的代码中它是 false,因此播放器不会混合在一起。)如果之前的任何播放器确实输出音频(从 process() 返回 true),则将 "bufferAdd" 设置为 true。因此只有第一个玩家的 bufferAdd 可以固定为 false,因为没有 "previous" 个玩家。
更优雅的解决方案可以是:
bool silence = playerA->process(floatBuffer, false, ...);
silence |= playerB->process(floatBuffer, !silence, ...);
silence |= playerC->process(floatBuffer, !silence, ...);
silence |= playerD->process(floatBuffer, !silence, ...);
@ConnorS 这是一个片段,它适用于 4 个玩家和一个 StereoMixer:
bool CrossExample::process(short int *output, unsigned int numberOfFrames, unsigned int samplerate) {
player1->outputSamplerate = player2->outputSamplerate = player3->outputSamplerate = player4->outputSamplerate;
// Get audio from the players into a buffer on the stack.
float outputBuffer[numberOfFrames * 2];
bool silence = player1->processStereo(outputBuffer, false, numberOfFrames, volA);
if (player2->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
if (player3->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
if (player4->processStereo(outputBuffer, !silence, numberOfFrames, volA)) silence = false;
mixer->process(outputBuffer,
NULL,
NULL,
NULL,
outputBuffer,
numberOfFrames);
};
// The output buffer is ready now, let's write the finished audio into the requested buffer.
if (!silence) Superpowered::FloatToShortInt(outputBuffer, output, numberOfFrames);
return !silence; //this equals true
}