2

谁能告诉我这是如何为 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;
4

3 回答 3

1

AudioQueue 不能同时播放多个声音。它只是从排队缓冲区中一一发送音频数据值。所以你需要将你想要同时播放的所有声音组合成一个单一的声音。你怎么能做到?如果数据没有被压缩,它不会太难。例如,您有两种不同的声音。您可以将它们中的每一个描述为从 -1 到 1 的浮点值数组。当声音存储在文件中或排队到 audioQueue 时,它​​们必须以适当的格式表示。在您的情况下(kAudioFormatLinearPCM,streamFormat.mBitsPerChannel = 16),它是两个字节的整数,每个值表示为从-32767到32767的短整数。因此,两个声音中的每一个都是一个短裤数组,当您将缓冲区排入队列时,您会填充它使用此数组的值(如果声音不是来自文件并且动态生成此数组不存在,但值是一一计算的)。并且要创建这两个音频文件的“总和”,您应该将每个新数组值构造为两个声音数组中相应值的平均值。
即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;
于 2011-09-14T09:01:16.597 回答
1

AudioQueue 可以同时播放声音。

来自苹果:

如何同时播放多个声音?

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

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

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

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

于 2011-10-27T20:37:40.230 回答
1

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

于 2012-08-09T01:50:10.320 回答