首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift:来自AVAudioPCMBuffer的触发函数

Swift:来自AVAudioPCMBuffer的触发函数
EN

Stack Overflow用户
提问于 2020-11-23 18:41:02
回答 1查看 39关注 0票数 0

我正在为iOS开发一个节拍器应用程序。引擎正在工作,目前非常准确,但是,它只给出音频反馈,而我也想给出视觉反馈。

我做了一个AVAudioPCMBuffer来按设定的时间间隔播放一次滴答声,如何在播放音频的时候触发函数?

下面是我目前掌握的代码:

‘private func generateBuffer(bpm: Double,beats: Int) -> AVAudioPCMBuffer {

代码语言:javascript
复制
    audioFileMainClick.framePosition = 0
    audioFileAccentedClick.framePosition = 0
    
    let beatLength = AVAudioFrameCount(audioFileMainClick.processingFormat.sampleRate * 60 / bpm)
    let bufferMainClick = AVAudioPCMBuffer(pcmFormat: audioFileMainClick.processingFormat, frameCapacity: beatLength)!
    try! audioFileMainClick.read(into: bufferMainClick)
    bufferMainClick.frameLength = beatLength
    
    let bufferAccentedClick = AVAudioPCMBuffer(pcmFormat: audioFileMainClick.processingFormat, frameCapacity: beatLength)!
    try! audioFileAccentedClick.read(into: bufferAccentedClick)
    
    let bufferBar = AVAudioPCMBuffer(pcmFormat: audioFileMainClick.processingFormat, frameCapacity: UInt32(beats) * beatLength)!
    bufferBar.frameLength = UInt32(beats) * beatLength
    
    let channelCount = Int(audioFileMainClick.processingFormat.channelCount)
    let accentedClickArray = Array(
        UnsafeBufferPointer(start: bufferAccentedClick.floatChannelData![0],
                            count: channelCount * Int(beatLength))
    )
    let mainClickArray = Array(
        UnsafeBufferPointer(start: bufferMainClick.floatChannelData![0],
                            count: channelCount * Int(beatLength))
    )
    
    var barArray = [Float]()
    // one time for first beat
    barArray.append(contentsOf: accentedClickArray)
    // n times for regular clicks
    for _ in 1...(beats - 1) {
        barArray.append(contentsOf: mainClickArray)
    }
    bufferBar.floatChannelData!.pointee.assign(from: barArray,
                                               count: channelCount * Int(bufferBar.frameLength))
    return bufferBar
    
}

func play(bpm: Double, beats: Int) {
    
    let buffer = generateBuffer(bpm: bpm, beats: beats)
    
    if audioPlayerNode.isPlaying {
        audioPlayerNode.scheduleBuffer(buffer, at: nil, options: .interruptsAtLoop, completionHandler: nil)
    } else {
        self.audioPlayerNode.play()
    }
    
    self.audioPlayerNode.scheduleBuffer(buffer, at: nil, options: .loops, completionHandler: nil)
    
}

“”“

提前谢谢你。

菲利波

EN

回答 1

Stack Overflow用户

发布于 2021-05-01 04:32:03

尽量不要使用scheduleBuffer的循环函数。使用重新触发play()函数的completionHandler。这使您可以选择将代码添加到play()函数以获得视觉反馈,如显示当前节拍。记住始终使用DispatchQueue.main.async {...}来处理UI内容。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64966806

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档