21

AVAudioEngineWWDC ビデオ (Session 502 in Practice) を見たばかりAVAudioEngineで、この技術を基にアプリを作成できることに非常に興奮しています。

マイクの入力やミキサーの出力のレベルを監視する方法がわかりません。

誰でも助けることができますか?明確にするために、チャンネル/トラックの入力/出力ボリューム設定ではなく、現在の入力信号を監視する (およびこれを UI に表示する) ことについて話しています。

でこれを実行できることはわかっていますが、これは が必要とするものでAVAudioRecorderはありません。AVAudioNodeAVAudioEngine

4

6 に答える 6

23

メイン ミキサーにタップをインストールし、フレーム長を設定して高速化し、サンプルを読み取って平均を取得します。次のようにします。

フレームワークを一番上にインポート

#import <Accelerate/Accelerate.h>

プロパティを追加

@property float averagePowerForChannel0;
@property float averagePowerForChannel1;

次に同じ>>

self.mainMixer = [self.engine mainMixerNode];
[self.mainMixer installTapOnBus:0 bufferSize:1024 format:[self.mainMixer outputFormatForBus:0] block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
    [buffer setFrameLength:1024];
    UInt32 inNumberFrames = buffer.frameLength;

    if(buffer.format.channelCount>0)
    {
        Float32* samples = (Float32*)buffer.floatChannelData[0];
        Float32 avgValue = 0;

        vDSP_meamgv((Float32*)samples, 1, &avgValue, inNumberFrames);
        self.averagePowerForChannel0 = (LEVEL_LOWPASS_TRIG*((avgValue==0)?-100:20.0*log10f(avgValue))) + ((1-LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel0) ;
        self.averagePowerForChannel1 = self.averagePowerForChannel0;
    }

    if(buffer.format.channelCount>1)
    {
        Float32* samples = (Float32*)buffer.floatChannelData[1];
        Float32 avgValue = 0;

        vDSP_meamgv((Float32*)samples, 1, &avgValue, inNumberFrames);
        self.averagePowerForChannel1 = (LEVEL_LOWPASS_TRIG*((avgValue==0)?-100:20.0*log10f(avgValue))) + ((1-LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel1) ;
    }
}];

次に、必要な目標値を取得します

NSLog(@"===test===%.2f", self.averagePowerForChannel1);

ピーク値を取得するには、vDSP_meamgv の代わりに vDSP_maxmgv を使用します。


LEVEL_LOWPASS_TRIG は、0.0 から 1.0 までの値の単純なフィルターです。0.0 を設定すると、すべての値がフィルター処理され、データは取得されません。1.0 に設定すると、ノイズが多すぎます。基本的に、値が高いほど、データの変動が大きくなります。ほとんどのアプリケーションでは、0.10 から 0.30 の間の値が適しているようです。

于 2015-10-16T08:52:03.313 に答える
1
#define LEVEL_LOWPASS_TRIG .3

#import "AudioRecorder.h"





@implementation AudioRecord


-(id)init {
     self = [super init];
     self.recordEngine = [[AVAudioEngine alloc] init];

     return self;
}


 /**  ----------------------  Snippet Stackoverflow.com not including Audio Level Meter    ---------------------     **/


-(BOOL)recordToFile:(NSString*)filePath {

     NSURL *fileURL = [NSURL fileURLWithPath:filePath];

     const Float64 sampleRate = 44100;

     AudioStreamBasicDescription aacDesc = { 0 };
     aacDesc.mSampleRate = sampleRate;
     aacDesc.mFormatID = kAudioFormatMPEG4AAC; 
     aacDesc.mFramesPerPacket = 1024;
     aacDesc.mChannelsPerFrame = 2;

     ExtAudioFileRef eaf;

     OSStatus err = ExtAudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAAC_ADTSType, &aacDesc, NULL, kAudioFileFlags_EraseFile, &eaf);
     assert(noErr == err);

     AVAudioInputNode *input = self.recordEngine.inputNode;
     const AVAudioNodeBus bus = 0;

     AVAudioFormat *micFormat = [input inputFormatForBus:bus];

     err = ExtAudioFileSetProperty(eaf, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), micFormat.streamDescription);
     assert(noErr == err);

     [input installTapOnBus:bus bufferSize:1024 format:micFormat block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
       const AudioBufferList *abl = buffer.audioBufferList;
       OSStatus err = ExtAudioFileWrite(eaf, buffer.frameLength, abl);
       assert(noErr == err);


       /**  ----------------------  Snippet from stackoverflow.com in different context  ---------------------     **/


       UInt32 inNumberFrames = buffer.frameLength;
       if(buffer.format.channelCount>0) {
         Float32* samples = (Float32*)buffer.floatChannelData[0]; 
         Float32 avgValue = 0;
         vDSP_maxv((Float32*)samples, 1.0, &avgValue, inNumberFrames);
         self.averagePowerForChannel0 = (LEVEL_LOWPASS_TRIG*((avgValue==0)?
                                  -100:20.0*log10f(avgValue))) + ((1- LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel0) ;
         self.averagePowerForChannel1 = self.averagePowerForChannel0;
       }

       dispatch_async(dispatch_get_main_queue(), ^{

         self.levelIndicator.floatValue=self.averagePowerForChannel0;

       });     


       /**  ---------------------- End of Snippet from stackoverflow.com in different context  ---------------------     **/

     }];

     BOOL startSuccess;
     NSError *error;

     startSuccess = [self.recordEngine startAndReturnError:&error]; 
     return startSuccess;
}



@end
于 2019-07-25T02:06:48.177 に答える