Start with empty scene as last resort option.
[calfbox.git] / pattern.c
blob8be098f74db9931adcc160fefeae3a7b4e873ab9
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "blob.h"
20 #include "config-api.h"
21 #include "pattern.h"
22 #include "pattern-maker.h"
23 #include "song.h"
25 #include <glib.h>
27 extern void cbox_song_remove_pattern(struct cbox_song *song, struct cbox_midi_pattern *pattern);
29 CBOX_CLASS_DEFINITION_ROOT(cbox_midi_pattern)
31 struct cbox_midi_pattern *cbox_midi_pattern_new_metronome(struct cbox_song *song, int ts)
33 struct cbox_midi_pattern_maker *m = cbox_midi_pattern_maker_new(song);
35 int length = PPQN;
36 int channel = cbox_config_get_int("metronome", "channel", 10);
37 int accnote = cbox_config_get_note("metronome", "note_accent", 37);
38 int note = cbox_config_get_note("metronome", "note", 37);
40 for (int i = 0; i < ts; i++)
42 int e = 2 * i;
43 int accent = !i && ts != 1;
44 cbox_midi_pattern_maker_add(m, length * i, 0x90 + channel - 1, accent ? accnote : note, accent ? 127 : 100);
45 cbox_midi_pattern_maker_add(m, length * i + 1, 0x80 + channel - 1, accent ? accnote : note, 0);
48 struct cbox_midi_pattern *p = cbox_midi_pattern_maker_create_pattern(m, song, g_strdup_printf("click-%d", ts));
49 p->loop_end = length * ts;
51 cbox_midi_pattern_maker_destroy(m);
53 return p;
56 void cbox_midi_pattern_destroyfunc(struct cbox_objhdr *objhdr)
58 struct cbox_midi_pattern *pattern = CBOX_H2O(objhdr);
59 if (pattern->owner)
60 cbox_song_remove_pattern(pattern->owner, pattern);
61 g_free(pattern->name);
62 if (pattern->events != NULL)
63 free(pattern->events);
64 free(pattern);
67 static int cbox_midi_pattern_load_smf_into(struct cbox_midi_pattern_maker *m, const char *smf)
69 int length = 0;
70 if (!cbox_midi_pattern_maker_load_smf(m, smf, &length, NULL))
72 g_error("Cannot load SMF file %s", smf);
73 return -1;
75 return length;
78 static int cbox_midi_pattern_load_melodic_into(struct cbox_midi_pattern_maker *m, const char *name, int start_pos, int transpose, int transpose_to_note)
80 gchar *cfg_section = g_strdup_printf("pattern:%s", name);
82 if (!cbox_config_has_section(cfg_section))
84 g_error("Melodic pattern '%s' not found", name);
85 g_free(cfg_section);
86 return -1;
89 gchar *smf = cbox_config_get_string(cfg_section, "smf");
90 if (smf)
91 return cbox_midi_pattern_load_smf_into(m, smf);
93 int length = PPQN * cbox_config_get_int(cfg_section, "beats", 4);
94 int gchannel = cbox_config_get_int(cfg_section, "channel", 1);
95 int gswing = cbox_config_get_int(cfg_section, "swing", 0);
96 int gres = cbox_config_get_int(cfg_section, "resolution", 4);
97 int orignote = cbox_config_get_note(cfg_section, "base_note", 24);
98 if (transpose_to_note != -1)
99 transpose += transpose_to_note - orignote;
101 for (int t = 1; ; t++)
103 gchar *tname = g_strdup_printf("track%d", t);
104 char *trkname = cbox_config_get_string(cfg_section, tname);
105 g_free(tname);
106 if (trkname)
108 tname = g_strdup_printf("%s_vel", trkname);
109 int vel = cbox_config_get_note(cfg_section, tname, 100);
110 g_free(tname);
111 tname = g_strdup_printf("%s_res", trkname);
112 int res = cbox_config_get_note(cfg_section, tname, gres);
113 g_free(tname);
114 tname = g_strdup_printf("%s_channel", trkname);
115 int channel = cbox_config_get_note(cfg_section, tname, gchannel);
116 g_free(tname);
117 tname = g_strdup_printf("%s_swing", trkname);
118 int swing = cbox_config_get_int(cfg_section, tname, gswing);
119 g_free(tname);
120 tname = g_strdup_printf("%s_notes", trkname);
121 const char *notes = cbox_config_get_string(cfg_section, tname);
122 g_free(tname);
123 if (!notes)
125 g_error("Invalid track %s", trkname);
127 const char *s = notes;
128 int i = 0, t = 0;
129 while(1)
131 if (!*s)
132 break;
134 gchar *note;
135 const char *comma = strchr(s, ',');
136 if (comma)
138 note = g_strndup(s, comma - s);
139 s = comma + 1;
141 else
143 note = g_strdup(s);
144 s += strlen(s);
147 if (*note)
149 int pitch = note_from_string(note);
151 int pos = t * PPQN / res + start_pos;
152 if (t & 1)
153 pos += PPQN * swing / (res * 24);
155 int pos2 = (t + 1) * PPQN / res + start_pos;
156 if (t & 1)
157 pos2 += PPQN * swing / (res * 24);
159 pitch += transpose;
161 cbox_midi_pattern_maker_add(m, pos, 0x90 + channel - 1, pitch, vel);
162 cbox_midi_pattern_maker_add(m, pos2 - 1, 0x80 + channel - 1, pitch, 0);
164 t++;
167 else
168 break;
171 g_free(cfg_section);
173 return length;
176 static int cbox_midi_pattern_load_drum_into(struct cbox_midi_pattern_maker *m, const char *name, int start_pos)
178 gchar *cfg_section = g_strdup_printf("drumpattern:%s", name);
180 if (!cbox_config_has_section(cfg_section))
182 g_error("Drum pattern '%s' not found", name);
183 g_free(cfg_section);
184 return -1;
187 gchar *smf = cbox_config_get_string(cfg_section, "smf");
188 if (smf)
189 return cbox_midi_pattern_load_smf_into(m, smf);
191 int length = PPQN * cbox_config_get_int(cfg_section, "beats", 4);
192 int channel = cbox_config_get_int(cfg_section, "channel", 10);
193 int gswing = cbox_config_get_int(cfg_section, "swing", 0);
194 int gres = cbox_config_get_int(cfg_section, "resolution", 4);
196 for (int t = 1; ; t++)
198 gchar *tname = g_strdup_printf("track%d", t);
199 char *trkname = cbox_config_get_string(cfg_section, tname);
200 g_free(tname);
201 if (trkname)
203 tname = g_strdup_printf("%s_note", trkname);
204 int note = cbox_config_get_note(cfg_section, tname, -1);
205 g_free(tname);
206 tname = g_strdup_printf("%s_res", trkname);
207 int res = cbox_config_get_note(cfg_section, tname, gres);
208 g_free(tname);
209 tname = g_strdup_printf("%s_swing", trkname);
210 int swing = cbox_config_get_int(cfg_section, tname, gswing);
211 g_free(tname);
212 tname = g_strdup_printf("%s_trigger", trkname);
213 const char *trigger = cbox_config_get_string(cfg_section, tname);
214 g_free(tname);
215 if (!trigger || note == -1)
217 g_error("Invalid track %s", trkname);
219 int t = 0;
220 for (int i = 0; trigger[i]; i++)
222 int pos = t * PPQN / res + start_pos;
223 if (t & 1)
224 pos += PPQN * swing / (res * 24);
225 if (trigger[i] >= '1' && trigger[i] <= '9')
227 int amt = (trigger[i] - '0') * 127 / 9;
228 cbox_midi_pattern_maker_add(m, pos, 0x90 + channel - 1, note, amt);
229 cbox_midi_pattern_maker_add(m, pos + 1, 0x80 + channel - 1, note, 0);
230 t++;
232 if (trigger[i] == 'F') // flam
234 int dflam = PPQN / 4;
235 int rnd = rand() & 7;
236 dflam += rnd / 2;
237 cbox_midi_pattern_maker_add(m, pos - dflam, 0x90 + channel - 1, note, 90+rnd);
238 cbox_midi_pattern_maker_add(m, pos - dflam + 1, 0x80 + channel - 1, note, 0);
239 cbox_midi_pattern_maker_add(m, pos , 0x90 + channel - 1, note, 120 + rnd);
240 cbox_midi_pattern_maker_add(m, pos + 1, 0x80 + channel - 1, note, 0);
241 t++;
243 if (trigger[i] == 'D') // drag
245 pos = (t + 1) * PPQN / res + start_pos;
246 //if (!(t & 1))
247 // pos += PPQN * swing / (res * 24);
248 float dflam = PPQN/8.0;
249 int rnd = rand() & 7;
250 cbox_midi_pattern_maker_add(m, pos - dflam*2, 0x90 + channel - 1, note, 70+rnd);
251 cbox_midi_pattern_maker_add(m, pos - dflam*2 + 1, 0x80 + channel - 1, note, 0);
252 cbox_midi_pattern_maker_add(m, pos - dflam, 0x90 + channel - 1, note, 60+rnd);
253 cbox_midi_pattern_maker_add(m, pos - dflam + 1, 0x80 + channel - 1, note, 0);
254 t++;
256 else if (trigger[i] == '.')
257 t++;
260 else
261 break;
264 g_free(cfg_section);
266 return length;
269 struct cbox_midi_pattern *cbox_midi_pattern_load(struct cbox_song *song, const char *name, int is_drum)
271 struct cbox_midi_pattern_maker *m = cbox_midi_pattern_maker_new(song);
273 int length = 0;
274 if (is_drum)
275 length = cbox_midi_pattern_load_drum_into(m, name, 0);
276 else
277 length = cbox_midi_pattern_load_melodic_into(m, name, 0, 0, -1);
278 struct cbox_midi_pattern *p = cbox_midi_pattern_maker_create_pattern(m, song, g_strdup(name));
279 p->loop_end = length;
281 cbox_midi_pattern_maker_destroy(m);
283 return p;
286 struct cbox_midi_pattern *cbox_midi_pattern_load_track(struct cbox_song *song, const char *name, int is_drum)
288 int length = 0;
289 struct cbox_midi_pattern_maker *m = cbox_midi_pattern_maker_new(song);
291 gchar *cfg_section = g_strdup_printf(is_drum ? "drumtrack:%s" : "track:%s", name);
293 if (!cbox_config_has_section(cfg_section))
295 g_error("Drum track '%s' not found", name);
296 g_free(cfg_section);
297 return NULL;
300 for (int p = 1; ; p++)
302 gchar *pname = g_strdup_printf("pos%d", p);
303 char *patname = cbox_config_get_string(cfg_section, pname);
304 g_free(pname);
305 if (patname)
307 int tplen = 0;
308 char *comma = strchr(patname, ',');
309 while(*patname)
311 char *v = comma ? g_strndup(patname, comma - patname) : g_strdup(patname);
312 patname = comma ? comma + 1 : patname + strlen(patname);
314 int xpval = 0, xpnote = -1;
315 if (!is_drum)
317 char *xp = strchr(v, '+');
318 if (xp)
320 *xp = '\0';
321 xpval = atoi(xp + 1);
323 else
325 xp = strchr(v, '=');
326 if (xp)
328 *xp = '\0';
329 xpnote = note_from_string(xp + 1);
333 int plen = 0;
334 int is_drum_pat = is_drum;
335 int nofs = 0;
336 if (*v == '@')
338 nofs = 1;
339 is_drum_pat = !is_drum_pat;
341 if (is_drum_pat)
342 plen = cbox_midi_pattern_load_drum_into(m, v + nofs, length);
343 else
344 plen = cbox_midi_pattern_load_melodic_into(m, v + nofs, length, xpval, xpnote);
345 g_free(v);
346 if (plen < 0)
348 cbox_midi_pattern_maker_destroy(m);
349 return NULL;
351 if (plen > tplen)
352 tplen = plen;
353 if (*patname)
354 comma = strchr(patname, ',');
356 length += tplen;
358 else
359 break;
362 g_free(cfg_section);
364 struct cbox_midi_pattern *p = cbox_midi_pattern_maker_create_pattern(m, song, g_strdup(name));
365 p->loop_end = length;
367 cbox_midi_pattern_maker_destroy(m);
369 return p;
372 struct cbox_midi_pattern *cbox_midi_pattern_new_from_blob(struct cbox_song *song, const struct cbox_blob *blob, int length)
374 struct cbox_midi_pattern_maker *m = cbox_midi_pattern_maker_new(song);
376 struct cbox_blob_serialized_event event;
377 for (size_t i = 0; i < blob->size; i += sizeof(event))
379 // not sure about alignment guarantees of Python buffers
380 memcpy(&event, ((uint8_t *)blob->data) + i, sizeof(event));
381 cbox_midi_pattern_maker_add(m, event.time, event.cmd, event.byte1, event.byte2);
384 struct cbox_midi_pattern *p = cbox_midi_pattern_maker_create_pattern(m, song, g_strdup("unnamed-blob"));
385 p->loop_end = length;
387 cbox_midi_pattern_maker_destroy(m);
389 return p;
392 struct cbox_blob *cbox_midi_pattern_to_blob(struct cbox_midi_pattern *pat, int *length)
394 if (length)
395 *length = pat->loop_end;
397 struct cbox_blob_serialized_event event;
398 int size = 0;
399 for (int i = 0; i < pat->event_count; i++)
401 // currently sysex events and the like are not supported
402 if (pat->events[i].size < 4)
403 size += sizeof(event);
406 struct cbox_blob *blob = cbox_blob_new(size);
408 size = 0;
409 uint8_t *data = blob->data;
410 for (int i = 0; i < pat->event_count; i++)
412 // currently sysex events and the like are not supported
413 const struct cbox_midi_event *src = &pat->events[i];
414 if (src->size < 4)
416 event.time = src->time;
417 event.len = src->size;
418 memcpy(&event.cmd, &src->data_inline[0], event.len);
419 memcpy(data + size, &event, sizeof(event));
420 size += sizeof(event);
423 return blob;
426 gboolean cbox_midi_pattern_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
428 struct cbox_midi_pattern *p = ct->user_data;
430 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
432 if (!cbox_check_fb_channel(fb, cmd->command, error))
433 return FALSE;
435 return cbox_execute_on(fb, NULL, "/event_count", "i", error, (int)p->event_count) &&
436 cbox_execute_on(fb, NULL, "/loop_end", "i", error, (int)p->loop_end) &&
437 cbox_execute_on(fb, NULL, "/name", "s", error, p->name) &&
438 CBOX_OBJECT_DEFAULT_STATUS(p, fb, error)
441 else if (!strcmp(cmd->command, "/name") && !strcmp(cmd->arg_types, "s"))
443 char *old_name = p->name;
444 p->name = g_strdup(CBOX_ARG_S(cmd, 0));
445 g_free(old_name);
446 return TRUE;
448 return cbox_object_default_process_cmd(ct, fb, cmd, error);