Objective c iOS音频单元-创建立体声正弦波

Objective c iOS音频单元-创建立体声正弦波,objective-c,ios,audio,core-audio,audiounit,Objective C,Ios,Audio,Core Audio,Audiounit,周末,我在学习如何在iOS上编程音频合成时遇到了一个绊脚石。我已经在iOS上开发了好几年了,但我刚刚进入音频合成方面。现在,我正在编写演示应用程序来帮助我学习这些概念。目前,我已经能够在播放渲染器中为音频单元构建和堆叠正弦波,没有任何问题。但是,我想了解渲染器中发生了什么,以便可以在每个左通道和右通道中渲染2个单独的正弦波。目前,我假设在init audio部分中,我需要进行以下更改: 发件人: AudioStreamBasicDescription audioFormat; audio

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

发件人:

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;
致:

但是,渲染器对我来说有点希腊化。我一直在编写我能找到的任何教程或示例代码。我可以在单声道信号的给定环境下工作,但无法使渲染器生成立体声信号。我想要的只是在左通道中有一个不同的频率,在右通道中有一个不同的频率——但我真的不太了解渲染器,无法让它正常工作。我曾尝试将memcpy函数插入mBuffers[0]和mBuffers[1],但这会使应用程序崩溃。下面是我的渲染(它当前包含叠加的正弦波,但对于立体声示例,我可以在每个通道中使用一个设定频率的波)

#定义kOutputBus 0
#定义kSampleRate 44100
//44100.0f
#定义kWaveform(M_PI*2.0f/kSampleRate)
OSStatus回放回调(无效*inRefCon,
AudioUnitRenderActionFlags*ioActionFlags,
常量音频时间戳*inTimeStamp,
UInt32 InBunsNumber,
UInt32数字帧,
音频缓冲列表*ioData){
refcon中的HomeViewController*me=(HomeViewController*);
静态int相位=1;
静态int相位1=1;
对于(UInt32 i=0;imNumberBuffers;i++){
int samples=ioData->mBuffers[i].mDataByteSize/sizeof(SInt16);
16个数值[样本];
浮波;
浮动量=.5;
浮波1;
对于(int j=0;jwave1){
[me setFr1:sharedManager.globalFr1];
相位1=0;
//NSLog(“开关”);
}
波+=波1;
waves+=sin(kWaveform*sharedManager.globalFr2*相位)*sharedManager.globalVol2;
waves+=sin(kWaveform*sharedManager.globalf3*相位)*sharedManager.globalVol3;
waves+=sin(kWaveform*sharedManager.Globalr4*阶段)*sharedManager.globalVol4;
waves+=sin(kWaveform*sharedManager.globalf5*相位)*sharedManager.globalVol5;
waves+=sin(kWaveform*sharedManager.globalFr6*相位)*sharedManager.globalVol6;
波+=sin(kWaveform*sharedManager.globalFr7*相位)*sharedManager.globalVol7;
波+=sin(kWaveform*sharedManager.globalFr8*相位)*sharedManager.globalVol8;
波+=sin(kWaveform*sharedManager.globalFr9*相位)*sharedManager.globalVol9;

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

我也有同样的问题,想要将音调独立地指向左声道和右声道。这是用马特·加拉赫(Matt Gallagher)现在的标准来描述的最简单的方法

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

//独立设置左右缓冲区
32 tmp;
Float32*buffer0=(Float32*)ioData->mBuffers[0].mData;
Float32*buffer1=(Float32*)ioData->mBuffers[1].mData;
//生成样本
对于(UInt32 frame=0;frame2.0*M_-PI)θ-=2.0*M_-PI;
}

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

如果格式是交错的(如ASBD所建议的那样),然后样本将在一个左右交替的缓冲区中:
lr
。然而,在回调中使用交错格式是不寻常的-通常这种格式是操作系统的标准格式。谢谢。实际上我几分钟前就已经完全弄清楚了。不过,正如你所说,它是交错的。我必须弄清楚如何通过回调循环在不同的L&R通道中渲染正弦波。谢谢你的帮助!!你好,jwkerr,我希望我能说服你发布渲染函数。我已经尝试让立体渲染工作了一段时间,但没有完全实现。ThanksHello@jwkerr。你能告诉我如何设置AudioStreamBasic吗描述?我也想得到立体声正弦波!channelLR需要解释更多。编辑。这有帮助吗?什么时候设置channelLR?我已经尝试了你的示例,但它是静态的。你正在C函数中使用此代码(如示例中所示),对吗?设置
channelLR[]有很多选项
。您可以将其设置为全局,也可以通过EFCON中的
传递,或者设置它
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;
#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;

}
// 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;
}