使用 AudioQueueServices 同时播放 (10+)
谁能告诉我这是如何在 iPhone 上实现的?我正在尝试制作一款可以同时播放大约 12 个声音的游戏,但我不知道如何使用 AudioQueueServices。我知道您必须初始化、添加缓冲区、播放它们并使用 AudioQueueEnqueueBufferWithParameters 来同时播放,但我不知道如何将其转换为代码。任何有这方面代码的人或者可以向我解释的人都会很棒!
如果您听说过音调网格/音调板,这正是我正在尝试做的。我知道应用程序商店中已经有一些应用程序可以执行此操作,但我不知道它是如何完成的。
太长了;需要 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;
Can anyone show me how this is done for for the iPhone? I am trying to make a game to play about 12 sounds at exactly the same time and I can't figure out how to use AudioQueueServices. I understand you have to initialize, add buffers, play them back and use AudioQueueEnqueueBufferWithParameters to get simultaneous playback, but I don't know how to turn that into code. Anyone with code on this or someone that could explain it to me would be amazing!
If you've heard of a Tone Grid/Tone Board that's exactly what I'm trying to do. I know there are a few apps in the Appstore already that do this, but I don't know how it is done.
TLDR; Need help with AudioQueueServices simultaneous playback with 10+ sounds.
Example:
New playback
if (isPlaying == NO) {
err = AudioQueueNewOutput (&streamFormat, AudioEngineOutputBufferCallback, self, nil, nil, 0, &outputQueue);
if (err != noErr) NSLog(@"AudioQueueNewOutput() error: %d", err);
Enqueue buffers
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;
}
}
Starting playback
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.");
Set up stream format fields
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
AudioQueue 无法同时播放多个声音。它只是从排队缓冲区中一一发送音频数据值。因此,您需要将所有想要同时播放的声音合成为一个。
你怎样才能做到呢?
如果数据没有被压缩,那并不太难。
例如,你有两种不同的声音。您可以将它们中的每一个描述为从 -1 到 1 的浮点值数组。当声音存储在文件中或排队到 audioQueue 中时,它们必须以适当的格式表示。在您的情况下(kAudioFormatLinearPCM,streamFormat.mBitsPerChannel = 16),它是两个字节的整数,每个值表示为从-32767到32767的短整型。
因此,两个声音中的每一个都是一个 Shorts 数组,当您将缓冲区放入队列时,您将用该数组的值填充它(如果声音不是来自文件并且动态生成,则该数组不存在,但值是一一计算的)。
要创建这两个音频文件的“总和”,您应该将每个新数组值构造为
两个声音数组中对应值的平均值。
即 resultSound[i] = sound1[i]/2 + sound2[i]/2;
对于任何数量的声音都是一样的。
例如,要生成纯谐波声音,您可以填充缓冲区,例如:
并混合具有不同频率的两个谐波声音:
AudioQueue can't play multiple sounds simultaneously. It just sends audio data values one by one from enqueued buffer. So you need compose all sounds you want play simultaneously into single one.
How you can do it?
If data are not compressed it is not too hard.
E.g. you have two different sounds. Each of them you can describe as an array of float values from -1 to 1. When sounds stored in file or enqueued to audioQueue they must be represented in appropriate format. In your case (kAudioFormatLinearPCM, streamFormat.mBitsPerChannel = 16) it is two-bytes integers, and each value represented as short int from -32767 to 32767.
Therefore each of two sounds is an array of shorts and when you enqueue buffer you fill it with values of this array (if sound is not from file and generated dynamically this array not exists, but values are calculated one by one).
And to create "sum" of this two audio file you should construct each new array value as
average of corresponding values from two sounds array.
i.e. resultSound[i] = sound1[i]/2 + sound2[i]/2;
And all the same for any number of sounds.
E.g. to generate pure harmonic sound you fill buffer like:
and to mix two harmonic sounds with different frequencies:
请记住,您正在处理单个音频流,因此您要么需要自己创建组合流,要么可以使用混合器单元,它可以让您为其提供多个流。请参阅 Apple 的“音频混合器 (MixerHost)”示例代码。
Remember that you're dealing with a single audio stream, so you either need to create the combined stream yourself, or you could use the mixer unit which will let you feed it multiple streams. See the "Audio Mixer (MixerHost)" sample code from Apple.
AudioQueue可以同时播放声音。
来自苹果:
如何同时播放多个声音?
使用音频队列服务 (AudioToolbox/AudioQueue.h) 中的接口。为您要播放的每种声音创建一个音频队列对象。然后使用 AudioQueueEnqueueBufferWithParameters 函数指定每个音频队列中第一个音频缓冲区的同时开始时间。
以下限制适用于 iPhone OS 中的同步声音,具体取决于音频数据格式:
AudioQueue can play sounds at the same time.
from apple:
How do I play multiple sounds simultaneously?
Use the interfaces in Audio Queue Services (AudioToolbox/AudioQueue.h). Create one audio queue object for each sound that you want to play. Then specify simultaneous start times for the first audio buffer in each audio queue, using the AudioQueueEnqueueBufferWithParameters function.
The following limitations pertain for simultaneous sounds in iPhone OS, depending on the audio data format: