Но Могу ли я сгладить измерение уровня звука для более реалистичного аналогового VU-метра?
Вопрос
Я создал эмулируемый аналоговый 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 Гц).
Что касается изготовления метра гладкой, это немного удара.
Вы могли бы сделать что-то вроде этого.
- Создайте массив, который содержит 7-8 значений.
- Каждый раз, когда вы получаете чтение, добавьте его в массив и POP 7-е значение (например, только удерживайте последние семь значений.
- Найдите среднее значение массива (суммируйте массив / разделить количество элементов в массиве.
- Показать это среднее.
Таким образом, это немного похоже на заполнение трубы, и как только вы перестанете наполнить, это займет некоторое время для его пустой, а иглы медленно упадут.
Или вы могли бы только иглу упасть только на столько всего цикла.
Позвольте сказать, что игольчатые качели составляют 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.Просмотр анимации может не обеспечить такой же скорости отклика.