1

録音アプリ用にエミュレートされたアナログ VU メーターを作成しましたが、すべてが適切に接続され、1 つの側面を除いて期待どおりに動作しています。この13 秒間の VU メーターの動作のビデオを見ると、実際の VU メーターで発生するものとは異なり、針がいたるところで跳ねていることがわかります。私が探しているものの例として、Apple の「Voice Memos」アプリを試してみてください。

これまでの私の論理は簡単です。

#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 メーターにできるだけ近いベンチマークを使用して、これを何らかの方法で調整してよりスムーズな針を提供する方法を探しています。を取得するためにneedleValue、 を使用して、AudioQueueが呼び出されるmAveragePowerたびにクエリを実行しています。currentDBどうすればこれを滑らかにできますか?

4

2 に答える 2

2

ウィキペディアによると、VUMeterの動作はANSI仕様C16.5-1942で定義されています。針の完全な立ち上がりと立ち下がりの時間は300mSecであると想定されており、その期間の平均ラウドネスです。

針の角度で1極ローパスフィルターを試してその角速度を概算し、CADisplayLinkベースのdrawRectアニメーションを使用して、フレームごとにメーターを手動でアニメーション化します。ビューアニメーションでは、同じ応答性が得られない場合があります。

于 2010-11-23T04:26:49.170 に答える
2

私が提案する1つのことは、これを変更することです。

#define VU_METER_FREQUENCY    1.0/5.0

つまり、毎秒5倍の更新が必要です。問題は、Appleが0.2秒のサンプルを保持すると思うので、実際に音の平均を取得しているため、メーターは実際には音の高低を追跡していませんが、より低い平均。

この設定は1.0/60(60hz)まで上がる可能性があると思います。

メーターをスムーズにすることに関しては、それは少しトリッキーです。

あなたはこのようなことをすることができます。

  1. 7〜8個の値を保持する配列を作成します。
  2. 読み取り値を取得するたびに、それを配列に追加し、の7番目の値をポップします(たとえば、最後の7つの値のみを保持します。
  3. 配列の平均を求めます(配列を合計する/配列内の要素の数で除算します)。
  4. この平均を表示します。

つまり、パイプをいっぱいにするのと少し似ています。いっぱいになるのをやめると、パイプが空になり、針がゆっくりと落ちるまでに時間がかかります。

または、サイクルごとに針が下がるのを許すことができます。

針の振りが0(最小値)と1(右端の最大値)であるとしましょう。また、20Hz(1秒間に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 に答える