使用AudioQueueServices同时播放(10+)

时间:2011-09-12 03:02:47

标签: iphone objective-c audioqueueservices

有人能告诉我这是如何为iPhone做的吗?我试图让游戏在同一时间播放大约12种声音,我无法弄清楚如何使用AudioQueueServices。我知道你必须初始化,添加缓冲区,播放它们并使用AudioQueueEnqueueBufferWithParameters来同时播放,但我不知道如何将其转换为代码。任何有此代码的人或可以向我解释的人都会很棒!

如果您听说过Tone Grid / Tone Board,那正是我想要做的。我知道Appstore中有一些应用程序可以执行此操作,但我不知道它是如何完成的。

TLDR;需要有关AudioQueueServices同时播放10+声音的帮助。

示例:

新播放

    if (isPlaying == NO) {
err = AudioQueueNewOutput (&streamFormat, AudioEngineOutputBufferCallback, self, nil, nil, 0, &outputQueue);
if (err != noErr) NSLog(@"AudioQueueNewOutput() error: %d", err);

排队缓冲区

outputBuffersToRewrite = 3;
bufferByteSize = (sampleRate > 16000)? 2176 : 512; // 40.5 Hz : 31.25 Hz 
for (i=0; i<3; i++) {
    err = AudioQueueAllocateBuffer (outputQueue, bufferByteSize, &buffer); 
    if (err == noErr) {
        [self generateTone: buffer];
        err = AudioQueueEnqueueBuffer (outputQueue, buffer, 0, nil);
        if (err != noErr) NSLog(@"AudioQueueEnqueueBuffer() error: %d", err);
    } else {
        NSLog(@"AudioQueueAllocateBuffer() error: %d", err); 
        return;
    }
}

开始播放

isPlaying = YES;
err = AudioQueueStart(outputQueue, nil);
if (err != noErr) { NSLog(@"AudioQueueStart() error: %d", err); isPlaying= NO; return; }
} else {
NSLog (@"Error: audio is already playing back.");

设置流格式字段

BOOL isHighSampleRate = (sampleRate > 16000);
int bufferByteSize;
AudioQueueBufferRef buffer;

AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = sampleRate;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
streamFormat.mBitsPerChannel = 16;
streamFormat.mChannelsPerFrame = 1;
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mFramesPerPacket = 1;
streamFormat.mReserved = 0;

3 个答案:

答案 0 :(得分:1)

AudioQueue可以同时播放声音。

来自苹果:

如何同时播放多个声音?

使用音频队列服务(AudioToolbox / AudioQueue.h)中的接口。为要播放的每个声音创建一个音频队列对象。然后使用AudioQueueEnqueueBufferWithParameters函数指定每个音频队列中第一个音频缓冲区的同时开始时间。

以下限制适用于iPhone OS中的同步声音,具体取决于音频数据格式:

  

AAC,MP3和ALAC(Apple Lossless)音频:您可以同时播放多种AAC,MP3和ALAC格式的声音;播放这些格式的多种声音需要CPU资源进行解码。

     

线性PCM和IMA / ADPCM(IMA4音频):您可以同时播放多个线性PCM或IMA4格式声音而无需CPU资源。

答案 1 :(得分:1)

请记住,您正在处理单个音频流,因此您需要自己创建组合流,或者您可以使用混音器单元,它可以让您为多个流提供数据流。请参阅&#34;音频混音器(MixerHost)&#34;来自Apple的示例代码。

答案 2 :(得分:0)

AudioQueue无法同时播放多个声音。它只是从排队缓冲区中逐个发送音频数据值。因此,您需要将您想要同时播放的所有声音组合成单个声音。  你怎么能这样做? 如果数据没有压缩,那就不难了。 例如。你有两种不同的声音。它们中的每一个都可以描述为从-1到1的浮点值数组。当声音存储在文件中或排入audioQueue时,它们必须以适当的格式表示。在您的情况下(kAudioFormatLinearPCM,streamFormat.mBitsPerChannel = 16),它是两个字节的整数,每个值表示为-32767到32767的short int。 因此,两个声音中的每一个都是一个短路数组,当您将缓冲区排入队列时,请使用此数组的值填充它(如果声音不是来自文件并且动态生成此数组不存在,但值是逐个计算的)。 并创造&#34;总和&#34;在这两个音频文件中你应该构造每个新的数组值 来自两个声音数组的相应值的平均值 即resultSound [i] = sound1 [i] / 2 + sound2 [i] / 2;
任何数量的声音都是一样的。 例如。产生纯净的谐波声音就像填充缓冲区一样:

buffer[i] = sin(i * 2 * M_PI * frequency / sampleRate) * 32767;

并混合两种不同频率的谐波声音:

buffer[i] = sin(i * 2 * M_PI * frequency1 / sampleRate) + sin(i * 2 * M_PI * frequency2 / sampleRate) * 0.5 * 32767;