AudioKit ios AKSequencer не возобновляет воспроизведение точно - PullRequest
0 голосов
/ 31 мая 2018

Я пытаюсь использовать AudioKit для воспроизведения звука при каждом ударе такта.Хотя я реализовал код из этого аналогичного вопроса, касающегося обратных вызовов через AudioKit, я не могу заставить секвенсор корректно обновлять изменения и воспроизводить.Он будет воспроизводиться точно один раз, однако после перемотки и изменения значений он будет использовать только начальные значения (или не воспроизводить их вообще).

Я намереваюсь создать структуру тактов со значениями ударов для каждого такта,затем используйте MIDI и обратный вызов для воспроизведения разных звуков в зависимости от количества тактов / ударов.Спасибо!

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()
}
}

1 Ответ

0 голосов
/ 31 мая 2018

В вашем коде есть несколько запутанных вещей, поэтому я не уверен, что это ваша единственная проблема, но, как минимум, каждый раз, когда вы изменяете длину вашей последовательности, вам нужно будет вызвать setLength() с последующим enableLooping.По сути, по умолчанию (т. Е. Если вы явно не установите длину) длина последовательности будет равна длине самой длинной дорожки в последовательности.В вашем методе «воспроизведения» вы добавляете дорожку поверх дорожки, не удаляя старые, поэтому у вас нет возможности узнать, как долго вы предполагаете эту последовательность.

Ваш метод «воспроизведения» выполняет два разных действия.вещи (ни одна из которых не включает воспроизведение).Вы могли бы хотеть сломать это.У вас может быть 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()
    }

Надеюсь, это поможет.

...