2012-06-14 6 views
7

Ich habe eine OSX App, die Audiodaten mit einer Audio Unit aufzeichnet. Der Eingang der Audio-Einheit kann auf jede verfügbare Quelle mit Eingängen einschließlich des eingebauten Eingangs eingestellt werden. Das Problem ist, dass der Ton, den ich vom eingebauten Eingang bekomme, oft beschnitten wird, während ich in einem Programm wie Audacity (oder sogar Quicktime) den Eingangspegel herunterdrehen kann und ich keinen Clipping bekomme.Wie stellen Sie den Eingangspegel (Gain) am eingebauten Eingang (OSX Core Audio/Audio Unit) ein?

Das Multiplizieren der Beispielrahmen mit einem Bruchteil funktioniert natürlich nicht, weil ich eine niedrigere Lautstärke erhalte, aber die Samples selbst werden zum Zeitpunkt der Eingabe immer noch abgeschnitten.

Wie stelle ich den Eingangspegel oder die Verstärkung für diesen integrierten Eingang ein, um das Clipping-Problem zu vermeiden?

Antwort

10

Das funktioniert für mich, um die Eingangslautstärke auf meinem MacBook Pro (Modell 2011) einzustellen. Es ist ein bisschen funky, ich musste versuchen, die Lautstärke des Master-Kanals einzustellen, dann jedes unabhängige Stereo-Kanal-Volume, bis ich einen gefunden habe, der funktioniert hat. Sehen Sie sich die Kommentare in meinem Code an. Ich vermute, der beste Weg zu sagen, ob Ihr Code funktioniert, ist, eine get/set-property-Kombination zu finden, die funktioniert, und dann etwas wie get/set (etwas anderes) zu tun Setter arbeitet.

Oh, und ich werde natürlich darauf hinweisen, dass ich nicht auf die Werte in der Adresse verlassen würde, die bei getProperty Calls gleich bleiben, wie ich hier mache. Es scheint zu funktionieren, aber es ist auf jeden Fall eine schlechte Übung, sich darauf zu verlassen, dass die Strukturwerte gleich sind, wenn Sie eine durch Verweis auf eine Funktion übergeben. Dies ist natürlich ein Beispielcode, bitte verzeih mir meine Faulheit. ;)

// 
// main.c 
// testInputVolumeSetter 
// 

#include <CoreFoundation/CoreFoundation.h> 
#include <CoreAudio/CoreAudio.h> 

OSStatus setDefaultInputDeviceVolume(Float32 toVolume); 

int main(int argc, const char * argv[]) { 
    OSStatus      err; 

    // Load the Sound system preference, select a default 
    // input device, set its volume to max. Now set 
    // breakpoints at each of these lines. As you step over 
    // them you'll see the input volume change in the Sound 
    // preference panel. 
    // 
    // On my MacBook Pro setting the channel[ 1 ] volume 
    // on the default microphone input device seems to do 
    // the trick. channel[ 0 ] reports that it works but 
    // seems to have no effect and the master channel is 
    // unsettable. 
    // 
    // I do not know how to tell which one will work so 
    // probably the best thing to do is write your code 
    // to call getProperty after you call setProperty to 
    // determine which channel(s) work. 
    err = setDefaultInputDeviceVolume(0.0); 
    err = setDefaultInputDeviceVolume(0.5); 
    err = setDefaultInputDeviceVolume(1.0); 
} 

// 0.0 == no volume, 1.0 == max volume 
OSStatus setDefaultInputDeviceVolume(Float32 toVolume) { 
    AudioObjectPropertyAddress  address; 
    AudioDeviceID     deviceID; 
    OSStatus      err; 
    UInt32       size; 
    UInt32       channels[ 2 ]; 
    Float32       volume; 

    // get the default input device id 
    address.mSelector = kAudioHardwarePropertyDefaultInputDevice; 
    address.mScope = kAudioObjectPropertyScopeGlobal; 
    address.mElement = kAudioObjectPropertyElementMaster; 

    size = sizeof(deviceID); 
    err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nil, &size, &deviceID); 

    // get the input device stereo channels 
    if (! err) { 
     address.mSelector = kAudioDevicePropertyPreferredChannelsForStereo; 
     address.mScope = kAudioDevicePropertyScopeInput; 
     address.mElement = kAudioObjectPropertyElementWildcard; 
     size = sizeof(channels); 
     err = AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &channels); 
    } 

    // run some tests to see what channels might respond to volume changes 
    if (! err) { 
     Boolean      hasProperty; 

     address.mSelector = kAudioDevicePropertyVolumeScalar; 
     address.mScope = kAudioDevicePropertyScopeInput; 

     // On my MacBook Pro using the default microphone input: 

     address.mElement = kAudioObjectPropertyElementMaster; 
     // returns false, no VolumeScalar property for the master channel 
     hasProperty = AudioObjectHasProperty(deviceID, &address); 

     address.mElement = channels[ 0 ]; 
     // returns true, channel 0 has a VolumeScalar property 
     hasProperty = AudioObjectHasProperty(deviceID, &address); 

     address.mElement = channels[ 1 ]; 
     // returns true, channel 1 has a VolumeScalar property 
     hasProperty = AudioObjectHasProperty(deviceID, &address); 
    } 

    // try to get the input volume 
    if (! err) { 
     address.mSelector = kAudioDevicePropertyVolumeScalar; 
     address.mScope = kAudioDevicePropertyScopeInput; 

     size = sizeof(volume); 
     address.mElement = kAudioObjectPropertyElementMaster; 
     // returns an error which we expect since it reported not having the property 
     err = AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &volume); 

     size = sizeof(volume); 
     address.mElement = channels[ 0 ]; 
     // returns noErr, but says the volume is always zero (weird) 
     err = AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &volume); 

     size = sizeof(volume); 
     address.mElement = channels[ 1 ]; 
     // returns noErr, but returns the correct volume! 
     err = AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &volume); 
    } 

    // try to set the input volume 
    if (! err) { 
     address.mSelector = kAudioDevicePropertyVolumeScalar; 
     address.mScope = kAudioDevicePropertyScopeInput; 

     size = sizeof(volume); 

     if (toVolume < 0.0) volume = 0.0; 
     else if (toVolume > 1.0) volume = 1.0; 
     else volume = toVolume; 

     address.mElement = kAudioObjectPropertyElementMaster; 
     // returns an error which we expect since it reported not having the property 
     err = AudioObjectSetPropertyData(deviceID, &address, 0, nil, size, &volume); 

     address.mElement = channels[ 0 ]; 
     // returns noErr, but doesn't affect my input gain 
     err = AudioObjectSetPropertyData(deviceID, &address, 0, nil, size, &volume); 

     address.mElement = channels[ 1 ]; 
     // success! correctly sets the input device volume. 
     err = AudioObjectSetPropertyData(deviceID, &address, 0, nil, size, &volume); 
    } 

    return err; 
} 

EDIT als Antwort auf Ihre Frage: "Wie hast [I] Figur this out?"

Ich habe in den letzten fünf Jahren viel Zeit mit dem Audiocode von Apple verbracht und ich habe eine Intuition/einen Prozess entwickelt, wenn es darum geht, wo und wie nach Lösungen gesucht wird. Mein Geschäftspartner und ich haben die ursprünglichen iHeartRadio-Apps für das iPhone der ersten Generation und einige andere Geräte mitgeschrieben. Eine meiner Aufgaben in diesem Projekt war der Audioteil, speziell das Schreiben eines AAC Shoutcast Stream-Decoders/-Players für iOS. Es gab zu der Zeit keine Dokumente oder Open-Source-Beispiele, also war es eine Menge Versuch und Irrtum, und ich habe eine Menge gelernt.

Auf jeden Fall, als ich Ihre Frage las und sah die Bounty ich dachte, das war nur niedrig hängenden Frucht (d. H. Sie hatten nicht RTFM ;-). Ich habe ein paar Codezeilen geschrieben, um die Volume-Eigenschaft festzulegen, und als das nicht funktioniert habe, habe ich mich wirklich dafür interessiert.

Prozess weise vielleicht werden Sie dies nützlich finden:

Sobald ich wusste, dass es keine einfache Antwort war ich begann darüber nachzudenken, wie das Problem zu lösen. Ich wusste, dass das Sound System Preference können Sie die Eingangsverstärkung so eingestellt, dass ich durch Zerlegen es mit otool begonnen, um zu sehen, ob Apple-wurde die Verwendung von alten oder neuen Audio Toolbox Routinen machen (neu, wie es geschieht):

Versuchen Sie es mit:

otool -tV /System/Library/PreferencePanes/Sound.prefPane/Contents/MacOS/Sound | bbedit

dann für Audio suchen, um zu sehen, welche Methoden aufgerufen werden (wenn Sie BBEdit nicht haben, die jeder Mac-Entwickler IMO sollte, werfen Sie es in einem anderen Text-Editor in eine Datei und öffnen).

Ich bin am vertrautesten mit den älteren, veralteten Audio Toolbox-Routinen (drei Jahre bis zur Veralterung in dieser Branche), also habe ich mir ein paar Technotes von Apple angeschaut.Sie haben eines, das zeigt, wie man das Standard-Eingabegerät erhält und seine Lautstärke mit den neuesten CoreAudio-Methoden einstellt, aber wie Sie zweifellos gesehen haben, funktioniert ihr Code nicht richtig (zumindest auf meinem MBP).

Sobald ich an diesen Punkt kam, fiel ich auf das Altbewährte zurück: Beginnen Sie mit der Suche nach Stichwörtern, die wahrscheinlich beteiligt sind (z. B. AudioObjectSetPropertyData, kAudioDevicePropertyVolumeScalar usw.).

Eine interessante Sache, die ich über CoreAudio- und mit dem Apple-Toolbox im Allgemeinen gefunden habe, ist, dass es einen gibt, viel von Open-Source-Code ist, wo die Menschen verschiedene Dinge (Tonnen Pastebins und Google Projekte etc.) versuchen . Wenn Sie bereit sind, einen Haufen Code zu durchforsten, werden Sie normalerweise entweder die Antwort finden oder sehr gute Ideen bekommen.

In meiner Suche waren die relevantesten Dinge, die ich fand, der Apple Technote, der zeigt, wie man das Standardeingabegerät erhält und die Haupteingabeverstärkung unter Verwendung der neuen Toolboxroutinen einstellt (obwohl es auf meiner Hardware nicht funktionierte), und Ich habe einen Code gefunden, der das Einstellen der Verstärkung nach Kanal auf einem Ausgabegerät anzeigt. Da Eingabegeräte mehrkanalig sein können, dachte ich mir, dass dies das nächste logische Mittel ist, es zu versuchen.

Ihre Frage ist wirklich gut, denn zumindest gibt es im Moment keine korrekte Dokumentation von Apple, die zeigt, wie Sie tun können, was Sie gefragt haben. Es ist auch albern, weil beide Kanäle berichten, dass sie die Lautstärke einstellen, aber nur eine von ihnen (das Eingangsmikrofon ist eine Monoquelle, also ist das nicht überraschend, aber ich denke über einen No-Op-Kanal und keine Dokumentation darüber nach eines Fehlers auf Apple).

Dies passiert ziemlich gleichmäßig, wenn Sie mit den neuesten Technologien von Apple beginnen. Sie können erstaunliche Dinge mit ihrer Toolbox tun und es bringt jedes andere Betriebssystem aus dem Wasser, mit dem ich gearbeitet habe, aber es dauert nicht lange, um ihre Dokumentation zu überholen, besonders wenn Sie versuchen, etwas Moderates zu machen.

Wenn Sie sich zum Beispiel dafür entscheiden, einen Kernel-Treiber zu schreiben, werden Sie die Dokumentation zu IOKit als unzureichend empfinden. Letztendlich müssen Sie online gehen und den Quellcode durchforsten, entweder die Projekte anderer Leute oder die OS X-Quelle oder beides, und bald werden Sie feststellen, dass die Quelle wirklich der beste Ort für Antworten ist (auch wenn StackOverflow ist ziemlich toll).

Danke für die Punkte und viel Glück mit Ihrem Projekt :)

+0

Danke für die tolle Antwort. Aus Neugier und potentiellem zukünftigen Nutzen, wie kommt es, dass Sie entweder auf diese Lösung stießen oder das Wissen hatten, den Code zu schreiben? –

+0

Stellt sich heraus, dass eine richtige Antwort nicht in einen Kommentar passt, also habe ich meine Antwort bearbeitet. Nochmals vielen Dank für die Prämie! – par

+0

Tolle Beschreibung - Danke, dass du dir die Zeit genommen hast! –

Verwandte Themen