2011-09-16 9 views
1

私は、0.25秒ごとにシステム音を鳴らして、簡単なメトロノームを書こうとしています。私は別のスレッド上でクリックを再生するためにGCDを使用していますが、クリックは2回の速いビートと遅いビートの後にくることがあります。ループのif文が実行された時刻と0.25秒後の時刻を記録しました。 Audio Queue Servicesを使用する必要はありません。助言がありますか?彼らはいずれかの特定のハードウェア/ OS用に開発されていないもののシンプルなメトロノーム

- (IBAction)start:(id)sender 
{ 
    dispatch_queue_t clickQueue; // the queue to run the metronome clicker 
    dispatch_queue_t mainQueue; // I access the main queue to demonstrate how to change UIKit items 
    //clickQueue = dispatch_queue_create("clickQueue", NULL); 
    clickQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
    mainQueue = dispatch_get_main_queue(); 
    dispatch_async(clickQueue, ^{ 
     double timeWas = [NSDate timeIntervalSinceReferenceDate]; 
     //delay by a 1/10 of a second so the first few clicks don't bunch up. 
     double timeIs = [NSDate timeIntervalSinceReferenceDate] - 0.1; 
     // playing starts out as NO because it gets switched at the end of the loop 
     // and the PlaySystemSound block isn't off the queue yet. There is probably a 
     // better way to do this. 
     while (playing) { 
      timeIs = [NSDate timeIntervalSinceReferenceDate] ; 
      if ((timeIs - timeWas) > (60.0/240)) { 
       AudioServicesPlaySystemSound(sound); 
       timeWas = timeIs; 
       // I want to flast the 200 label between orange and black but I have to access 
       // user interface objects from the queue that they are running in, usually the 
       // main queue. 
       dispatch_async(mainQueue, ^{ 
        if (flash) 
         [bpm setTextColor:[UIColor orangeColor]]; 
        else 
         [bpm setTextColor:[UIColor blackColor]]; 
        flash = !flash; 
       }); 
      } 
     } 
    }); 
    playing = !playing; 
    if (playing) 
     [startButton setTitle:@"Stop" forState:UIControlStateNormal]; 
    else 
     [startButton setTitle:@"Start" forState:UIControlStateNormal]; 
} 

答えて

3

時間はNSTimer、サウンドはAVFoundationを使用してください。

+2

...あなたのコンテキストで非常に興味深いであるhttp://atastypixel.com/blog/experiments-with-precise-timing-in-ios/をも読み取ることができますAVFoundationによって導入された遅れはあなたのタイミングを捨てます。いくつかの状況では許容できる程度に近いかもしれませんが、メトロノームの場合、より正確なタイミングが必要になります。 –

1

一緒http://www.metronomeonline.com/を置く人々は、タイミングの問題に対処するのはかなり良い仕事をしました。彼らがやったやり方は、あらかじめ録音された.wav/.mp3ファイルを数秒間作成することであると信じていますごとにを入れてループしました。ループレートは、正確なテンポとして計算されます。ループイベントをクライアントのタイミングに依存する唯一のものにすることで、タイミングエラーを減らすことができます。

0

より良いアプローチは、必要な間隔で繰り返すNSTimerを使用することです。あなたのメソッドは、CPUを解体します。

0

私はメトロノームアプリを使って同じルートを一度にダウンしていました。残念ながら、PlaySystemSoundのような高水準のAPIでは、決して正確な応答は得られません。

あなたのテンポと正確な正確さと、あなたが「クリック」として再生するサウンドを望むなら、Audio Unitを使用したいと思うでしょう。あなたはAudio Queue Servicesとにかく低レベルになる必要があることを実感し、すべてを外出することを選択したことを実感した。

+0

これまでしばらく答えてくれたことは分かっていますが、明確にするためにNSTimerを使ってオーディオユニットを別のスレッドでスケジュールしましたか?今日あなたはメトロノームアプリで別のアプローチを取っていますか?あなたが指しているリソースはどれですか? – blwinters

+0

AudioUnitsでNSTimerを使用しません。おそらく、メトロノームを構築する唯一の信頼できるソリューションなので、AudioUnitsの使い方をお読みになることをお勧めします。 –

+0

ありがとうございます。おそらくこのフレームワークから学習曲線を緩和するために始めます:http://theamazingaudioengine.com/ – blwinters

0

私が使用しようとするだろう:

void dispatch_after(
    dispatch_time_t when, 
    dispatch_queue_t queue, 
    dispatch_block_t block); 

あなたはNSTimerはとして正確にあなたがそれがする必要があるとして解雇し得る場合であっても