Я правильно делаю, чтобы преобразовать децибел из -120 - 0 в 0 - 120 - PullRequest
7 голосов
/ 12 февраля 2012

Я хотел бы измерить громкость звука окружающего, не слишком уверенный, правильно ли я поступаю.

Я хотел бы создать измеритель VU в диапазоне от 0 (тихий) до 120(очень шумно).

Я получил пиковую и среднюю мощность, но они очень высоки в обычной тихой обстановке.Дайте мне указатель.

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

Ответы [ 5 ]

24 голосов
/ 24 апреля 2013

Apple использует справочную таблицу в их SpeakHere выборке, которая преобразует значение из дБ в линейное значение, отображаемое на индикаторе уровня.Это для экономии энергии устройства (я думаю).

Мне это тоже нужно, но я не думал, что пара вычислений с плавающей запятой каждые 1/10 с (моя частота обновления) будет стоить столько энергии устройства.Таким образом, вместо того, чтобы создать таблицу, я преобразовал их код в:

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

Я использую AVAudioRecorder, следовательно, вы видите получение дБ с averagePowerForChannel:, но вы можете заполнить свой собственный дБзначение там.

Пример Apple использовал double расчеты, которые я не понимаю, потому что для измерения звука float точность более чем достаточна и стоит меньше энергии устройства.

Нет необходимостискажем, теперь вы можете масштабировать этот вычисленный level до вашего диапазона 0 .. 120 с помощью простого level * 120.0f.

Приведенный выше код может быть ускорен, когда мы исправим root в 2.0f,замена powf(adjAmp, 1.0f / root) на sqrtf(adjAmp);но это мелочь, и очень хороший компилятор может сделать это за нас.И я почти уверен, что inverseAmpRange будет вычислено один раз во время компиляции.

8 голосов
/ 12 февраля 2012

Формула для преобразования линейной амплитуды в децибелы, когда вы хотите использовать 1,0 в качестве эталона (для 0 дБ), равна

20 * log10(amp);

Так что я не уверен в намерении взглянуть на ваш код, но вы, вероятно, хотите

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

Это будет идти от -infinity при амплитуде ноль, до 0 дБ при амплитуде 1. Если вам действительно нужно, чтобы значение было между 0 и 120, вы можете добавить 120 и использовать функцию max в нуле.

Итак, после строки выше:

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

Формула, которую вы используете, похоже, является формулой для преобразования DB в amp, что, я думаю, противоположно тому, что вы хотите.

Редактировать: Я перечитал, и, возможно, у вас уже есть значение в децибелах.

Если это так, просто не конвертируйте в амплитуду и добавьте 120.

Смена

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

до

double peakPowerForChannel = [recorder averagePowerForChannel:0];

и с тобой все будет в порядке.

1 голос
/ 20 марта 2013

На самом деле диапазон децибел составляет от -160 до 0, но он может принимать положительные значения. ( Ссылка на класс AVAudioRecorder - averagePowerForChannel: метод)

Тогда лучше написать db += 160; вместо db += 120;.Конечно, вы также можете поставить смещение, чтобы исправить это.

0 голосов
/ 09 августа 2017

Я делаю регрессионную модель для преобразования отношения отображения между данными wav, сгенерированными из NSRecorder, и данными децибел из NSRecorder.averagePowerForChannel

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

Где wav_RMS - среднеквадратичное значение wav-данных за короткое время, т. Е. 0,1 с.

0 голосов
/ 18 апреля 2015

Просто установите максимальное и минимальное значение.Как вы получаете диапазон 0-120.Если вы хотите диапазон 0-60.Просто разделите значение на половину, чтобы получить половину диапазона и т. Д.

...