【问题标题】:iOS Audio Unit - Creating Stereo Sine WavesiOS 音频单元 - 创建立体声正弦波
【发布时间】:2012-09-03 09:34:36
【问题描述】:

周末,我在学习如何在 iOS 上编写音频合成程序时遇到了障碍。我已经在 iOS 上开发了几年,但我只是进入音频合成方面。现在,我只是在编写演示应用程序来帮助我学习这些概念。我目前已经能够在音频单元的播放渲染器中构建和堆叠正弦波而没有问题。但是,我想了解渲染器中发生了什么,这样我就可以在每个左右通道中渲染 2 个单独的正弦波。目前,我假设在我的初始音频部分中我需要进行以下更改:

发件人:

AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate = kSampleRate;
    audioFormat.mFormatID = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioFormat.mFramesPerPacket = 1;
    audioFormat.mChannelsPerFrame = 1;
    audioFormat.mBitsPerChannel = 16;
    audioFormat.mBytesPerPacket = 2;
    audioFormat.mBytesPerFrame = 2;

收件人:

AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate = kSampleRate;
    audioFormat.mFormatID = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioFormat.mFramesPerPacket = 1;
    audioFormat.mChannelsPerFrame = 2;
    audioFormat.mBitsPerChannel = 16;
    audioFormat.mBytesPerPacket = 4;
    audioFormat.mBytesPerFrame = 4;

但是,渲染器对我来说有点希腊化。我一直在研究我能找到的任何教程或示例代码。我可以使事情适用于给定的单声道信号上下文,但我不能让渲染器生成立体声信号。我想要的只是左声道中的一个不同频率和右声道中的不同频率 - 但老实说,我对渲染器的了解不足以让它工作。我已尝试将 memcpy 函数放入 mBuffers[0] 和 mbuffers[1],但这会使应用程序崩溃。我的渲染在下面(它当前包含堆叠的正弦波,但对于立体声示例,我可以在每个通道中只使用一个设定频率的波)。

#define kOutputBus 0
#define kSampleRate 44100
//44100.0f
#define kWaveform (M_PI * 2.0f / kSampleRate)

OSStatus playbackCallback(void *inRefCon,
                          AudioUnitRenderActionFlags *ioActionFlags,
                          const AudioTimeStamp *inTimeStamp,
                          UInt32 inBusNumber,
                          UInt32 inNumberFrames,
                          AudioBufferList *ioData) {

        HomeViewController *me = (HomeViewController *)inRefCon;

    static int phase = 1;
    static int phase1 = 1;

    for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) {

        int samples = ioData->mBuffers[i].mDataByteSize / sizeof(SInt16);

        SInt16 values[samples];

        float waves;
        float volume=.5;
        float wave1;

        for(int j = 0; j < samples; j++) {


            waves = 0;
            wave1 = 0;

            MyManager *sharedManager = [MyManager sharedManager];


            wave1 = sin(kWaveform * sharedManager.globalFr1 * phase1)*sharedManager.globalVol1;
            if (0.000001f > wave1) {
                [me setFr1:sharedManager.globalFr1];
                phase1 = 0;
                //NSLog(@"switch");
            }

            waves += wave1;
            waves += sin(kWaveform * sharedManager.globalFr2 * phase)*sharedManager.globalVol2;
            waves += sin(kWaveform * sharedManager.globalFr3 * phase)*sharedManager.globalVol3;
            waves += sin(kWaveform * sharedManager.globalFr4 * phase)*sharedManager.globalVol4;
            waves += sin(kWaveform * sharedManager.globalFr5 * phase)*sharedManager.globalVol5;
            waves += sin(kWaveform * sharedManager.globalFr6 * phase)*sharedManager.globalVol6;
            waves += sin(kWaveform * sharedManager.globalFr7 * phase)*sharedManager.globalVol7;
            waves += sin(kWaveform * sharedManager.globalFr8 * phase)*sharedManager.globalVol8;
            waves += sin(kWaveform * sharedManager.globalFr9 * phase)*sharedManager.globalVol9;
            waves *= 32767 / 9; // <--------- make sure to divide by how many waves you're stacking

            values[j] = (SInt16)waves;
            values[j] += values[j]<<16;

            phase++;
            phase1++;

        }

        memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16));

    }


    return noErr;

}

提前感谢您的帮助!

【问题讨论】:

  • 如果格式是交错的(正如您的 ASBD 建议的那样),那么样本将在一个缓冲区中左右交替:LRLRLRLR。但是,在回调中使用交错格式是不寻常的——通常该格式是操作系统的规范格式。
  • 谢谢。实际上,我只是在几分钟前才弄清楚这一切。不过,正如你所说,它是交错的。我必须弄清楚如何循环通过回调以在不同的 L&R 通道中呈现正弦波。不过感谢您的帮助!
  • 你好 jwkerr,我希望我能说服你发布你的渲染函数。我一直试图让立体渲染工作一段时间,但不能完全理解。谢谢
  • 你好@jwkerr。你能告诉我如何设置AudioStreamBasicDescription吗?我也想得到立体声正弦波!

标签: objective-c ios audio core-audio audiounit


【解决方案1】:

OP 似乎已经解决了他的问题,但我认为发布一个明确的答案会对我们其他人有所帮助。

我也有同样的问题,想将音调分别指向左右声道。用 Matt Gallagher 现在的标准 An iOS tone generator (an introduction to AudioUnits) 来描述是最容易的。

要做的第一个更改是在createToneUnit 方法中设置(在@jwkerr 之后)streamFormat.mChannelsPerFrame = 2;(而不是streamFormat.mChannelsPerFrame = 1;)。一旦完成并且每帧中有两个通道/缓冲区,您需要在RenderTone() 中独立填充左右缓冲区:

// Set the left and right buffers independently
Float32 tmp;
Float32 *buffer0 = (Float32 *)ioData->mBuffers[0].mData;
Float32 *buffer1 = (Float32 *)ioData->mBuffers[1].mData;

// Generate the samples
for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
    tmp = sin(theta) * amplitude;

    if (channelLR[0]) buffer0[frame] = tmp; else buffer0[frame] = 0;
    if (channelLR[1]) buffer1[frame] = tmp; else buffer1[frame] = 0;

    theta += theta_increment;
    if (theta > 2.0 * M_PI) theta -= 2.0 * M_PI;
}

当然channelLR[2] 是一个bool 数组,您可以设置其元素来指示相应通道是否可听。请注意,程序需要将静音通道的帧显式设置为零,否则会发出一些有趣的音调。

【讨论】:

  • channelLR 需要解释更多。
  • 已编辑。这有帮助吗?
  • 什么时候设置channelLR?我试过你的例子,但它是静态的
  • 您在 C 函数中使用此代码(如示例中所示),对吗?设置channelLR[] 有很多选项。您可以将其设为全局,您可以通过inRefCon 传递它,或者您可以在回调本身中设置它。您只需要在开始运行回调之前设置它。
  • 是的,在 C 中。听起来你说你只设置了一次。所以不知道为什么它甚至在那里。感谢您的编辑。仍然不确定您的解决方案是如何工作的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 2013-01-06
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多