2 #include <jack/midiport.h>
8 static int get_effective_bpm(qn_pattern_t
* pat
, int base_beats_per_minute
) {
9 int bpm
= base_beats_per_minute
;
10 if(pat
->bpm_relation
== RelativeToBase
&& bpm
+pat
->beats_per_minute
> 0) {
11 bpm
+= pat
->beats_per_minute
;
16 static void set_playheads(qn_context_t
* ctx
, int pattern_advanced
, enum eventset evtset
) {
18 qn_pattern_t
*start_pattern
= NULL
, *newest_pattern
= NULL
;
21 start_pattern
= newest_pattern
= ctx
->next_pattern_func(ctx
);
24 start_pattern
= newest_pattern
= ctx
->run
->curr
;
25 if(pattern_advanced
) {
26 newest_pattern
= ctx
->next_pattern_func(ctx
);
30 start_pattern
= newest_pattern
= ctx
->run
->prev
;
31 if(pattern_advanced
) {
40 if(pattern_advanced
&& start_pattern
) {
41 // Reset playhead to 0 for the past pattern. If the
42 // newest pattern is the same as the old one, the next
43 // block will overwrite the 0 with playhead_tmp
44 for(k
=0;k
<start_pattern
->npatternvoices
;k
++) {
45 qn_patternvoice_t
* pv
= start_pattern
->patternvoices
+ k
;
46 pv
->playhead
[evtset
] = 0;
50 // Set playhead for the newest pattern.
52 for(k
=0;k
<newest_pattern
->npatternvoices
;k
++) {
53 qn_patternvoice_t
* pv
= newest_pattern
->patternvoices
+ k
;
54 pv
->playhead
[evtset
] = pv
->playhead_tmp
[evtset
];
59 static void accumulate_pattern_events(qn_context_t
* ctx
, jack_port_t
* port
,
60 qn_pattern_t
* pat
, int* nout
, qn_outevent_t
* out
,
61 jack_nframes_t fill_last_nframes
,
62 int* pattern_advanced
, enum eventset evtset
) {
64 qn_runstate_t
* run
= ctx
->run
;
66 // If we straddle two patterns, the latter one will only
67 // want to fill a subset of frames with events.
68 while(fill_last_nframes
) {
69 // Inside this loop assumes we're working within a single pattern
70 // (pat). If we advance to a new pattern, we advance this loop and
71 // reduce fill_last_nframes.
74 for(k
=0;k
<pat
->npatternvoices
;k
++) {
75 qn_patternvoice_t
* pv
= pat
->patternvoices
+ k
;
76 pv
->playhead_tmp
[evtset
] = pv
->playhead
[evtset
];
79 int curr_bpm
= get_effective_bpm(run
->curr
,run
->base_beats_per_minute
);
80 int this_bpm
= get_effective_bpm(pat
,run
->base_beats_per_minute
);
81 int curr_beat_len
= (run
->sample_rate
* 60) / curr_bpm
;
82 int this_beat_len
= (run
->sample_rate
* 60) / this_bpm
;
84 // When the longest pv completes, the pattern advances from curr
86 jack_nframes_t til_curr_pattern_end
=
87 (run
->curr
->longest_pv
->nbeats
* curr_beat_len
)
88 - run
->curr
->longest_pv
->playhead
[CURRENT
];
91 jack_nframes_t fill_last_nframes_in_pv
;
92 for(j
=0; j
<pat
->npatternvoices
; j
++) {
93 fill_last_nframes_in_pv
= fill_last_nframes
;
94 qn_patternvoice_t
* pv
= pat
->patternvoices
+ j
;
96 int pv_len
= pv
->nbeats
* this_beat_len
;
100 if(evtset
== PREFIX
) {
101 qn_patternvoice_t
*current
= run
->curr
->longest_pv
;
104 jack_nframes_t longest_len
= current
->nbeats
* ((run
->sample_rate
* 60) / (get_effective_bpm(run
->curr
,run
->base_beats_per_minute
)));
105 int longest_playhead
= current
->playhead
[CURRENT
];
107 pv
->playhead_tmp
[PREFIX
] = longest_playhead
- longest_len
;
108 } else if(evtset
== SUFFIX
) {
110 qn_patternvoice_t
*current
= run
->curr
->longest_pv
;
111 jack_nframes_t longest_len
= run
->prev
->longest_pv
->nbeats
*
112 ((run
->sample_rate
* 60) /
113 (get_effective_bpm(run
->prev
,run
->base_beats_per_minute
)));
115 int longest_playhead
= current
->playhead
[CURRENT
];
116 pv_end
= pv_len
+ longest_playhead
;
118 setting_suffix_playheadtmp
:
119 pv
->playhead_tmp
[SUFFIX
] = longest_len
+ longest_playhead
;
126 int range_start
= pv
->playhead_tmp
[evtset
];
127 int range_end
= range_start
+ fill_last_nframes
;
129 // Don't collect suffix events in current pattern
130 if(fill_last_nframes
> til_curr_pattern_end
) {
131 range_end
= range_start
+ til_curr_pattern_end
;
134 int maybe_more_loops
= 1;
135 while(maybe_more_loops
) {
136 if(pv
->voice
->port
== port
) {
138 for(k
=0; k
<pv
->nevents
; k
++) {
139 qn_event_t ev
= pv
->events
[k
];
141 // evtime is expressing a value as a frame index.
142 // However, jack_nframes_t is unsigned and we need to
143 // support negative indices (prefixes).
144 int evtime
= (this_beat_len
* ev
.start_tick
)
145 / pat
->tbm_ticks_per_beat
;
147 // Enforce some space between note off and subsequent
148 // note on, otherwise the later note may not sound
150 # define NOTE_OFF_EARLY_NFRAMES (this_beat_len/8)
151 if((ev
.data
[0] & 0xf0) == 0x80) {
152 evtime
-= NOTE_OFF_EARLY_NFRAMES
;
153 if (evtime
< 0 && evtset
!= PREFIX
) {
157 # define MAX_OUT_EVENTS 1024
159 if(evtime
>= range_start
160 && evtime
< range_end
161 && *nout
< MAX_OUT_EVENTS
) {
163 qn_outevent_t
* outev
= out
+ *nout
;
165 // time in the out event must be indexed
166 // with 0 being the start of nframes
167 outev
->at
= evtime
- pv
->playhead_tmp
[evtset
];
169 outev
->data
[0] = ev
.data
[0];
170 outev
->data
[1] = ev
.data
[1];
171 outev
->data
[2] = ev
.data
[2];
173 switch(ev
.data
[0] & 0xf0) {
174 case 0x90: // note on
175 case 0x80: // note off
176 case 0xb0: // control change
177 outev
->data
[0] |= pv
->voice
->channel
;
185 } // if(pv->voice->port == port)
188 if(range_end
>= pv_end
&& evtset
==CURRENT
) {
189 // We are straddling the boundary of this loop and something.
191 if(fill_last_nframes
> til_curr_pattern_end
) {
192 // This is the end of the pattern, and
193 // We're straddling two patterns
194 maybe_more_loops
= 0;
195 *pattern_advanced
= 1;
197 // Loop this patternvoice because there's
198 // still a longer one in progress
199 range_start
= pv_end
- pv_len
;
201 pv
->playhead_tmp
[evtset
] = range_start
;
204 fill_last_nframes_in_pv
= range_end
- pv_end
;
207 // Simple case, this patternvoice didn't wrap
208 maybe_more_loops
= 0;
209 fill_last_nframes_in_pv
= 0;
210 if(evtset
==CURRENT
) {
211 pv
->playhead_tmp
[evtset
] = range_end
;
214 } // while(maybe_more_loops)
215 } // loop patternvoices
218 fill_last_nframes
= fill_last_nframes_in_pv
;
220 if(*pattern_advanced
&& evtset
==CURRENT
) {
221 pat
= ctx
->next_pattern_func(ctx
);
224 for(k
=0;k
<pat
->npatternvoices
;k
++) {
225 qn_patternvoice_t
* pv
= pat
->patternvoices
+ k
;
226 pv
->playhead_tmp
[evtset
] = 0;
230 } // while(fill_last_nframes)
233 int process(jack_nframes_t nframes
, void *arg
) {
234 qn_context_t
* ctx
= (qn_context_t
*)arg
;
235 qn_runstate_t
* run
= ctx
->run
;
237 // Clear all port buffers. Jack doesn't clear them
240 for(i
=0; i
<ctx
->config
->noutports
; i
++) {
241 jack_port_t
* port
= run
->ports
[i
];
242 void* port_buf
= jack_port_get_buffer( port
, nframes
);
243 jack_midi_clear_buffer(port_buf
);
246 jack_transport_state_t transport
= jack_transport_query(run
->client
, NULL
);
248 // If stopping, send "All Notes Off" MIDI message
249 if(transport
!= run
->transtate
) {
250 run
->transtate
= transport
;
251 if(transport
== JackTransportStopped
) {
252 for(i
=0; i
<ctx
->config
->noutports
; i
++) {
253 jack_port_t
* port
= run
->ports
[i
];
255 int channels_encountered
[16];
257 for(ce
=0;ce
<16;ce
++) {
258 channels_encountered
[ce
] = 0;
261 void* port_buf
= jack_port_get_buffer( port
, nframes
);
262 jack_midi_clear_buffer(port_buf
);
265 for(j
=0; j
<ctx
->config
->nvoices
; j
++) {
266 qn_voice_t
* voice
= ctx
->config
->voices
+ j
;
267 if(voice
->port
== port
) {
269 // Don't write multiple messages per-channel per-port
270 if(channels_encountered
[voice
->channel
]) continue;
272 channels_encountered
[voice
->channel
] = 1;
274 unsigned char val
[NBYTES_MIDI
];
275 val
[0] = (176 | voice
->channel
);
278 if(jack_midi_event_write(port_buf
,0,val
,NBYTES_MIDI
)) {
279 printf("Couldn't reserve space for a note off event.\n");
287 if(transport
!= JackTransportRolling
) {
291 int pattern_advanced
= 0;
293 // Write a list of output events, grouped by output port
294 for(i
=0; i
<ctx
->config
->noutports
; i
++) {
295 jack_port_t
* port
= run
->ports
[i
];
297 // We can't write events to the actual port_buf yet since they
298 // would be out of order. Use a fixed buffer for our intermediate
301 qn_outevent_t out
[MAX_OUT_EVENTS
];
303 accumulate_pattern_events(ctx
,port
,ctx
->next_pattern_func(ctx
),
304 &nout
,out
,nframes
,&pattern_advanced
, PREFIX
);
305 accumulate_pattern_events(ctx
,port
,run
->prev
,
306 &nout
,out
,nframes
,&pattern_advanced
, SUFFIX
);
307 accumulate_pattern_events(ctx
,port
,run
->curr
,
308 &nout
,out
,nframes
,&pattern_advanced
, CURRENT
);
312 qsort(out
,nout
,sizeof(qn_outevent_t
),cmp_outevent
);
314 void* port_buf
= jack_port_get_buffer( port
, nframes
);
315 jack_midi_clear_buffer(port_buf
);
317 jack_midi_data_t
* buffer
;
319 for(j
=0; j
<nout
; j
++) {
320 qn_outevent_t
* evt
= out
+ j
;
322 buffer
= jack_midi_event_reserve(port_buf
, evt
->at
, NBYTES_MIDI
);
324 memcpy(buffer
,evt
->data
,NBYTES_MIDI
);
326 printf("Couldn't send event, probably the time %d is wrong.\n",
333 set_playheads(ctx
,pattern_advanced
,PREFIX
);
334 set_playheads(ctx
,pattern_advanced
,SUFFIX
);
335 set_playheads(ctx
,pattern_advanced
,CURRENT
);
337 // Calculate bar/beat/tick since we are a jack timebase master.
338 // It's easier to do this before we advance the pattern than
339 // to do it in timebase() where we have to look backwards.
340 jack_nframes_t frames_left
= nframes
;
341 qn_pattern_t
* pat
= run
->curr
;
342 while(frames_left
&& pat
) {
343 int bpm
= get_effective_bpm(pat
,run
->base_beats_per_minute
);
344 jack_nframes_t tick_len
= (run
->sample_rate
* 60) / (bpm
* pat
->tbm_ticks_per_beat
);
346 run
->frame_in_tick
+= frames_left
;
347 if(run
->frame_in_tick
> tick_len
) {
348 // We advanced a tick
349 run
->tbm_bar_start_tick
++;
351 if(run
->tbm_tick
> pat
->tbm_ticks_per_beat
) {
352 // We advanced a beat
356 if(run
->tbm_beat
> pat
->tbm_beats_per_bar
) {
358 run
->tbm_bar_start_tick
= 1;
362 if(run
->tbm_bar
*pat
->tbm_beats_per_bar
> pat
->longest_pv
->nbeats
) {
363 // We advanced to the next pattern
364 pat
= ctx
->next_pattern_func(ctx
);
369 frames_left
-= (run
->frame_in_tick
- tick_len
);
370 run
->frame_in_tick
= 0;
372 // still in same tick
376 // End BBT calculations
378 if(pattern_advanced
) {
379 run
->prev
= run
->curr
;
380 run
->curr
= ctx
->next_pattern_func(ctx
);
382 if(run
->curr
&& run
->curr
->bpm_relation
== Absolute
) {
383 run
->base_beats_per_minute
= run
->curr
->beats_per_minute
;
390 void timebase(jack_transport_state_t state
,
391 jack_nframes_t nframes
,
392 jack_position_t
*pos
,
396 pos
->valid
= (JackPositionBBT
| JackBBTFrameOffset
);
398 qn_context_t
* ctx
= (qn_context_t
*)arg
;
400 if(new_pos
&& pos
->frame
==0) {
402 qn_reset_playhead(ctx
);
404 // Report the song time
405 pos
->frame
= ctx
->run
->elapsed
;
408 qn_runstate_t
* run
= ctx
->run
;
410 pos
->bar
= run
->tbm_bar
;
411 pos
->beat
= run
->tbm_beat
;
412 pos
->tick
= run
->tbm_tick
;
413 pos
->bar_start_tick
= run
->tbm_bar_start_tick
;
414 pos
->bbt_offset
= run
->frame_in_tick
;
416 pos
->beats_per_bar
= run
->curr
->tbm_beats_per_bar
;
417 pos
->beat_type
= run
->curr
->tbm_beat_type
;
418 pos
->ticks_per_beat
= run
->curr
->tbm_ticks_per_beat
;
419 // TODO: set bpm to interpolated value as per transport.h
420 pos
->beats_per_minute
= get_effective_bpm(run
->curr
,run
->base_beats_per_minute
);