Но Могу ли я сгладить измерение уровня звука для более реалистичного аналогового VU-метра?

StackOverflow https://stackoverflow.com/questions/4252695

Вопрос

Я создал эмулируемый аналоговый VU-метр для приложения для записи, и все подключено должным образом и работает так, как я ожидаю, за исключением одного аспекта.Если вы посмотрите это 13-секундное видео наблюдая за VU-метром в действии, вы увидите, что стрелка прыгает повсюду и на самом деле это не то, что произошло бы в реальном VU-метре.Для примера того, что я ищу, попробуйте приложение Apple "Голосовые заметки" и посмотрите.

Моя логика пока проста:

#define VU_METER_FREQUENCY                                      1.0/5.0

- (void)someMethod {
    _updateTimer = [NSTimer 
                    scheduledTimerWithTimeInterval:VU_METER_FREQUENCY
                    target:self 
                    selector:@selector(_refresh) 
                    userInfo:nil 
                    repeats:YES];
}

- (void)_refresh {  
    // if we have no queue, but still have levels, gradually bring them down
    if (_delegate == nil) {
        CFAbsoluteTime thisFire = CFAbsoluteTimeGetCurrent();
        // calculate how much time passed since the last draw
        CFAbsoluteTime timePassed = thisFire - _peakFalloffLastFire;
        needleValue = needleValue - timePassed * VU_METER_LEVEL_FALL_OFF_PER_SECOND;
        if (needleValue < VU_METER_MIN_DB) {
            needleValue = VU_METER_MIN_DB;
            TT_INVALIDATE_TIMER(_updateTimer);
        }
        _peakFalloffLastFire = thisFire;
    } else {
        prevNeedleValue = needleValue;
        needleValue = [_delegate currentDB];
    }
    [self updateNeedle];
}

- (void)updateNeedle {
    [UIView beginAnimations:nil context:NULL]; // arguments are optional
    [UIView setAnimationDuration:VU_METER_FREQUENCY];
    [UIView setAnimationCurve:(needleValue > prevNeedleValue ? UIViewAnimationCurveEaseOut : UIViewAnimationCurveEaseIn)];
    CGFloat radAngle = [self radianAngleForValue:needleValue];
    self.needle.transform = CGAffineTransformMakeRotation(radAngle);
    [UIView commitAnimations];
}

По сути, я настраиваю таймер для запуска в VU_METER_FREQUENCY и обновите вращение иглы, используя анимацию UIView с ослаблением, которое предпочтительно для того, чтобы держать иглу выше.Я ищу способ как-то отрегулировать это, чтобы обеспечить более плавную стрелку, при этом мой бенчмарк должен быть как можно ближе к аналоговому измерителю VU от Apple.Чтобы получить needleValue, я использую AudioQueue's mAveragePower и запрашиваю его каждый раз currentDB называется.Как я могу это сгладить?

Это было полезно?

Решение

Одна вещь, которую я бы предложил, это изменение этого.

#define VU_METER_FREQUENCY    1.0/5.0

Это говорит об обновлении 5x в секунду, вопрос заключается в том, что я думаю, что Apple удержит 0,2 с образцов, поэтому вы действительно получаете средние звуки, следовательно, измеритель на самом деле не следит за максимумами и минимума звуков, но больше ниже среднего.

Я думаю, что эта настройка может идти максимально 1,0 / 60 (60 Гц).

Что касается изготовления метра гладкой, это немного удара.

Вы могли бы сделать что-то вроде этого.

  1. Создайте массив, который содержит 7-8 значений.
  2. Каждый раз, когда вы получаете чтение, добавьте его в массив и POP 7-е значение (например, только удерживайте последние семь значений.
  3. Найдите среднее значение массива (суммируйте массив / разделить количество элементов в массиве.
  4. Показать это среднее.

Таким образом, это немного похоже на заполнение трубы, и как только вы перестанете наполнить, это займет некоторое время для его пустой, а иглы медленно упадут.

Или вы могли бы только иглу упасть только на столько всего цикла.

Позвольте сказать, что игольчатые качели составляют 0 (наименьшее значение) и 1 (наивысшее значение, далеко правая сторона). Давайте также скажем, что вы образец в 20 Гц (20x раз в секунду).

Каждый раз, когда вы обновляете позицию, позвольте иглу подняться, скажем, 0,1 значения максимального и падения всего 0,05 значения.

Вы можете сделать что-то вроде этого и играть со значениями, чтобы получить его приятно и гладко.

if newValue>currentMeterValue
   currentMeterValue = Min(currentMeterValue + 0.1, newValue);
else
   currentMeterValue = Max(currentMeterValue - 0.05, newValue);

ИЛИ

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

   currentMeterValue += (newValue - currentMeterValue)/4.0;

Другие советы

Согласно Википедии, поведение VUMeter определено в спецификации ANSI C16.5-1942.Предполагается, что время полного подъема и спада стрелки составляет 300 мс, усредняя громкость за это время.

Я бы попробовал использовать 1-полюсный фильтр нижних частот для определения угла наклона иглы, чтобы приблизить эту угловую частоту, и анимировать счетчик вручную покадрово, используя анимацию drawRect на основе CADisplayLink.Просмотр анимации может не обеспечить такой же скорости отклика.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top