Fix playback of the first note in each layer in cloned programs.
[calfbox.git] / pattern-maker.c
blob479370462d5a7e2115bccbce563edef70de3ec2b
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 "config.h"
20 #include "errors.h"
21 #include "pattern.h"
22 #include "pattern-maker.h"
23 #include "song.h"
24 #include <glib.h>
25 #if USE_LIBSMF
26 #include <smf.h>
27 #endif
29 struct event_entry
31 uint32_t time;
32 uint8_t data[4];
35 static gint event_entry_compare(gconstpointer a, gconstpointer b, gpointer unused)
37 const struct event_entry *ea = a, *eb = b;
38 // Event ordering - it's to ensure bank changes are emitted before program
39 // changes and program changes are emitted before notes.
40 static const char event_class[8] = {
41 8, // Note Off
42 9, // Note On
43 20, // Poly Pressure
44 4, // Control Change
45 6, // Program Change
46 16, // Mono Pressure
47 18, // Pitch Wheel
48 0, // SysEx/Realtime
51 if (ea->time < eb->time)
52 return -1;
53 if (ea->time == eb->time && event_class[(ea->data[0] >> 4) & 7] < event_class[(eb->data[0] >> 4) & 7])
54 return -1;
55 if (ea->time == eb->time && (ea->data[0] & 15) < (eb->data[0] & 15))
56 return -1;
57 if (ea->time == eb->time && ea->data[0] == eb->data[0] && ea->data[1] < eb->data[1])
58 return -1;
59 if (ea->time == eb->time && ea->data[0] == eb->data[0] && ea->data[1] == eb->data[1])
60 return 0;
61 return +1;
64 static void event_entry_destroy(gpointer p)
66 struct event_entry *e = p;
67 free(e);
70 struct cbox_midi_pattern_maker
72 CBOX_OBJECT_HEADER()
73 GTree *events;
76 struct cbox_midi_pattern_maker *cbox_midi_pattern_maker_new(void)
78 struct cbox_midi_pattern_maker *maker = malloc(sizeof(struct cbox_midi_pattern_maker));
79 maker->events = g_tree_new_full(event_entry_compare, NULL, event_entry_destroy, NULL);
80 return maker;
84 void cbox_midi_pattern_maker_add(struct cbox_midi_pattern_maker *maker, uint32_t time, uint8_t cmd, uint8_t val1, uint8_t val2)
86 struct event_entry *e = malloc(sizeof(struct event_entry));
87 e->time = time;
88 e->data[0] = cmd;
89 e->data[1] = val1;
90 e->data[2] = val2;
92 g_tree_insert(maker->events, e, NULL);
95 void cbox_midi_pattern_maker_add_mem(struct cbox_midi_pattern_maker *maker, uint32_t time, const uint8_t *src, uint32_t len)
97 if (len > 3)
99 g_warning("Event size %d not supported yet, ignoring", (int)len);
100 return;
102 struct event_entry *e = malloc(sizeof(struct event_entry));
103 e->time = time;
104 memcpy(e->data, src, len);
106 g_tree_insert(maker->events, e, NULL);
109 struct traverse_state
111 struct cbox_midi_event *events;
112 int pos;
115 static gboolean traverse_func(gpointer key, gpointer value, gpointer pstate)
117 struct traverse_state *state = pstate;
118 struct event_entry *e = key;
119 struct cbox_midi_event *event = &state->events[state->pos++];
120 event->time = e->time;
121 event->size = midi_cmd_size(e->data[0]);
122 memcpy(event->data_inline, &e->data[0], 3);
123 return FALSE;
126 extern void cbox_song_add_pattern(struct cbox_song *song, struct cbox_midi_pattern *pattern);
128 struct cbox_midi_pattern *cbox_midi_pattern_maker_create_pattern(struct cbox_midi_pattern_maker *maker, struct cbox_song *song, gchar *name)
130 struct cbox_midi_pattern *p = malloc(sizeof(struct cbox_midi_pattern));
131 CBOX_OBJECT_HEADER_INIT(p, cbox_midi_pattern, CBOX_GET_DOCUMENT(song));
132 cbox_command_target_init(&p->cmd_target, cbox_midi_pattern_process_cmd, p);
133 p->owner = NULL;
134 p->name = name;
135 p->event_count = g_tree_nnodes(maker->events);
136 p->events = malloc(sizeof(struct cbox_midi_event[1]) * p->event_count);
138 struct traverse_state st = { p->events, 0 };
140 g_tree_foreach(maker->events, traverse_func, &st);
142 CBOX_OBJECT_REGISTER(p);
144 cbox_song_add_pattern(song, p);
146 return p;
149 #if USE_LIBSMF
150 gboolean cbox_midi_pattern_maker_load_smf(struct cbox_midi_pattern_maker *maker, const char *filename, int *length, GError **error)
152 smf_t *smf = smf_load(filename);
153 if (!smf)
155 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot load SMF file '%s'", filename);
156 return FALSE;
159 int ppqn = smf->ppqn;
160 smf_event_t *event = NULL;
161 while ((event = smf_get_next_event(smf)) != NULL) {
162 if (smf_event_is_metadata(event))
163 continue;
165 cbox_midi_pattern_maker_add_mem(maker, event->time_pulses * 1.0 * PPQN / ppqn, event->midi_buffer, event->midi_buffer_length);
167 if (length)
168 *length = smf_get_length_pulses(smf) * 1.0 * PPQN / ppqn;
169 smf_delete(smf);
171 return TRUE;
173 #endif
175 void cbox_midi_pattern_maker_destroy(struct cbox_midi_pattern_maker *maker)
177 g_tree_destroy(maker->events);
178 free(maker);