2010-11-23 3 views
1

私はレコーディングアプリケーションのためのエミュレートされたアナログVUメーターを作り、すべてが正しく接続され、1つの面を除いて私が期待したように動作しています。 VUメーターのwatch this 13-second videoが動作していると、針が場所全体に跳ね返ることがわかります。実際のVUメーターではどうなるでしょうか。私が探しているものの例については、Appleの "Voice Memos"アプリを試してみてください。もっと現実的なアナログVUメーターのオーディオレベルメーターを滑らかにすることはできますか?

私のロジックは、これまでは簡単です:基本的に

#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を取得するには、私はAudioQueuemAveragePowerを使用しており、currentDBが呼び出されるたびにそれを照会しています。どうすればこれを平滑化できますか?

+0

radianAngleForValue:needleValue:メソッドを私と共有してもらいたいと思います。私はVUメーターを稼働させようとしていますが、それはうまく動作しません。 –

+0

角度はあなた自身の実装に非常に特有です。ニードルの長さとスケールに依存しますが、これは値を表示するために作成した画像によって決まります。私は、必要な複数の方程式を解き、セットアップでこの関数に必要な値を取得するために、紙でそれを試してみるまでにある程度時間がかかりました。このリンクは、自分で設定する方法を決定する際に役立ちました:http://neolit123.blogspot.com/2009/03/designing-analog-vu-meter-in-dsp.html#hcon – coneybeare

+0

ありがとうございます私はそれを把握するのに役立ちます。眠れない週末、ここに来る!現時点では、私は横に動く針を備えたVUメーターを馬鹿にして実装していますが、ちょっとしたことですが、実際のVUメーターが必要です。 –

答えて

2

これを変更することをお勧めします。第二5倍の更新を言う

#define VU_METER_FREQUENCY 1.0/5.0 

は、問題は、私はAppleがサンプルの0.2秒を保持すると思いますので、あなたが本当にそれゆえメーターは本当に高値と安値、次のされていない、音の平均値を取得しているということですより多くのより低い平均の音の。

私はこの設定が1.0/60(60hz)の高さになると思います。

メーターを滑らかにするために、少しトリッキーです。

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

  1. 7-8の値を保持する配列を作成します。
  2. あなたが読み値を取得するたびに、それを配列に追加して、7番目の値をポップします(例えば、最後の7つの値だけを保持します)。
  3. 配列の平均を求めます配列。
  4. 表示で、この平均。

だから、そのビットのパイプを埋めるように、そしてあなたはそれを空にすると針がゆっくり落ちるのは少し時間がかかります充填を停止一度。

または、毎回毎回針が倒れないようにすることができます。

ニードルスイングが0(最小値)と1(最も高い値が最も右側)と言います。 20hz(20x秒)でサンプリングすることもできます。

ポジションを更新するたびに、ニードルが0になるようにします。1を値の最大値とし、値を0.05とする。

あなたはこのようなことをして、値を付けて遊んでいいと滑らかになります。

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

OR

あなたは、単に各値との間の距離に比例した速度で計を動かす(これはうまくそれを滑らかにすべきである)と、実際に針を押圧するスプリングと実メートルに近くなります電磁石によって動力を供給される。

currentMeterValue += (newValue - currentMeterValue)/4.0; 
+0

サンプルの配列を使用して異常を除外しました。また、大きなジャンプを抑制するためにMIX、MAXメソッドでスムージングを実装しました。以下のCADisplayLinkを使用すると、約60HZのリフレッシュレートが得られ、UIViewアニメーションが完全になくなりました。 – coneybeare

2

ウィキペディアによると、VUMeterの動作はANSI仕様C16.5-1942で定義されています。針の完全な立ち上がり時間および立ち下がり時間は、300mSecであり、その持続時間にわたる平均音量を想定している。

この角速度に近づけるためにニードルアングルの1極ローパスフィルタを試し、CADisplayLinkベースのdrawRectアニメーションを使用してメーターを手動でフレームごとにアニメーション化します。ビューのアニメーションが同じ応答性を提供しない可能性があります。

+0

とCADisplayLinkの場合は1です。 Didntはそれについて知っていた。 – coneybeare