带混音器的 NewTimePitch

Posted

技术标签:

【中文标题】带混音器的 NewTimePitch【英文标题】:NewTimePitch with Mixer 【发布时间】:2016-01-08 02:47:51 【问题描述】:

我有一个与 Apple 提供的示例应用程序非常相似的图表。

https://developer.apple.com/library/ios/samplecode/MixerHost/Listings/Classes_MixerHostAudio_m.html#//apple_ref/doc/uid/DTS40010210-Classes_MixerHostAudio_m-DontLinkElementID_6

我的混合器节点由自定义数据(而不是吉他/节拍)提供 - 但设置类似。混音器上的两条总线都是立体声的。

我正在尝试对内容进行时间转换,但到目前为止还没有成功。我尝试将 kAudioUnitSubType_NewTimePitch 添加到图表中,但无论何时添加图表都无法创建。是否有任何源示例说明我如何使用混音器单元进行时移(移动所有总线)?

这是一些工作代码:

// Describe audio component
AudioComponentDescription output_desc;
bzero(&output_desc, sizeof(output_desc));
output_desc.componentType = kAudioUnitType_Output;
output_desc.componentSubType = self.componentSubType;
output_desc.componentFlags = 0;
output_desc.componentFlagsMask = 0;
output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;


// multichannel mixer unit
AudioComponentDescription mixer_desc;
bzero(&mixer_desc, sizeof(mixer_desc));
mixer_desc.componentType = kAudioUnitType_Mixer;
mixer_desc.componentSubType = kAudioUnitSubType_MultiChannelMixer;
mixer_desc.componentFlags = 0;
mixer_desc.componentFlagsMask = 0;
mixer_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

// Describe NewTimePitch component
AudioComponentDescription speed_desc;
bzero(&speed_desc, sizeof(speed_desc));
speed_desc.componentType = kAudioUnitType_FormatConverter;
speed_desc.componentSubType = kAudioUnitSubType_NewTimePitch;
speed_desc.componentFlags = 0;
speed_desc.componentFlagsMask = 0;
speed_desc.componentManufacturer = kAudioUnitManufacturer_Apple;


result = AUGraphAddNode(mGraph, &output_desc, &outputNode);
if (result)  printf("AUGraphNewNode 1 result %ld %4.4s\n", (long)result, (char*)&result); return; 

result = AUGraphAddNode(mGraph, &speed_desc, &timeNode );
if (result)  printf("AUGraphNewNode 2 result %ld %4.4s\n", (long)result, (char*)&result); return; 

result = AUGraphAddNode(mGraph, &mixer_desc, &mixerNode );
if (result)  printf("AUGraphNewNode 3 result %ld %4.4s\n", (long)result, (char*)&result); return; 

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, outputNode, 0);
if (result)  printf("AUGraphConnectNodeInput mixer-> time result %ld %4.4s\n", (long)result, (char*)&result); return; 

// open the graph AudioUnits are open but not initialized (no resource allocation occurs here)

result = AUGraphOpen(mGraph);
if (result)  printf("AUGraphOpen result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

result = AUGraphNodeInfo(mGraph, mixerNode, NULL, &mMixer);
if (result)  printf("AUGraphNodeInfo mixer result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

result = AUGraphNodeInfo(mGraph, timeNode, NULL, &mTime);
if (result)  printf("AUGraphNodeInfo time result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

result = AUGraphNodeInfo(mGraph, outputNode, NULL, &mOutput);
if (result)  printf("AUGraphNodeInfo output result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 


UInt32 numbuses = 1;

result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, sizeof(numbuses));
if (result)  printf("AudioUnitSetProperty bus result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 


for (int i = 0; i < numbuses; ++i) 
    // setup render callback struct
    AURenderCallbackStruct rcbs;
    rcbs.inputProc = &mixerInput;
    rcbs.inputProcRefCon = (__bridge void *)(outputStream);

    printf("set kAudioUnitProperty_SetRenderCallback for mixer input bus %d\n", i);

    // Set a callback for the specified node's specified input
    result = AUGraphSetNodeInputCallback(mGraph, mixerNode, i, &rcbs);
    // equivalent to AudioUnitSetProperty(mMixer, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, i, &rcbs, sizeof(rcbs));
    if (result)  printf("AUGraphSetNodeInputCallback result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

    // set input stream format to what we want
    printf("set mixer input kAudioUnitProperty_StreamFormat for bus %d\n", i);

result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, i, mAudioFormat.streamDescription, sizeof(AudioStreamBasicDescription));
    if (result)  printf("AudioUnitSetProperty result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 


result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamInAudioFormat, sizeof(streamInAudioFormat));
if (result)  printf("AudioUnitSetProperty mixer result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

result = AudioUnitSetProperty(mOutput, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &streamInAudioFormat, sizeof(streamInAudioFormat));
if (result)  printf("AudioUnitSetProperty output result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

CAShow(mGraph);
// now that we've set everything up we can initialize the graph, this will also validate the connections
result = AUGraphInitialize(mGraph);
if (result)  printf("AUGraphInitialize result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

此代码有效 - 我有一个混音器,我可以通过回调将数据泵入其中。您可以看到我创建了时间节点,但无论我将它插入图表的哪个位置,它都会杀死它。我也无法设置流格式或其他任何内容。

理想情况下,我想做这样的事情:

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, timeNode, 0);
result = AUGraphConnectNodeInput(mGraph, timeNode, 0, outputNode, 0);

但这不起作用。

这是该设置的输出:

音频单元图 0x385003: 会员节点: 节点 1:'auou''vpio''appl',实例 0x134f40b10 O 节点 2:'aufc''nutp''appl',实例 0x134e733b0 O 节点 3:'aumx''mcmx''appl',实例 0x134ea71d0 O 连接: 节点 3 总线 0 => 节点 2 总线 0 [ 2 ch,44100 Hz,'lpcm' (0x00000029) 32 位小端浮点,去交错] 节点 2 总线 0 => 节点 1 总线 0 [ 1 ch, 0 Hz, 'lpcm' (0x00000029) 32 位小端浮点数,去交错] 输入回调: 0x100038ea0, 0x134f7f900 => 节点 3 总线 0 [2 ch, 44100 Hz] 当前状态: mLastUpdateError=0, eventsToProcess=F, isInitialized=F, isRunning=F 2016-01-07 23:21:32.230 R5ProTestbed[901:503908] 23:21:32.229 错误:[0x19ff25000] 2776:ConnectAudioUnit 失败,错误 -10868 2016-01-07 23:21:32.230 R5ProTestbed[901:503908] 23:21:32.230 错误:[0x19ff25000] 1682:初始化失败,错误 -10868

【问题讨论】:

什么样的班次?音高变化还是相移? 音高(我正在尝试加快音频播放速度)。我正在尝试做混音器-> newtimepitch-> IO,但图形无法初始化。我不确定流格式是否与它有关,或者这只是设置它的错误方法。 粘贴一些代码。指定有效的方法以及您添加的导致图表失败的确切代码。 用代码更新了原始问题。 【参考方案1】:

根据 CAShow,您当前的图表是这样的: 混音器 -> TimePitch -> VoiceProcess (你的输出节点不在图中)

您无法另外将混音器输出连接到其他设备 在你的代码中,你有这样的

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, timeNode, 0);

所以你不能也添加

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, outputNode, 0);

同时拥有上述两条线会导致图表混淆,并且它不知道您希望混合器的输出去哪里。

同样,您将混音器输出连接到输出节点

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, outputNode, 0);

所以你不能同时将时间节点连接到输出节点

result = AUGraphConnectNodeInput(mGraph, timeNode, 0, outputNode, 0);

同时拥有这两个会使图形混淆,因为输出节点有两个输入,而且它只能有一个。 就好像您正在尝试建立“Y”连接,就连接而言您无法做到。

您可以将输出放在一个输入上,这样两行就会发生冲突。找出您希望它在链中的位置,并将一个输出连接到一个输入。 然后将渲染回调设置为链中的第一个节点。

来自您的 cmets “我正在尝试做混音器->newtimepitch->IO” 你需要做三个节点,

将混音器输出连接到 Time Pitch 将 Time Pitch 连接到 RemoteIO

您需要 3 个节点。两个 AUGraphConnectNodeInput() 调用。 将您的渲染回调连接到混音器。像这样的:

result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, timeNode, 0);
result = AUGraphConnectNodeInput(mGraph, timeNode, 0, outputNode, 0); 

就像你一样。确保从您的代码中删除其他节点连接。我不知道您是删除了其他连接还是保留了它们并添加了更多连接。

【讨论】:

不幸的是,这就是我的确切设置。正如您从输出中看到的那样,3 个节点、2 个连接、1 个混音器上的输入回调。错误可能来自具有 2 条总线的混音器,还是流格式问题?【参考方案2】:

如果不手动配置错误检查,默认音频格式可能不合适。您需要将混音器的输出格式设置为时间音高单元的输入格式,并将您的输出节点(RemoteIO?)的输入格式设置为时间音高单元的输出格式。连接单元前需要配置格式。

不要在时间间距单位上设置格式。获取时间音高单位的格式,并将这些格式设置在时间音高连接的所有内容上。

【讨论】:

我试过这样做 - 但每当我在 timepitch 单元上明确设置格式时,它都会失败(格式无效)。不过,我会再试一次,让你知道。谢谢! 不要在时间音高单位上设置格式。获取时间音高单位的格式,并将这些格式设置在时间音高连接的所有内容上。 就是这样!我在 IO 和混音器上设置格式,而这些正是导致问题的原因。非常感谢!【参考方案3】:

hotpaw2 在我自己弄清楚后立即回答。非常感谢。我在混音器和 IO 的输出上设置 StreamFormat,通过停止它,转换器能够运行。

//    result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamInAudioFormat, sizeof(streamInAudioFormat));
//    if (result)  printf("AudioUnitSetProperty mixer result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

//    result = AudioUnitSetProperty(mOutput, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &streamInAudioFormat, sizeof(streamInAudioFormat));
//    if (result)  printf("AudioUnitSetProperty output result %ld %08lX %4.4s\n", (long)result, (long)result, (char*)&result); return; 

【讨论】:

以上是关于带混音器的 NewTimePitch的主要内容,如果未能解决你的问题,请参考以下文章

电脑无法播放声音,怎样安装混音器设备,电脑没声。

pygame混音器将音频保存到磁盘?

视频混音器api?

Java - 从混音器录制

录音/混音器软件

混音器 AudioUnit 到 RemoteIO AudioUnit