Implement MIDI clock
[quincer.git] / src / context.c
blob0808d9050844b6d91136d8729810fd79393537e5
1 #include "context.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 qn_pattern_t* loop_one(void* ctx) {
7 qn_context_t* real_ctx = ctx;
8 return real_ctx->run->curr;
11 static qn_pattern_t* advance_pattern(void* ctx, int loop) {
12 qn_context_t* real_ctx = ctx;
13 qn_config_t* config = real_ctx->config;
14 int i;
15 for(i=0; i<config->npatterns; i++) {
16 qn_pattern_t* pat = config->patterns + i;
17 if(pat == real_ctx->run->curr) {
18 int patindex = i+1;
19 if(patindex==config->npatterns) {
20 if(loop) {
21 patindex = 0;
22 } else {
23 break;
26 return config->patterns + patindex;
29 return NULL;
31 qn_pattern_t* loop_all(void* ctx) {
32 return advance_pattern(ctx,1);
34 qn_pattern_t* once_through(void* ctx) {
35 return advance_pattern(ctx,0);
38 qn_config_t* qn_get_fake_config() {
39 qn_config_t* config = malloc(sizeof(qn_config_t));
40 qn_init_config(config);
42 config->noutports = 1;
43 char* portname = "fluidsynth";
44 config->outports = malloc(sizeof(qn_config_port_t) * config->noutports);
45 config->outports[0].name = strndup(portname,strlen(portname));
46 config->outports[0].clock_numerator = 0;
47 config->outports[0].clock_denominator = 0;
49 config->nvoices = 1;
50 config->voices = malloc(sizeof(qn_voice_t) * config->nvoices);
51 char* voicename = "bass";
52 config->voices[0].name = strndup(voicename,strlen(voicename));
53 int i;
54 for(i=0; i<config->noutports; i++) {
55 /* fprintf(stderr,"First, does %s equal %s\n","fluidsynth",config->outports[i]); */
56 if(!strcmp("fluidsynth",config->outports[i].name)) {
57 config->voices[0].portname = config->outports[i].name;
58 break;
61 config->voices[0].channel = 14;
62 config->voices[0].port = NULL;
64 config->npatterns = 2;
65 config->patterns = malloc(sizeof(qn_pattern_t) * config->npatterns);
67 qn_pattern_t* p;
68 p = config->patterns;
69 p->npatternvoices = 2;
70 p->patternvoices = malloc(sizeof(qn_patternvoice_t) * p->npatternvoices);
71 p->beats_per_minute = 144;
72 p->bpm_relation = Absolute;
73 p->tbm_ticks_per_beat = 2;
74 p->tbm_beats_per_bar = 4;
75 p->tbm_beat_type = 4;
77 qn_patternvoice_t* pv = p->patternvoices + 0;
78 pv->voice = config->voices + 0;
79 pv->nbeats = 4;
80 pv->nevents = 2;
81 pv->events = malloc(sizeof(qn_event_t) * pv->nevents);
82 pv->events[0].start_tick = 0;
83 pv->events[0].data[0] = 0x90; // note on
84 pv->events[0].data[1] = 60; // pitch
85 pv->events[0].data[2] = 110; // vel
86 pv->events[1].start_tick = 6;
87 pv->events[1].data[0] = 0x80; // note off
88 pv->events[1].data[1] = 60; // pitch
90 pv = p->patternvoices + 1;
91 pv->voice = config->voices + 0;
92 pv->nbeats = 1;
93 pv->nevents = 2;
94 pv->events = malloc(sizeof(qn_event_t) * pv->nevents);
95 pv->events[0].start_tick = 0;
96 pv->events[0].data[0] = 0x90; // note on
97 pv->events[0].data[1] = 53; // pitch
98 pv->events[0].data[2] = 64; // vel
99 pv->events[1].start_tick = 1;
100 pv->events[1].data[0] = 0x80; // note off
101 pv->events[1].data[1] = 53; // pitch
105 p = config->patterns + 1;
106 p->npatternvoices = 1;
107 p->patternvoices = malloc(sizeof(qn_patternvoice_t) * p->npatternvoices);
108 p->beats_per_minute = 56;
109 p->tbm_ticks_per_beat = 2;
110 p->tbm_beats_per_bar = 4;
111 p->tbm_beat_type = 4;
112 p->bpm_relation = RelativeToBase;
114 pv = p->patternvoices + 0;
115 pv->voice = config->voices + 0;
116 pv->nbeats = 4;
117 pv->nevents = 12;
118 pv->events = malloc(sizeof(qn_event_t) * pv->nevents);
119 pv->events[0].start_tick = 0;
120 pv->events[0].data[0] = 0x90; // note on
121 pv->events[0].data[1] = 58; // pitch
122 pv->events[0].data[2] = 64; // vel
123 pv->events[1].start_tick = 1;
124 pv->events[1].data[0] = 0x80; // note off
125 pv->events[1].data[1] = 58; // pitch
127 pv->events[2].start_tick = 0;
128 pv->events[2].data[0] = 0x90; // note on
129 pv->events[2].data[1] = 67; // pitch
130 pv->events[2].data[2] = 64; // vel
131 pv->events[3].start_tick = 2;
132 pv->events[3].data[0] = 0x80; // note off
133 pv->events[3].data[1] = 67; // pitch
135 pv->events[4].start_tick = 2;
136 pv->events[4].data[0] = 0x90; // note on
137 pv->events[4].data[1] = 58; // pitch
138 pv->events[4].data[2] = 64; // vel
139 pv->events[5].start_tick = 3;
140 pv->events[5].data[0] = 0x80; // note off
141 pv->events[5].data[1] = 58; // pitch
144 pv->events[6].start_tick = 4;
145 pv->events[6].data[0] = 0x90; // note on
146 pv->events[6].data[1] = 59; // pitch
147 pv->events[6].data[2] = 64; // vel
148 pv->events[7].start_tick = 5;
149 pv->events[7].data[0] = 0x80; // note off
150 pv->events[7].data[1] = 59; // pitch
152 pv->events[8].start_tick = 4;
153 pv->events[8].data[0] = 0x90; // note on
154 pv->events[8].data[1] = 67; // pitch
155 pv->events[8].data[2] = 64; // vel
156 pv->events[9].start_tick = 6;
157 pv->events[9].data[0] = 0x80; // note off
158 pv->events[9].data[1] = 67; // pitch
160 pv->events[10].start_tick = 6;
161 pv->events[10].data[0] = 0x90; // note on
162 pv->events[10].data[1] = 59; // pitch
163 pv->events[10].data[2] = 64; // vel
164 pv->events[11].start_tick = 7;
165 pv->events[11].data[0] = 0x80; // note off
166 pv->events[11].data[1] = 59; // pitch
168 config->next_pattern_func = loop_all;
170 return config;
173 void qn_init_config(qn_config_t* config) {
174 config->nvoices = 0;
175 config->voices = NULL;
176 config->noutports = 0;
177 config->outports = NULL;
178 config->npatterns = 0;
179 config->patterns = NULL;
180 config->next_pattern_func = NULL;
183 qn_context_t* qn_init_context(qn_config_t* config, jack_client_t* client) {
184 qn_context_t* ctx = malloc(sizeof(qn_context_t));
185 ctx->config = config;
187 ctx->run = malloc(sizeof(qn_runstate_t));
188 ctx->run->client = client;
189 ctx->run->ports = malloc(sizeof(qn_port_t*) * config->noutports);
190 ctx->run->awaiting_common_start_beat = 0;
191 int i;
192 for(i=0; i<config->noutports; i++) {
193 ctx->run->ports[i] = malloc(sizeof(qn_port_t));
194 ctx->run->ports[i]->jackport =
195 jack_port_register(client, config->outports[i].name,
196 JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
197 ctx->run->ports[i]->clock_numerator = config->outports[i].clock_numerator;
198 /* printf("Set num to %d\n",ctx->run->ports[i]->clock_numerator); */
199 ctx->run->ports[i]->clock_denominator = config->outports[i].clock_denominator;
200 ctx->run->ports[i]->clock_next_tick = 0;
201 ctx->run->ports[i]->clock_tick_index = 0;
204 // Set the port on each voice
205 for(i=0; i<config->nvoices; i++) {
206 int found = 0;
207 int j;
208 for(j=0; j<config->noutports; j++) {
209 /* fprintf(stderr,"Does %s equal %s\n",config->outports[j],config->voices[i].portname); */
210 if(!strcmp(config->outports[j].name,config->voices[i].portname)) {
211 config->voices[i].port = ctx->run->ports[j];
212 found = 1;
213 break;
216 if(!found) {
217 fprintf(stderr,"No port was created for this voice\n");
221 // Identify the longest patternvoice for each pattern
222 for(i=0; i<config->npatterns; i++) {
223 qn_pattern_t* pat = config->patterns + i;
224 int j, max_beats = 0;
225 for(j=0; j<pat->npatternvoices; j++) {
226 qn_patternvoice_t* pv = pat->patternvoices + j;
227 if(pv->nbeats > max_beats) {
228 max_beats = pv->nbeats;
229 pat->longest_pv = pv;
234 ctx->run->prev = NULL;
235 ctx->run->curr = config->patterns; // TODO: don't just use first-parsed pattern
237 ctx->run->sample_rate = jack_get_sample_rate(client);
239 ctx->run->transtate = JackTransportStopped;
241 if(ctx->run->curr->bpm_relation == RelativeToBase) {
242 fprintf(stderr,"First pattern must have an absolute tempo.\n");
243 exit(1);
244 } else {
245 ctx->run->base_beats_per_minute = ctx->run->curr->beats_per_minute;
248 ctx->next_pattern_func =
249 (config->next_pattern_func ? config->next_pattern_func : loop_all);
251 return ctx;
254 /* Resets all patterns to the beginning of their playhead. May be
255 called from realtime thread.
257 Note that we don't change the "current" and "next" pattern pointers
258 since controllers may set those, and therefore the first pattern
259 may vary with each song start. Exception: if "current" is NULL,
260 the song is over and we have been requested to locate 0.
262 For the same reason, the base BPM is also not reset.
264 void qn_reset_playhead(qn_context_t* ctx) {
265 qn_config_t* config = ctx->config;
266 qn_runstate_t* run = ctx->run;
268 run->elapsed = 0;
270 int i;
271 for(i=0; i<config->npatterns; i++) {
272 qn_pattern_t* pat = config->patterns + i;
273 int j;
274 for(j=0; j<pat->npatternvoices; j++) {
275 qn_patternvoice_t* pv = pat->patternvoices + j;
276 int k;
277 for(k=0;k<NEVENTSETS;k++) {
278 pv->playhead[k] = 0;
279 pv->playhead_tmp[k] = 0;
284 // Timebase master values
285 run->tbm_bar = 1;
286 run->tbm_beat = 1;
287 run->tbm_tick = 1;
288 run->tbm_bar_start_tick = 1;
289 run->frame_in_tick = 0;
291 // Song has finished, set back to start
292 if(!run->curr) {
293 run->prev = NULL;
294 run->curr = config->patterns;
298 void qn_free_config(qn_config_t* cfg) {
299 int i;
300 for(i=0; i<cfg->nvoices; i++) {
301 cfg->voices[i].port = NULL;
302 free(cfg->voices[i].name);
304 free(cfg->voices);
306 for(i=0; i<cfg->noutports; i++) {
307 free(cfg->outports[i].name);
309 free(cfg->outports);
311 for(i=0; i<cfg->npatterns; i++) {
312 qn_pattern_t* p = cfg->patterns + i;
314 if(p->patternvoices) {
315 if(p->patternvoices->nevents) {
316 free(p->patternvoices->events);
319 free(p->patternvoices);
324 if(cfg->patterns) {
325 free(cfg->patterns);
329 void qn_free_context(qn_context_t* ctx) {
331 qn_config_t* cfg = ctx->config;
333 int i;
334 for(i=0; i<cfg->noutports; i++) {
335 jack_port_unregister(ctx->run->client, ctx->run->ports[i]->jackport);
336 free(ctx->run->ports[i]);
338 free(ctx->run->ports);
339 free(ctx->run);
341 qn_free_config(cfg);
342 free(cfg);
344 free(ctx);
347 int cmp_outevent(const void* a, const void* b) {
348 const qn_outevent_t* ea = a;
349 const qn_outevent_t* eb = b;
351 // early message before late ones
352 if(ea->at < eb->at) {
353 return -1;
354 } else if(ea->at > eb->at) {
355 return 1;
358 // real-time (clock) messages over channel messages
359 int as = ((ea->data[0] & 0xf8) == 0xf8);
360 int bs = ((eb->data[0] & 0xf8) == 0xf8);
361 if(as && !bs) {
362 return -1;
363 } else if(!as && bs) {
364 return 1;
367 return 0;