2012-02-12 10 views
7

Chciałbym zmierzyć głośność dźwięku otoczenia, nie jestem pewien, czy robię to, co trzeba.Czy robię dobrze, aby przekonwertować decybel z -120 - 0 na 0 - 120

Chciałbym stworzyć miernik VU z zakresu od 0 (cichy) do 120 (bardzo głośny).

Zdobyłam moc szczytową i średnią, ale w normalnych, cichych warunkach jest bardzo wysoka. Daj mi wskazówkę.

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 


    //creating an audio CAF file in the temporary directory, this isn’t ideal but it’s the only way to get this class functioning (the temporary directory is erased once the app quits). Here we also specifying a sample rate of 44.1kHz (which is capable of representing 22 kHz of sound frequencies according to the Nyquist theorem), and 1 channel (we do not need stereo to measure noise). 

    NSDictionary* recorderSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
             [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey, 
             [NSNumber numberWithInt:44100],AVSampleRateKey, 
             [NSNumber numberWithInt:1],AVNumberOfChannelsKey, 
             [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey, 
             [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey, 
             [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, 
             nil]; 
    NSError* error; 

    NSURL *url = [NSURL fileURLWithPath:@"/dev/null"]; 
    recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recorderSettings error:&error]; 

    //enable measuring 
    //tell the recorder to start recording: 
    [recorder record]; 

    if (recorder) { 
     [recorder prepareToRecord]; 
     recorder.meteringEnabled = YES; 
     [recorder record]; 
     levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES]; 

    } else 
    { 
     NSLog(@"%@",[error description]); 
    }   
} 

- (void)levelTimerCallback:(NSTimer *)timer { 
    [recorder updateMeters]; 

    const double ALPHA = 0.05; 
    double peakPowerForChannel = pow(10, (0.05 * [recorder averagePowerForChannel:0])); 
    lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;  

    NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults); 

    float tavgPow =[recorder averagePowerForChannel:0] + 120.0; 
    float tpPow = [recorder peakPowerForChannel:0] + 120.0; 

    float avgPow = tavgPow;//(float)abs([recorder averagePowerForChannel:0]); 
    float pPow = tpPow;//(float)abs([recorder peakPowerForChannel:0]); 

    NSString *tempAvg = [NSString stringWithFormat:@"%0.2f",avgPow]; 
     NSString *temppeak = [NSString stringWithFormat:@"%0.2f",pPow]; 
    [avg setText:tempAvg]; 
     [peak setText:temppeak]; 
    NSLog(@"Average input: %f Peak input: %f Low pass results: %f", avgPow,pPow , lowPassResults); 
} 

Odpowiedz

8

Wzór na konwersję liniową amplitudę do decybeli, gdy chcesz użyć jako odniesienia 1.0 (do 0 dB), jest

20 * log10(amp); 

Więc nie jestem pewien co do intencji od patrzenia na Twój kod, ale prawdopodobnie chcesz

float db = 20 * log10([recorder averagePowerForChannel:0]); 

Ten pójdzie z + infinity przy amplitudzie zera do 0 dB przy amplitudzie 1. Jeśli naprawdę potrzebujesz, aby przejść do przedziału od 0 do 120 ty można dodać 120 i użyć funkcji max na zero.

Tak więc, po powyższej linii:

db += 120; 
db = db < 0 ? 0 : db; 

Formuła używasz wydaje się być formuła do konwersji DB do wzmacniacza, który myślę, że jest przeciwieństwem tego, co chcesz.

Edytuj: Ponownie przeczytałem i wydaje się, że możesz już mieć wartość decybeli.

Jeśli jest to przypadek, po prostu nie konwertować do amplitudy i dodać 120.

Więc Zmień

double peakPowerForChannel = pow(10, (0.05 * [recorder averagePowerForChannel:0])); 

do

double peakPowerForChannel = [recorder averagePowerForChannel:0]; 

i powinno być dobrze iść.

+0

Cześć Michael, dzięki za odpowiedź. Wierzę, że averagePowerForChannel jest wartością decybelową w -x będzie chciał przekonwertować ją na wartość 0 - 120 – Desmond

+1

@Desmond: Ok, więc wykonaj ostatni krok Sugeruję zmianę peakPowerForChannel, aby bezpośrednio użyć wartości decybeli. Dodajesz 120 później. Musisz również upewnić się, że jest nie mniej niż zero, używając max (0, db), tak jak to zrobiłem z "db = db <0? 0: db; ' –

+0

dziękuje Michaelowi, jednak decybel jest bardzo bardzo wysoki w cichym pokoju .... ja ściągam aplikację decibel10, żeby sprawdzić, czy decybel jest inny. Aplikacja pokazuje około 40db, moje pokazuje 70db. moim głównym celem tutaj jest sprawdzenie, czy użytkownik robi hałas. jeśli przekroczy próg, coś wyzwoli. – Desmond

1

Faktycznie, zakres decybeli wynosi od -160 do 0, ale może przejść do wartości dodatnich (AVAudioRecorder Class Reference - averagePowerForChannel: metoda).

Wtedy lepiej jest pisać db += 160; zamiast db += 120;. Oczywiście możesz również przesunąć korektę, aby to poprawić.

22

Apple używa tabeli odnośników w ich próbce SpeakHere, która konwertuje z dB na liniową wartość wyświetlaną na mierniku poziomu. Ma to na celu oszczędność mocy urządzenia (chyba).

Też potrzebowałem tego, ale nie myślałem, że kilka obliczeń pływalności co 1/10 (moja częstotliwość odświeżania) będzie kosztować tyle mocy urządzenia. Tak więc, zamiast budowania tabelę I formowane swój kod do:

float  level;    // The linear 0.0 .. 1.0 value we need. 
const float minDecibels = -80.0f; // Or use -60dB, which I measured in a silent room. 
float  decibels = [audioRecorder averagePowerForChannel:0]; 

if (decibels < minDecibels) 
{ 
    level = 0.0f; 
} 
else if (decibels >= 0.0f) 
{ 
    level = 1.0f; 
} 
else 
{ 
    float root   = 2.0f; 
    float minAmp   = powf(10.0f, 0.05f * minDecibels); 
    float inverseAmpRange = 1.0f/(1.0f - minAmp); 
    float amp    = powf(10.0f, 0.05f * decibels); 
    float adjAmp   = (amp - minAmp) * inverseAmpRange; 

    level = powf(adjAmp, 1.0f/root); 
} 

Używam AVAudioRecorder, stąd widać coraz DB z averagePowerForChannel:, ale można wypełnić własną wartość dB tam.

Przykład Apple użyty do obliczeń double, którego nie rozumiem, ponieważ do pomiaru dźwięku float dokładność jest więcej niż wystarczająca i kosztuje mniej mocy urządzenia.

Nie trzeba dodawać, że teraz można skalować obliczoną wartość level do zakresu 0 .. 120 za pomocą prostego level * 120.0f.

Powyższy kod można przyspieszyć, gdy naprawimy root pod adresem 2.0f, zastępując powf(adjAmp, 1.0f/root) przez sqrtf(adjAmp); ale to jest drobnostka, a bardzo dobry kompilator może to zrobić dla nas. I jestem prawie pewien, że inverseAmpRange zostanie obliczony jeden raz podczas kompilacji.

-3

Po prostu ustaw maksymalną i minimalną wartość. Podoba ci się zasięg w zakresie 0-120. Jeśli chcesz zakres 0-60. Wystarczy podzielić wartość na pół, aby uzyskać zakres pół i tak dalej ..

0

Robię model regresji do przekształcenia relacji mapowania między danych wygenerowanych z NSRecorder wav i danych decybeli od NSRecorder.averagePowerForChannel

NSRecorder.averagePowerForChannel (dB) = -80 + 6 log2 (wav_RMS)

Gdzie wav_RMS to średnia kwadratowa danych wav w krótkim czasie, tj. 0,1 sek.

Powiązane problemy