2014-09-30 4 views
6

Я хочу отображать волну в режиме реального времени с микрофона. Я был реализован с использованием installTapOnBus: bufferSize: format: block :, Эта функция вызывается три раза за одну секунду. Я хочу, чтобы эту функцию вызывали 20 раз в секунду. Где я могу установить?Я хочу позвонить 20 раз в секунду installTapOnBus: bufferSize: format: block:

AVAudioSession *audioSession = [AVAudioSession sharedInstance]; 

NSError* error = nil; 
if (audioSession.isInputAvailable) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 
if(error){ 
    return; 
} 

[audioSession setActive:YES error:&error]; 
if(error){ 
    retur; 
} 

self.engine = [[[AVAudioEngine alloc] init] autorelease]; 

AVAudioMixerNode* mixer = [self.engine mainMixerNode]; 
AVAudioInputNode* input = [self.engine inputNode]; 
[self.engine connect:input to:mixer format:[input inputFormatForBus:0]]; 

// tap ... 1 call in 16537Frames 
// It does not change even if you change the bufferSize 
[input installTapOnBus:0 bufferSize:4096 format:[input inputFormatForBus:0] block:^(AVAudioPCMBuffer* buffer, AVAudioTime* when) { 

    for (UInt32 i = 0; i < buffer.audioBufferList->mNumberBuffers; i++) { 
     Float32 *data = buffer.audioBufferList->mBuffers[i].mData; 
     UInt32 frames = buffer.audioBufferList->mBuffers[i].mDataByteSize/sizeof(Float32); 

     // create waveform 
     ... 
    } 
}]; 

[self.engine startAndReturnError:&error]; 
if (error) { 
    return; 
} 

ответ

5

Класс AVAudioNode эталонных состояний, что реализация может выбрать размер буфера, кроме того, что вы поставляете, так, насколько я знаю, мы застряли с очень большим размером буфера. Это печально, потому что AVAudioEngine - отличная оболочка Core Audio. Поскольку мне тоже нужно использовать входной сигнал для чего-то другого, кроме записи, я смотрю на The Amazing Audio Engine, а также на Core Audio C API (см. IBook Learning Core Audio для отличных обучающих программ на нем) в качестве альтернативы.

*** Обновление: Оказывается, вы можете получить доступ к AudioUnit AVAudioInputNode и установить на него обратный вызов визуализации. Через AVAudioSession вы можете установить желаемый размер буфера аудиосеанса (не гарантируется, но, конечно, лучше, чем удаленные узлы). До сих пор я получил размеры буфера до 64 образцов, используя этот подход. Я отправлю обратно сюда код, как только у меня будет возможность проверить это.

+0

Благодарим за ответ. Я жду вашего замечательного кода! – Melodybox

+0

К сожалению, мой эксперимент не удался (установка обратного вызова рендеринга на входном узле). Моя функция обратного вызова вызывается, и я получаю допустимые буферы, однако все значения выборки равны 0. Предположительно, для входного узла существует специальное поведение, препятствующее этому работать. Извините, что не смог решить нашу проблему и сделать работу AVAudioEngine для наших целей. Я собираюсь преследовать реализацию C++ со старым API ... –

+0

Melodybox, если вы хотите взять дорогу C/C++ для своего решения, посмотрите https://github.com/abbood/Learning-Core-Audio-Book-Code-Sample. Книга, которая идет с ней, тоже стоит покупать. Не уверен, работаете ли вы на OS X или iOS, но если вы работаете в iOS, посмотрите проект Chapter10_iOSPlayThrough в указанном репозитории. –

0

Для достижения этой цели вы можете использовать CADisplayLink. A CADisplayLink даст вам обратный вызов каждый раз, когда экран обновляется, что обычно будет намного больше 20 раз в секунду (так что может потребоваться дополнительная логика для дросселирования или ограничения количества раз, когда ваш метод выполняется в вашем случае).

Это, очевидно, решение, которое довольно дискретно от вашей аудиоработы, и в той степени, в которой вам требуется решение, которое отражает вашу сессию, оно может не работать. Но когда нам нужны частые повторяющиеся обратные вызовы в iOS, это часто подход к выбору, так что это идея.

+0

Благодарим за ответ. Можно ли получить AudioBuffer в обратном вызове CADisplayLink? – Melodybox

+0

Вы должны иметь возможность назначить буфер в качестве ivar после его инициализации. – isaac

+0

Спасибо. Мне нужно учиться для вашего ответа. – Melodybox

11

они говорят, Apple Support ответил нет: (сен 2014)

Да, в настоящее время внутри страны мы имеем фиксированный размер буфера крана (0.375s), и клиент указанный размер буфера для крана не действует.

но кто-то изменяет размер буфера и получает 40мс https://devforums.apple.com/thread/249510?tstart=0

Не может проверить это, Нина в ObjC :(

UPD это работает только одна строка:

[input installTapOnBus:0 bufferSize:1024 format:[mixer outputFormatForBus:0] block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) { 
    buffer.frameLength = 1024; //here 
+0

Я понял. Спасибо за отличный совет! – Melodybox

+0

Melodybox, протестирован, отлично работает – djdance

+0

Он работал должным образом! Спасибо! – Melodybox

0

Не знаю, почему или даже если это работает, просто попробуйте несколько вещей. Но наверняка NSLogs указывают интервал 21 мс, 1024 образцы, поступающие в буфер ...

 AVAudioEngine* sEngine = NULL; 
     - (void)applicationDidBecomeActive:(UIApplication *)application 
     { 
      /* 
      Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 
      */ 

      [glView startAnimation]; 

      AVAudioSession *audioSession = [AVAudioSession sharedInstance]; 

      NSError* error = nil; 
      if (audioSession.isInputAvailable) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 
      if(error){ 
       return; 
      } 

      [audioSession setActive:YES error:&error]; 
      if(error){ 
       return; 
      } 

      sEngine = [[AVAudioEngine alloc] init]; 

      AVAudioMixerNode* mixer = [sEngine mainMixerNode]; 
      AVAudioInputNode* input = [sEngine inputNode]; 
      [sEngine connect:input to:mixer format:[input inputFormatForBus:0]]; 

      __block NSTimeInterval start = 0.0; 

      // tap ... 1 call in 16537Frames 
      // It does not change even if you change the bufferSize 
      [input installTapOnBus:0 bufferSize:1024 format:[input inputFormatForBus:0] block:^(AVAudioPCMBuffer* buffer, AVAudioTime* when) { 

       if (start == 0.0) 
        start = [AVAudioTime secondsForHostTime:[when hostTime]]; 

       // why does this work? because perhaps the smaller buffer is reused by the audioengine, with the code to dump new data into the block just using the block size as set here? 
       // I am not sure that this is supported by apple? 
       NSLog(@"buffer frame length %d", (int)buffer.frameLength); 
       buffer.frameLength = 1024; 
       UInt32 frames = 0; 
       for (UInt32 i = 0; i < buffer.audioBufferList->mNumberBuffers; i++) { 
        Float32 *data = buffer.audioBufferList->mBuffers[i].mData; 
        frames = buffer.audioBufferList->mBuffers[i].mDataByteSize/sizeof(Float32); 
        // create waveform 
        /// 
       } 
       NSLog(@"%d frames are sent at %lf", (int) frames, [AVAudioTime secondsForHostTime:[when hostTime]] - start); 
      }]; 

      [sEngine startAndReturnError:&error]; 
      if (error) { 
       return; 
      } 

     } 
+0

Спасибо! Я думаю, что я пытаюсь проверить эту функцию. – Melodybox

+0

, что не работает для меня. Он сообщает о '' 'длина буферного кадра 16537''' – horseshoe7

Смежные вопросы