Audiokit: (V5) Sequencer cannot play notes simultaneously at the same position in a track - audiokit

I have used Audiokit's both AKAppleSequencer and AKSequencer for 2 years now. This is my first iteration getting used to the new V5 version of the library. For whatever reason, I cannot get more than a single note to play simultaneously.
Below is a very simple example of what I am trying to do:
public func setupSequencerForInterval(note1: MIDINoteNumber, note2: MIDINoteNumber) {
sequencer.clear()
sequencer = Sequencer(targetNode: sampler)
sequencer.tempo = 120
sequencer.loopEnabled = false
sequencer.length = 12.0
sequencer.add(noteNumber: note1, velocity: 127, channel: 1, position: 0.0, duration: 4.0, trackIndex: 0)
sequencer.add(noteNumber: note2, velocity: 127, channel: 1, position: 4.0, duration: 4.0, trackIndex: 0)
sequencer.add(noteNumber: note1, velocity: 127, channel: 1, position: 8.0, duration: 4.0, trackIndex: 0)
sequencer.add(noteNumber: note2, velocity: 127, channel: 1, position: 8.0, duration: 4.0, trackIndex: 0)
}
Here is what it sounds like
A sequence of 3 whole notes: 1st whole note on note1, 2nd whole note on note2, 3rd whole note both note1 and note2 playing together.
I have tested my sampler to make sure it was not monophonic, and it can play notes polyphonically.
Stranger yet, if I change the last line of (adding the note 2 whole note at the same position as note 1 at position 8.0) to a position of anything greater than 8.0, the effect of polyphony occurs. You can hear that here, a value of 8.01 was used for position on the last sequencer.add call
Is this intended behavior? Is Sequencer not supposed to play multiple notes at the same position? Any guidance would be greatly appreciated, thank you!

According to the AudioKit team, this is not intended behavior and is being looked into: https://github.com/AudioKit/AudioKit/issues/2409

Related

How is the AKSequencer setup in AudioKit > 4.8?

An example of how to set up the latest version of AKSequencer is not available, so I had to assume a few things based in the previous version.
I have the following implementation for the AKAppleSequencer that works and there's audio output:
let track = sequencer.newTrack()
track?.setMIDIOutput(sampler.midiIn)
track?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: 1), duration: AKDuration(beats: 0.25))
sequencer.enableLooping(AKDuration(beats: 4))
sequencer.setTempo(self.defaultTempo)
sequencer.play()
Meanwhile, what I supposed to be enough for the latest AKSequencer has no audio output:
let track: AKSequencerTrack = self.sequencer.addTrack(for: self.sampler)
track.add(noteNumber: 60, velocity: 100, position: 1, duration: 1)
sequencer.length = 4
sequencer.loopEnabled = true
sequencer.tempo = 60
sequencer.play()
Both cases have the sampler connected to the mainMixer and are assigned to the AudioKit.output.
Since this doesn't work for the latest AKSequencer, I thought that the maybe plugging the AKSequencerTrack to the mainMixer and unplugging the sampler to the mainMixer could do? But didn't work!
mainMixer.connect(input: track)
Running out of alternatives! So, after looking for AKSequencerTrack found someone else reporting the same issue (Why is the new AKSequencer not producing any sound?), so tried:
mainMixer.connect(input: sampler)
mainMixer.connect(input: track)
Again, no sound! There's also a link to this related topic, which is similar to my previous attempt, which there's no output (How to play MIDI with AudioKit's new AKSequencer), but just to make sure changed to use the AKSampler and loaded a local sound:
sampler.loadSFZ(url: Bundle.main.url(forResource: "clock", withExtension: "wav")!)
Another failure...! There's no sound.
I'm running AudioKit 4.9.5
Just to keep my sanity, there's a method .play in AKSequencerTrack, what happens if I call it?
track.play()
No sound! Ok, what if I change the sampler back to AKSnareSynth?
let t: AKSynthSnare = AKSynthSnare()
sequencer.addTrack(for: t)
Did it play? Nope!
Do I have output at all in non AKSequencer? Yes:
let t: AKSynthSnare = AKSynthSnare()
self.mainMixer.connect(input: t)
t.play(noteNumber: 60,
velocity: MIDIVelocity(127),
channel: MIDIChannel(1))
What about the .isPlaying is it Truthy?
for track in self.sequencer.tracks {
mainMixer.connect(input: track)
track.play()
print("> > > > track.isPlaying: \(track.isPlaying)")
}
Yes, the isPlaying returns true:
> > > > track.isPlaying: true
But, nope, there's no sound!
I think the AKSequencer is a dark box for now and shouldn't be used unless someone posts an example in Github (which I searched for in source-codes but nothing at the time of writing). Or maybe I'm doing something wrong I don't know, just wasted a day of my life trying different things.
#c_booth provided the answer in the following post ( AudioKit: Using the new AKSequencer with any variety of the callback instruments )
Seems that the loop, tempo are set in the track not the sequencer itself,
// set up a track
let track = seq.addTrack(for: cbInst)
for i in 0 ..< 4 {
track.add(noteNumber: 60, position: Double(i), duration: 0.5)
}
track.length = 4.0
track.loopEnabled = true

AKOscillatorBank glitches when playing different velocities

I'm working on something that creates floating objects then plays notes when they collide. The velocity is worked out then plays a note using AKOscillatorBank play notes. When multiple notes with different velocities are sent, AKOscillatorBank starts clicking and volumes start jumping all over the place. It's like the velocity for any given note affects the volume for the whole oscillator bank.
Works fine when every note has the same velocity. Tried to use a new AKOsillator for every object instead of AKOSillatorBank but that creates its own set of problems.
oscBank = AKOscillatorBank(waveform: AKTable(.sine), attackDuration: 0.01, decayDuration: 0.4, sustainLevel: 0, releaseDuration: 0.4, pitchBend: 0, vibratoDepth: 0, vibratoRate: 0)
// each object has a playNote function that calculate velocity of object then converts to midi velocity value.
//Works fine when velocity is set to a static number eg: oscBank.play(noteNumber: midiNote, velocity: 100)
func playNote (_ velocity: CGFloat) {
oscBank.play(noteNumber: midiNote, velocity: phyVelToMidiVel(velocity))
_ = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { timer in
self.oscBank.stop(noteNumber: self.midiNote)
timer.invalidate()
}
}
func phyVelToMidiVel (_ phyVel: CGFloat) -> MIDIVelocity {
var midiVel = (127 / resizeConstant) * phyVel
if midiVel > 127 {
midiVel = 127
}
return UInt8(midiVel)
}
Loads of clicking when AKOsillatorBank is being sent multiple notes with different velocities.

AudioKit (still) missing Clock for sequencing Audiofiles

I am trying to playback audiofiles using with the sequencer in AudioKit framework.
AudioKit.output = sampler
AudioKit.start()
sampler.enableMIDI(midi.client,name: "sampler")
// sequencer start
let seq = AKSequencer()
seq.setLength(AKDuration(beats:Double(4)))
seq.enableLooping()
let pattern = seq.newTrack()
pattern?.setMIDIOutput(sampler.midiIn)
pattern!.add(noteNumber: 48, velocity: 127, position: AKDuration(beats:Double(1)), duration: AKDuration(beats:Double(0.2)), channel: 0)
pattern!.add(noteNumber: 48, velocity: 127, position: AKDuration(beats:Double(1)), duration: AKDuration(beats:Double(0.2)), channel: 0)
pattern!.add(noteNumber: 48, velocity: 127, position: AKDuration(beats:Double(2)), duration: AKDuration(beats:Double(0.2)), channel: 0)
pattern!.setLoopInfo(AKDuration( beats:Double(4) ), numberOfLoops: 80)
seq.play()
I got to the point where the AKMidiSampler will only play sine waves but not the right sample as described here
So as it turns out it is not possible to create sequences "on the fly" so i started to look for workarounds and found SelectorClock Its a workaround from the AudioKit Developers. Sadly this is not working anymore.. many of the class definitions and their properties changed.
Maybe I am not up to date and this is fixed already.. if not I'm sure there must be a go to solution to this issue.
Turn on the background capability to your target.
Choose audio.
Without this, you get just sine waves.
If you want to be completely independent from using AKSequencer you can try the following:
let metro = AKMetronome()
metro.tempo = 120.0
metro.frequency1 = 0
metro.frequency2 = 0
metro.callback = {
// your code e.g.: trigger a AKSamplePlayer() which should have been defined earlier in your code:
sample.play()
}
AudioKit.output = AKMixer(metro, sample)
try! AudioKit.start()
metro.start()
I haven‘t tested this piece of code since I am on my phone right now but it should work. I have this concept running on my iPhone 6s and it works very well. I also tried to replace AKMetronome() with my own class but I haven‘t figured out every single aspect of the sporth parameter yet. I basically want to get rid of initiating any metronome sound ( which is already set to zero in sporth so shouldn‘t produce any noise ) in the first place.. I‘ll let you know in case I‘ll achieve that.

Play a sequence of MIDI notes in swift

What is the best way to play one note after another? Here is the most functional bit of code I have right now.
let majorScale = [60, 62, 64, 65, 67, 69, 71, 72]
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
sleep(1)
sampler.stopNote(UInt8(i), onChannel: 1)
}
The problem with this method is that sleep() only takes UInt8 as parameters so I can't make a note last less than 1 second this way.
I'm a musician first and foremost. I just happen to understand a little about programming from back in college when I took a couple java classes. That said, I don't really know what other options exist.
Is there some built in MIDI player I could be using to handle note duration?
Is there a way to "sleep" less than a second, and then calculate the duration myself? As in a 1/8 note played at 100 bpm would last ((60/100)/2) = 0.3 seconds.
Should I instead be taking the note information and essentially making a MIDI file that I can then play?
How best to tackle the problem?
EDIT
Here is the updated code:
for i in majorScale {
sampler.startNote(UInt8(i), withVelocity: 127, onChannel: 1)
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
self.sampler.stopNote(UInt8(i), onChannel: 1)
}
sampler.stopNote(UInt8(i), onChannel: 1)
}
So I realized something about this. I changed the instrument to organ (instead of piano), and it does stop the notes after 1 second, or 10, or whatever I put in there, but it seems like it's going on with the for loop in the meantime, so all the notes are sounding simultaneously instead of in sequence.
I can't help with the midi aspect of this, but as for pausing or sleeping, you should use dispatch_after. Put the following code in place of the sleep(1) and the stopNote call. This will allow you to perform delays with nano second accuracy. Just change the second parameter of the dispatch_time_t() call to whatever time you need.
let pause = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(pause, dispatch_get_main_queue()) {
sampler.stopNote(UInt8(i), onChannel: 1)
}
Try to use timer to control loop through the notes array.
after note play one time, stop the notes when the timer started next time.
var playCount = 0
timer = Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(fireTimerContinue), userInfo: nil, repeats: true)
#objc func fireTimerContinue(){
var note: Int8 = 0
if(index < note_array.count){
note = Int8(note_array[index])
self.audioEngine.sampler.startNote(UInt8(note), withVelocity: UInt8(velocity), onChannel: 0)
playCount += 1
if playCount > 1 {
audioEngine.sampler.stopNote(UInt8(note), onChannel: 0)
playCount = 0
index = index + 1
}
}
}

Consecutive Animations - Watchkit

I'm looking to have a variety of animations for an apple watch app. I'm using a series of images and the method of animation is startAnimatingWithImagesInRange(). Any time I have consecutive animation instructions, only the last one in the code executes. Code looks like:
myImage.setImageNamed("testImage")
myImage.startAnimatingWithImagesInRange(NSRange(location: 0, length: 90), duration: 3, repeatCount: 1)
myImage.startAnimatingWithImagesInRange(NSRange(location: 90, length: 180), duration: 3, repeatCount: 1)
In the above code, only the second animation would play. I even tried putting them in separate functions, so I would be calling each function individually, but it still will only play the last animation in my code. I'm fairly new to this so I'm sure there is a better way but after hours and hours of research I haven't been able to come up with a solution or find one online.
This is easy as 1 + 1 :)
Here is what you want:
myImage.setImageNamed("testImage")
let duration = 3
let repeatCount = 1
Timeline.with(identifier: "MyQueuedAnimation", delay: 0.0, duration: duration * repeatCount, execution: {
myImage.startAnimatingWithImagesInRange(NSRange(location: 0, length: 90), duration: duration, repeatCount: repeatCount)
}, completion: {
myImage.startAnimatingWithImagesInRange(NSRange(location: 90, length: 180), duration: duration, repeatCount: 1)
}).start
TimelineKit - feel free to give me some feedback for my little framework. :)
The watch won't queue up animations for you, so use an NSTimer with a delay equal to the duration of the first animation and start the second animation once the timer fires.

Resources