1

我已经为录音应用程序构建了一个模拟的模拟 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 动画更新指针旋转,该动画优先保持指针更高。我正在寻找一种方法来调整它以提供更平滑的指针,我的基准尽可能接近 Apple 的模拟 VU Meter。为了得到needleValue,我使用AudioQueue'smAveragePower并在每次currentDB调用时查询它。我怎样才能平滑这个?

4

2 回答 2

2

根据 Wikipedia,VUMeter 的行为在 ANSI 规范 C16.5-1942 中定义。指针的完全上升和下降时间应该是 300 毫秒,在这段时间内平均响度。

我会尝试在针角上使用 1 极低通滤波器来近似该角速率,并使用基于 CADisplayLink 的 drawRect 动画逐帧手动为仪表设置动画。视图动画可能不会提供相同的响应能力。

于 2010-11-23T04:26:49.170 回答
2

我建议的一件事是改变这一点。

#define VU_METER_FREQUENCY    1.0/5.0

也就是说每秒更新 5 次,问题是我认为苹果会保存 0.2 秒的样本,所以你真的得到了声音的平均值,因此仪表并没有真正跟随声音的高低,而是更多较低的平均值。

我认为这个设置可以高达 1.0/60 (60hz)。

至于使仪表平滑,那就有点棘手了。

你可以做这样的事情。

  1. 创建一个包含 7-8 个值的数组。
  2. 每次获得读数时,将其添加到数组中并弹出第 7 个值(例如,仅保留最后七个值。
  3. 求数组的平均值(对数组求和/除以数组中的元素数。
  4. 显示这个平均值。

所以它有点像填充管道,一旦你停止填充,它需要一些时间才能排空,针会慢慢掉下来。

或者你只能让针在每个循环中掉下来这么多。

假设指针摆动为 0(最小值)和 1(最右侧的最大值)。假设您以 20hz(每秒 20 次)采样。

每次更新位置时,只允许指针上升 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;
于 2010-11-23T04:32:52.703 回答