12

大規模なアプリの一部としてメトロノームを作成しており、個々のサウンドとして使用する非常に短い wav ファイルがいくつかあります。NSTimer には重大な遅延の問題があり、Core Audio を Swift に実装するのはかなり難しいように思われるため、AVAudioEngine を使用したいと考えています。私は次のことを試みていますが、現在、最初の 3 つの手順を実装できず、より良い方法があるかどうか疑問に思っています。

コードの概要:

  1. メトロノームの現在の設定に従って、ファイル URL の配列を作成します (小節ごとのビート数とビートごとのサブディビジョンの数。ビート用のファイル A、サブディビジョン用のファイル B)。
  2. ファイルのテンポと長さに基づいて、適切な数の無音フレームを含む wav ファイルをプログラムで作成し、それを各サウンド間の配列に挿入します。
  3. それらのファイルを単一の AudioBuffer または AudioBufferList に読み込みます
  4. audioPlayer.scheduleBuffer(buffer, atTime:nil, options:.Loops, completionHandler:nil)

これまでのところ、単一のサウンド ファイルのループ バッファー (ステップ 4) を再生することはできましたが、ファイルの配列からバッファーを作成したり、プログラムで無音を作成したりすることはできませんでした。また、StackOverflow に関する回答も見つかりませんでした。これに対処します。したがって、これは最善のアプローチではないと推測しています。

私の質問は次のとおりです: AVAudioEngine を使用して低レイテンシーでサウンドのシーケンスをスケジュールし、そのシーケンスをループすることは可能ですか? そうでない場合、Swift でコーディングするときにサウンドをスケジューリングするのに最適なフレームワーク/アプローチはどれですか?

4

3 に答える 3

4

ファイルからのサウンドと必要な長さの無音を含むバッファーを作成できました。これが役立つことを願っています:

// audioFile here – an instance of AVAudioFile initialized with wav-file
func tickBuffer(forBpm bpm: Int) -> AVAudioPCMBuffer {
    audioFile.framePosition = 0 // position in file from where to read, required if you're read several times from one AVAudioFile
    let periodLength = AVAudioFrameCount(audioFile.processingFormat.sampleRate * 60 / Double(bpm)) // tick's length for given bpm (sound length + silence length)
    let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: periodLength)
    try! audioFile.readIntoBuffer(buffer) // sorry for forcing try
    buffer.frameLength = periodLength // key to success. This will append silcence to sound
    return buffer
}

// player – instance of AVAudioPlayerNode within your AVAudioEngine
func startLoop() {
    player.stop()
    let buffer = tickBuffer(forBpm: bpm)
    player.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil)
    player.play()
}
于 2015-09-28T07:53:11.970 に答える