2015-06-04 7 views
13

Ich habe gerade das WWDC-Video (Session 502 AVAudioEngine in der Praxis) unter AVAudioEngine angeschaut und bin sehr aufgeregt, eine App auf dieser Technologie aufzubauen.Level Metering mit AVAudioEngine

Ich konnte nicht herausfinden, wie ich Pegelüberwachung des Mikrofoneingangs oder eines Mischpultausgangs machen könnte.

Kann jemand helfen? Um es klar zu sagen, ich spreche über die Überwachung des aktuellen Eingangssignals (und dies in der Benutzeroberfläche angezeigt), nicht die Eingabe/Ausgabe-Lautstärke Einstellung eines Kanals/Tracks.

Ich weiß, dass Sie dies mit AVAudioRecorder tun können, aber das ist kein AVAudioNode, die AVAudioEngine erfordert.

Antwort

-2

AVAudioPlayer verfügt über Messfunktionen für das Ausgangssignal.

AVAudioRecorder verfügt über Funktionen zum Messen des Eingangssignals.

Hier ist ein blog post und Github-Projekt, das den Recorder verwendet.

+3

Dank für meine Post lesen. -.- Ich bin mir bewusst, dass diese Klassen überwachen, aber sie sind nicht in der AVAudioNode-Hierarchie und arbeiten daher nicht mit der übergeordneten AVAudioEngine API. Wenn ich mich nicht irre ...? – horseshoe7

-3

AVAudioPlayer und AVAudioRecorder sind die "high level" Möglichkeiten, dies zu tun.

Sie wollen den "harten" Weg.

Dann einen Abgriff am Eingangsknoten des Motors installieren. Sie erhalten den Audio-Puffer im Verschluss.

let inputNode = audioEngine.inputNode 
inputNode.installTapOnBus(etc. 
+0

Ich hätte mir meinen Wissensstand besser vorstellen können. Ja, ich habe auch die API-Dokumentation gelesen und dieses Video angesehen, in dem alle diese Konzepte besprochen werden. '' AVAudioNode''' Taps feuern tatsächlich den Callback alle 0,375s oder so (siehe hier http://Stackoverflow.com/a/27343266/421797), so dass dieser Ansatz auch nicht ideal ist. Wenn/wenn ich es herausgefunden habe, werde ich die Antwort posten. Ziemlich sicher, es hat mit AudioUnit Renderrückrufen zu tun. – horseshoe7

+0

Ich will nicht auf die harte Tour, ich möchte einen Weg, der einen gemeinsamen Ansatz verwendet, d. H. '' AVAudioEngine''''. Ich denke darüber nach, wie ich mit '' AVAudioRecorder'' 'erreichen kann, was ich will, aber am Ende des Tages, meine Aufgabe oder nicht, scheint es ein ziemlich gewöhnlicher Anwendungsfall zu sein, angesichts der' '' AVAudioEngine'' 'Architektur zu wollen in der Lage, Pegelanzeigen an beliebigen Stellen zu setzen. – horseshoe7

12

Versuchen Sie, einen Hahn auf Hauptmischer zu installieren, ist es dann schneller durch die Rahmenlänge einstellen, dann die Proben lesen und Durchschnitt bekommen, so etwas wie diese:

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) ; 
    } 
}]; 

die Spitzenwerte zu erhalten, Verwenden Sie vDSP_maxmgv anstelle von vDSP_meamgv.


LEVEL_LOWPASS_TRIG ist ein einfacher Filter geschätzt zwischen 0,0 bis 1,0, wenn man 0,0 eingestellt Sie alle Werte filtern wird und keine Daten. Wenn Sie es auf 1.0 setzen, erhalten Sie zu viel Rauschen. Grundsätzlich gilt, je höher der Wert ist, desto mehr Daten variieren. Es scheint, dass ein Wert zwischen 0,10 und 0,30 für die meisten Anwendungen gut ist.

+7

Welcher Wert (oder Bereich) wird für LEVEL_LOWPASS_TRIG verwendet? – apocolipse

+5

Um vDSP_meamgv zu verwenden, führen Sie "Import Accelerate" aus, um Apples leistungsstarkes mathematisches Framework zu verwenden. – Josh

+0

Können Sie vielleicht ein vollständiges Arbeitsbeispiel in Github veröffentlichen? –

0

Ich entdeckte eine andere Lösung, die ein bisschen seltsam ist, aber funktioniert perfekt gut und viel besser als tippen. Ein Mixer hat keine AudioUnit, aber wenn Sie ihn in einen AVAudioIONode umwandeln, können Sie die AudioUnit bekommen und die Messfunktion des iOS nutzen. Hier ist, wie:

So aktivieren oder deaktivieren Dosierung:

- (void)setMeteringEnabled:(BOOL)enabled; 
{ 
    UInt32 on = (enabled)?1:0; 
    AVAudioIONode *node = (AVAudioIONode*)self.engine.mainMixerNode; 
    OSStatus err = AudioUnitSetProperty(node.audioUnit, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Output, 0, &on, sizeof(on)); 
} 

Meter zu aktualisieren:

- (void)updateMeters; 
{ 
    AVAudioIONode *node = (AVAudioIONode*)self.engine.mainMixerNode; 

    AudioUnitParameterValue level; 
    AudioUnitGetParameter(node.audioUnit, kMultiChannelMixerParam_PostAveragePower, kAudioUnitScope_Output, 0, &level); 

    self.averagePowerForChannel1 = self.averagePowerForChannel0 = level; 
    if(self.numberOfChannels>1) 
    { 
     err = AudioUnitGetParameter(node.audioUnit, kMultiChannelMixerParam_PostAveragePower+1, kAudioUnitScope_Output, 0, &level); 
    } 
} 
+1

funktioniert nicht für mich, könnten Sie Ihre Antwort erweitern? –