Skip to content

Commit f0b7a1a

Browse files
committed
Don't update render observer when sequence changes.
1 parent 57e2af5 commit f0b7a1a

File tree

4 files changed

+52
-40
lines changed

4 files changed

+52
-40
lines changed

Sources/AudioKitEX/Sequencing/SequencerTrack.swift

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import AudioKit
1010
open class SequencerTrack {
1111

1212
/// Node sequencer sends data to
13-
public var targetNode: Node?
13+
public var targetNode: Node? { didSet { addRenderObserver() }}
1414

1515
/// Length of the track in beats
1616
public var length: Double = 4 { didSet { updateSequence() }}
@@ -123,7 +123,6 @@ open class SequencerTrack {
123123
}
124124

125125
private var renderObserverToken: Int?
126-
public var renderObserver: AURenderObserver?
127126

128127
private func updateSequence() {
129128
guard let block = targetNode?.avAudioNode.auAudioUnit.scheduleMIDIEventBlock else {
@@ -139,19 +138,25 @@ open class SequencerTrack {
139138

140139
let orderedEvents = sequence.beatTimeOrderedEvents()
141140
orderedEvents.withUnsafeBufferPointer { (eventsPtr: UnsafeBufferPointer<SequenceEvent>) -> Void in
142-
guard let observer = akSequencerEngineUpdateSequence(engine,
143-
eventsPtr.baseAddress,
144-
orderedEvents.count,
145-
settings,
146-
Settings.sampleRate,
147-
block) else { return }
148141

149-
guard let auAudioUnit = targetNode?.avAudioNode.auAudioUnit else { return }
142+
akSequencerEngineUpdateSequence(engine,
143+
eventsPtr.baseAddress,
144+
orderedEvents.count,
145+
settings,
146+
Settings.sampleRate,
147+
block)
150148

151-
renderObserver = observer
152-
if renderObserverToken == nil {
153-
renderObserverToken = auAudioUnit.token(byAddingRenderObserver: observer)
154-
}
149+
150+
}
151+
152+
addRenderObserver()
153+
}
154+
155+
private func addRenderObserver() {
156+
if renderObserverToken == nil {
157+
guard let observer = akSequencerGetRenderObserver(engine) else { return }
158+
guard let auAudioUnit = targetNode?.avAudioNode.auAudioUnit else { return }
159+
renderObserverToken = auAudioUnit.token(byAddingRenderObserver: observer)
155160
}
156161
}
157162
}

Sources/CAudioKitEX/Sequencing/SequencerEngine.mm

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -219,27 +219,29 @@ void akSequencerEngineRelease(SequencerEngineRef engine) {
219219
}
220220

221221
/// Updates the sequence and returns a new render observer.
222-
AURenderObserver akSequencerEngineUpdateSequence(SequencerEngineRef engine,
223-
const SequenceEvent* eventsPtr,
224-
size_t eventCount,
225-
SequenceSettings settings,
226-
double sampleRate,
227-
AUScheduleMIDIEventBlock block) {
228-
229-
// impl is captured in the render observer block.
230-
auto impl = engine->impl;
231-
222+
void akSequencerEngineUpdateSequence(SequencerEngineRef engine,
223+
const SequenceEvent* eventsPtr,
224+
size_t eventCount,
225+
SequenceSettings settings,
226+
double sampleRate,
227+
AUScheduleMIDIEventBlock block) {
232228
auto data = new SequencerData;
233229
data->settings = settings;
234230
data->sampleRate = sampleRate;
235231
data->midiBlock = block;
236232
data->events = {eventsPtr, eventsPtr+eventCount};
237-
impl->data.set(data);
233+
engine->impl->data.set(data);
234+
}
235+
236+
AURenderObserver akSequencerGetRenderObserver(SequencerEngineRef engine) {
237+
238+
// impl is captured in the render observer block.
239+
auto impl = engine->impl;
238240

239241
return ^void(AudioUnitRenderActionFlags actionFlags,
240-
const AudioTimeStamp *timestamp,
241-
AUAudioFrameCount frameCount,
242-
NSInteger outputBusNumber)
242+
const AudioTimeStamp *timestamp,
243+
AUAudioFrameCount frameCount,
244+
NSInteger outputBusNumber)
243245
{
244246
if (actionFlags != kAudioUnitRenderAction_PreRender) return;
245247
impl->process(frameCount);

Sources/CAudioKitEX/include/SequencerEngine.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@ SequencerEngineRef akSequencerEngineCreate(void);
3838
/// Release ownership of the sequencer. Sequencer is deallocated when no render observers are live.
3939
void akSequencerEngineRelease(SequencerEngineRef engine);
4040

41-
/// Updates the sequence and returns a new render observer.
42-
AURenderObserver akSequencerEngineUpdateSequence(SequencerEngineRef engine,
43-
const SequenceEvent* events,
44-
size_t eventCount,
45-
SequenceSettings settings,
46-
double sampleRate,
47-
AUScheduleMIDIEventBlock block);
41+
/// Updates the sequence atomically.
42+
void akSequencerEngineUpdateSequence(SequencerEngineRef engine,
43+
const SequenceEvent* events,
44+
size_t eventCount,
45+
SequenceSettings settings,
46+
double sampleRate,
47+
AUScheduleMIDIEventBlock block);
48+
49+
/// Returns function to be called on audio thread.
50+
AURenderObserver akSequencerGetRenderObserver(SequencerEngineRef engine);
4851

4952
/// Returns the sequencer playhead position in beats.
5053
double akSequencerEngineGetPosition(SequencerEngineRef engine);

Tests/AudioKitEXTests/SequencerEngineTests.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ class SequencerEngineTests: XCTestCase {
3434

3535
let orderedEvents = sequence.beatTimeOrderedEvents()
3636
orderedEvents.withUnsafeBufferPointer { (eventsPtr: UnsafeBufferPointer<SequenceEvent>) -> Void in
37-
let observer = akSequencerEngineUpdateSequence(engine,
38-
eventsPtr.baseAddress,
39-
orderedEvents.count,
40-
settings,
41-
44100,
42-
block)!
37+
akSequencerEngineUpdateSequence(engine,
38+
eventsPtr.baseAddress,
39+
orderedEvents.count,
40+
settings,
41+
44100,
42+
block)
43+
44+
let observer = akSequencerGetRenderObserver(engine)!
4345

4446
var timeStamp = AudioTimeStamp()
4547
timeStamp.mSampleTime = 0

0 commit comments

Comments
 (0)