Эквивалент MusicTrackSetDestNode для AVAudioUnitSampler (AVAudioEngine)?
Следуя этой статье в блоге , я могу подключить MusicTrack в MusicSequence к нужному AUNode в AUGraph.
Поскольку AUGraph устарел, я ищу эквивалент AVAudioEngine. Есть ли способ для MusicTrack воспроизводить ноты MIDI для отдельного и определенного AVAudioUnitSampler?
Ниже приведен мой код.
func createMusicSequence() -> MusicSequence {
var musicSequence: MusicSequence?
var status = NewMusicSequence(&musicSequence)
if status != noErr {
print("bad status when creating a musicSequence \(status)")
}
// add tracks
var pianoTrack: MusicTrack?
status = MusicSequenceNewTrack(musicSequence!, &pianoTrack)
if status != noErr {
print("error creating piano track \(status)")
}
var metronomeTrack: MusicTrack?
status = MusicSequenceNewTrack(musicSequence!, &metronomeTrack)
if status != noErr {
print("error creating metronome track \(status)")
}
var time = MusicTimeStamp(0.0)
for i:UInt8 in 60...80 {
var mess = MIDINoteMessage(channel: 0,
note: i,
velocity: 64,
releaseVelocity: 0,
duration: 1.0)
status = MusicTrackNewMIDINoteEvent(pianoTrack!, time, &mess)
if status != noErr {
print("failed to assign note to piano track")
}
mess = MIDINoteMessage(channel: 0,
note: 77,
velocity: 64,
releaseVelocity: 0,
duration: 1.0)
status = MusicTrackNewMIDINoteEvent(metronomeTrack!, time, &mess)
if status != noErr {
print("failed to assign mess to the metronome track")
}
time += 1
}
// associating the musicSequence with the AUGraph
MusicSequenceSetAUGraph(musicSequence!, processingGraph!)
// in order for the track to be connected to the desired node, the below needs to be configured after associating the musicSequence with the AUGraph
MusicSequenceGetIndTrack(musicSequence!, 0, &pianoTrack)
MusicTrackSetDestNode(pianoTrack!, pianoNode)
MusicSequenceGetIndTrack(musicSequence!, 1, &metronomeTrack)
MusicTrackSetDestNode(metronomeTrack!, metronomeNode)
return musicSequence!
}
Изменить. Я нашел решение своей проблемы с помощью AudioKit.
class PlaySound {
static let shared = PlaySound()
// need to set Background Modes
var pianoSampler = MIDISampler(name: "piano")
var sequencer = AppleSequencer()
var metronomeSampler = MIDISampler(name: "metronome")
var mixer = Mixer()
var engine = AudioEngine()
private init() {
setup()
setSequence()
}
func play() {
sequencer.play()
}
func setup() {
mixer.addInput(pianoSampler)
mixer.addInput(metronomeSampler)
engine.output = mixer
loadSF2(name: "Nice-Steinway-Lite-v3.0", ext: "sf2", preset: 0, sampler: pianoSampler)
loadMetronome(name: "Metronom", ext: "sf2", preset: 48, sampler: metronomeSampler)
do {
try engine.start()
} catch {
print("error starting the engine: \(error)")
}
}
func loadSF2(name: String, ext: String, preset: Int, sampler: MIDISampler) {
guard let url = Bundle.main.url(forResource: name, withExtension: ext) else {
print("Could not get SoundFont URL")
return
}
do {
try sampler.loadMelodicSoundFont(url: url, preset: preset)
} catch {
print("can not load SoundFont \(name) with error: \(error)")
}
}
func loadMetronome(name: String, ext: String, preset: Int, sampler: MIDISampler) {
do {
try sampler.loadSoundFont(name, preset: preset, bank: 128, in: .main)
} catch {
print("can not load SoundFont \(name) with error: \(error)")
}
}
func setSequence() {
let pianoTrackManager = sequencer.newTrack("piano")
let metronomeTrackManager = sequencer.newTrack("metronome")
var time = Duration(beats: 0.0)
for _ in 0...10 {
let note = UInt8.random(in: 48...72)
pianoTrackManager?.add(noteNumber: MIDINoteNumber(note), velocity: 64, position: time, duration: Duration(beats: 0.5))
metronomeTrackManager?.add(noteNumber: 77, velocity: 64, position: time, duration: Duration(beats: 0.5))
time += Duration(beats: 1.0)
}
sequencer.setTempo(30)
pianoTrackManager?.setMIDIOutput(pianoSampler.midiIn)
metronomeTrackManager?.setMIDIOutput(metronomeSampler.midiIn)
}
}