NewTimePitch с микшером

У меня есть график работы, который очень похож на пример приложения, предоставленного Apple.

https://developer.apple.com/library/ios/samplecode/MixerHost/Listings/Classes_MixerHostAudio_m.html

Мой микшер-нод заполняется пользовательскими данными (а не гитарой / битами), но настройка аналогична. Обе шины стерео на микшере.

Я пытаюсь вовремя сдвинуть контент, но пока безуспешно. Я попытался добавить 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);

Но это не работает.

Вот результат этой настройки:

AudioUnitGraph 0x385003: Узлы-члены: узел 1: "auou", "vpio", "appl", экземпляр 0x134f40b10 O, узел 2: "aufc", "nutp", "appl", экземпляр 0x134e733b0, узел 3: "aumx", "mcmx", "appl", экземпляр 0x134ea71d0 O Соединения: шина узла 3 0 => шина узла 2 0  [ 2 канала,  44100 Гц, 'lpcm' (0x00000029) 32-битная переменная с прямым порядком байтов с обратным порядком следования, шина узла 2 0 => шина узла 1 [ 1 канал, 0 Гц, 'lpcm' (0x00000029) 32-разрядный метод с прямым порядком байтов, обратное чередование =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

3 ответа

Решение

hotpaw2 ответил сразу после того, как сам разобрался. Спасибо. Я настраивал 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; }

Ваш текущий график таков в соответствии с CAShow: Mixer -> 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" соединения, которые вы не можете сделать, если речь идет о соединениях.

Вы можете поместить вывод в один вход, чтобы обе строки конфликтовали. Выясните, где вы хотите, чтобы это было в цепочке и подключите один выход точно к одному входу
Затем установите обратный вызов рендеринга в качестве первого узла в цепочке.

Из ваших комментариев "Я пытаюсь сделать микшер->newtimepitch->IO" Вам нужно сделать три узла,

  • подключите выход микшера к шагу времени
  • подключите Шаг Времени к RemoteIO

Вам нужно 3 узла. Два вызова AUGraphConnectNodeInput(). Соедините ваш обратный вызов рендера с микшером. Что-то вроде этого:

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

как ты. Убедитесь, что другие соединения узлов удалены из вашего кода. Я не мог сказать, удалили ли вы другие соединения или оставили их и добавили больше соединений.

Аудиоформаты по умолчанию могут не подходить, если они не настроены вручную с проверкой ошибок. Вам необходимо установить выходной формат микшера на формат ввода единицы шага времени, а формат ввода вашего узла вывода (RemoteIO?) - на формат вывода единицы шага времени. Форматы необходимо настроить перед подключением устройств.

Не устанавливайте формат на единицу времени. Получите форматы модуля шага по времени и установите эти форматы для всего, к чему подключается шаг по времени.

Другие вопросы по тегам