AudioKit ios AKSequencer 无法准确重启播放
AudioKit ios AKSequencer Not Restarting Playback Accurately
我正在尝试使用 AudioKit 在小节的每个节拍上播放声音。虽然我已经通过 AudioKit 实现了 similar question regarding callbacks 中的代码,但我似乎无法让音序器正确更新更改和播放。它会准确播放一次,但是在倒带和更改值后它只会使用初始值(或根本不播放)。
我的目的是为每个小节创建一个带有节拍值的小节结构,然后使用 MIDI 和回调来播放不同的声音,具体取决于有多少 measures/beats。谢谢!
import UIKit
import AudioKit
class ViewController: UIViewController {
let sequencer = AKSequencer()
let click = AKSynthSnare()
let callbackInst = AKCallbackInstrument()
// Create the struct that defines each line
struct Line {
var name: String
var measures: Int
var beatsPerMeasure: Int
func totalBeats() -> Int {
return (measures * beatsPerMeasure)
}
}
// Initialize intro line
var intro = Line(name: "Intro", measures: 0, beatsPerMeasure: 0)
// A function to create/update/playback the sequence on button press
func playBack() {
let metronomeTrack = sequencer.newTrack()
metronomeTrack?.setMIDIOutput(click.midiIn)
let callbackTrack = sequencer.newTrack()
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
for steps in 0 ... Int(measuresRowOneValue) {
// this will trigger the sampler on the four down beats
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the midiNote number to the current beat number
callbackTrack?.add(noteNumber: MIDINoteNumber(steps), velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the callback
callbackInst.callback = {status, noteNumber, velocity in
guard status == .noteOn else { return }
print("beat number: \(noteNumber + 1)")
}
}
}
@IBOutlet weak var rowOneLocationOne: UIImageView!
// Listener for UI display values
var measuresRowOneValue: Int = 0 {
didSet {
intro.measures = measuresRowOneValue
}
}
@IBAction func rowOnePlusButton(_ sender: UIButton) {
measuresRowOneValue += 1
}
@IBAction func rowOneMinusButton(_ sender: UIButton) {
measuresRowOneValue -= 1
}
@IBAction func playbackStart(_ sender: UIButton) {
playBack()
sequencer.play()
}
@IBAction func playbackStop(_ sender: UIButton) {
sequencer.stop()
}
@IBAction func playbackRestart(_ sender: UIButton) {
sequencer.rewind()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
AudioKit.output = click
try!AudioKit.start()
}
}
你的代码中有一些令人困惑的地方,所以我不确定这是否是你唯一的问题,但至少,每次你改变序列的长度时,你都需要调用 setLength()
后跟 enableLooping
。基本上,默认情况下(即,除非您明确设置长度)序列的长度将是序列中最长轨道的长度。在您的 'playback' 方法中,您是在不删除旧轨道的情况下在轨道之上添加轨道,因此它无法知道您希望序列持续多长时间。
您的 'playback' 方法正在做两件不同的事情(两者都不涉及回放)。你可能想打破它。你可以有一个 setup()
来做那些只需要做一次的事情(创建音轨,设置它们的输出,设置回调)和一个 rewriteSequence()
方法,当你想要的时候被调用重写曲目。这样您就可以重复使用现有曲目,而不是不断创建新曲目。
var metronomeTrack: AKMusicTrack!
var callbackTrack: AKMusicTrack!
// call this just once at the start
func setup() {
metronomeTrack = sequencer.newTrack()
metronomeTrack?.setMIDIOutput(click.midiIn)
callbackTrack = sequencer.newTrack()
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
callbackInst.callback = {status, noteNumber, velocity in
guard status == .noteOn else { return }
print("beat number: \(noteNumber + 1)")
}
}
// call this each time you want to change the sequence
func rewriteSequence() {
metronomeTrack?.clear()
callbackTrack?.clear()
for steps in 0 ... Int(measuresRowOneValue) {
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
callbackTrack?.add(noteNumber: MIDINoteNumber(steps), velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
}
// This will make sure it loops correctly:
sequencer.setLength(AKDuration(beats: Double(measuresRowOneValue)))
sequencer.enableLooping()
}
希望对您有所帮助。
我正在尝试使用 AudioKit 在小节的每个节拍上播放声音。虽然我已经通过 AudioKit 实现了
我的目的是为每个小节创建一个带有节拍值的小节结构,然后使用 MIDI 和回调来播放不同的声音,具体取决于有多少 measures/beats。谢谢!
import UIKit
import AudioKit
class ViewController: UIViewController {
let sequencer = AKSequencer()
let click = AKSynthSnare()
let callbackInst = AKCallbackInstrument()
// Create the struct that defines each line
struct Line {
var name: String
var measures: Int
var beatsPerMeasure: Int
func totalBeats() -> Int {
return (measures * beatsPerMeasure)
}
}
// Initialize intro line
var intro = Line(name: "Intro", measures: 0, beatsPerMeasure: 0)
// A function to create/update/playback the sequence on button press
func playBack() {
let metronomeTrack = sequencer.newTrack()
metronomeTrack?.setMIDIOutput(click.midiIn)
let callbackTrack = sequencer.newTrack()
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
for steps in 0 ... Int(measuresRowOneValue) {
// this will trigger the sampler on the four down beats
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the midiNote number to the current beat number
callbackTrack?.add(noteNumber: MIDINoteNumber(steps), velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the callback
callbackInst.callback = {status, noteNumber, velocity in
guard status == .noteOn else { return }
print("beat number: \(noteNumber + 1)")
}
}
}
@IBOutlet weak var rowOneLocationOne: UIImageView!
// Listener for UI display values
var measuresRowOneValue: Int = 0 {
didSet {
intro.measures = measuresRowOneValue
}
}
@IBAction func rowOnePlusButton(_ sender: UIButton) {
measuresRowOneValue += 1
}
@IBAction func rowOneMinusButton(_ sender: UIButton) {
measuresRowOneValue -= 1
}
@IBAction func playbackStart(_ sender: UIButton) {
playBack()
sequencer.play()
}
@IBAction func playbackStop(_ sender: UIButton) {
sequencer.stop()
}
@IBAction func playbackRestart(_ sender: UIButton) {
sequencer.rewind()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
AudioKit.output = click
try!AudioKit.start()
}
}
你的代码中有一些令人困惑的地方,所以我不确定这是否是你唯一的问题,但至少,每次你改变序列的长度时,你都需要调用 setLength()
后跟 enableLooping
。基本上,默认情况下(即,除非您明确设置长度)序列的长度将是序列中最长轨道的长度。在您的 'playback' 方法中,您是在不删除旧轨道的情况下在轨道之上添加轨道,因此它无法知道您希望序列持续多长时间。
您的 'playback' 方法正在做两件不同的事情(两者都不涉及回放)。你可能想打破它。你可以有一个 setup()
来做那些只需要做一次的事情(创建音轨,设置它们的输出,设置回调)和一个 rewriteSequence()
方法,当你想要的时候被调用重写曲目。这样您就可以重复使用现有曲目,而不是不断创建新曲目。
var metronomeTrack: AKMusicTrack!
var callbackTrack: AKMusicTrack!
// call this just once at the start
func setup() {
metronomeTrack = sequencer.newTrack()
metronomeTrack?.setMIDIOutput(click.midiIn)
callbackTrack = sequencer.newTrack()
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
callbackInst.callback = {status, noteNumber, velocity in
guard status == .noteOn else { return }
print("beat number: \(noteNumber + 1)")
}
}
// call this each time you want to change the sequence
func rewriteSequence() {
metronomeTrack?.clear()
callbackTrack?.clear()
for steps in 0 ... Int(measuresRowOneValue) {
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
callbackTrack?.add(noteNumber: MIDINoteNumber(steps), velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
}
// This will make sure it loops correctly:
sequencer.setLength(AKDuration(beats: Double(measuresRowOneValue)))
sequencer.enableLooping()
}
希望对您有所帮助。