2014-09-30 123 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了解其优秀教程),作为替代方案。

***更新:事实证明,您可以访问AVAudioInputNode的AudioUnit并在其上安装渲染回调。通过AVAudioSession,您可以设置您的音频会话所需的缓冲区大小(不保证,但肯定优于节点水龙头)。到目前为止,我已经使用这种方法获得了低至64个样本的缓冲区大小。一旦我有机会测试它,我会在这里回复代码。

+0

谢谢你的答案。 我在等你的伟大代码! – Melodybox 2014-10-30 01:59:07

+0

不幸的是,我的实验没有成功(在输入节点上安装呈现回调)。我的回调函数被调用,并且我得到了有效的缓冲区,但是所有的样本值都是0.假定输入节点有特殊行为阻止它的工作。很抱歉无法解决我们的问题,并使AVAudioEngine适合我们的用途。我将用旧的API来追求C++实现... – 2014-10-30 18:15:37

+0

Melodybox,如果您希望为您的解决方案采用C/C++之路,请查看https://github.com/abbood/Learning-Core-Audio-Book-Code-Sample。这本书也很值得购买。不知道您是否在使用OS X或iOS,但是如果您在iOS上工作,请查看该存储库中的Chapter10_iOSPlayThrough项目。 – 2014-10-31 00:22:56

0

您可能可以使用CADisplayLink来实现此目的。每次屏幕刷新时,CADisplayLink会给你一个回调,通常每秒钟超过20次(因此可能需要额外的逻辑来限制或限制你的方法在你的情况下执行的次数)。

这显然是一个与您的音频作品相当独立的解决方案,并且在需要反映会话的解决方案的情况下,它可能无法正常工作。但是当我们需要iOS上频繁的循环回调时,这往往是选择的方法,所以这是一个想法。

+0

谢谢你的回答。是否有可能在CADisplayLink的回调中获得AudioBuffer? – Melodybox 2014-10-30 02:04:14

+0

您应该能够在初始化后将缓冲区分配为伊娃。 – isaac 2014-10-31 18:03:53

+0

谢谢。 我需要研究你的答案。 – Melodybox 2014-11-01 20:22:16

11

他们说,苹果支持答道没有:(在2014年9月)

是的,目前我们内部有一个固定的水龙头缓冲区大小(0.375s), 并为客户指定缓冲区大小点击不起作用。

但有人重新调整缓冲区的大小,并得到40ms的 https://devforums.apple.com/thread/249510?tstart=0

不能在ObjC :(检查,neen

UPD它只是单行:

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

我很理解。感谢您的宝贵意见! – Melodybox 2014-12-08 15:13:13

+0

Melodybox,已测试,正常工作 – djdance 2014-12-08 21:05:56

+0

它按预期工作!谢谢! – Melodybox 2014-12-12 18:43:08

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 2014-12-12 18:45:04

+0

没有为我工作。它报告一个'''缓冲区帧长度16537''' – horseshoe7 2015-06-05 06:58:19

相关问题