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/>.
22 #include "pattern-maker.h"
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] = {
51 if (ea
->time
< eb
->time
)
53 if (ea
->time
== eb
->time
&& event_class
[(ea
->data
[0] >> 4) & 7] < event_class
[(eb
->data
[0] >> 4) & 7])
55 if (ea
->time
== eb
->time
&& (ea
->data
[0] & 15) < (eb
->data
[0] & 15))
57 if (ea
->time
== eb
->time
&& ea
->data
[0] == eb
->data
[0] && ea
->data
[1] < eb
->data
[1])
59 if (ea
->time
== eb
->time
&& ea
->data
[0] == eb
->data
[0] && ea
->data
[1] == eb
->data
[1])
64 static void event_entry_destroy(gpointer p
)
66 struct event_entry
*e
= p
;
70 struct cbox_midi_pattern_maker
77 struct cbox_midi_pattern_maker
*cbox_midi_pattern_maker_new(uint64_t ppqn_factor
)
79 struct cbox_midi_pattern_maker
*maker
= malloc(sizeof(struct cbox_midi_pattern_maker
));
80 maker
->events
= g_tree_new_full(event_entry_compare
, NULL
, event_entry_destroy
, NULL
);
81 maker
->ppqn_factor
= ppqn_factor
;
86 void cbox_midi_pattern_maker_add(struct cbox_midi_pattern_maker
*maker
, uint32_t time
, uint8_t cmd
, uint8_t val1
, uint8_t val2
)
88 struct event_entry
*e
= malloc(sizeof(struct event_entry
));
94 g_tree_insert(maker
->events
, e
, NULL
);
97 void cbox_midi_pattern_maker_add_mem(struct cbox_midi_pattern_maker
*maker
, uint32_t time
, const uint8_t *src
, uint32_t len
)
101 g_warning("Event size %d not supported yet, ignoring", (int)len
);
104 struct event_entry
*e
= malloc(sizeof(struct event_entry
));
106 memcpy(e
->data
, src
, len
);
108 g_tree_insert(maker
->events
, e
, NULL
);
111 struct traverse_state
113 struct cbox_midi_event
*events
;
117 static gboolean
traverse_func(gpointer key
, gpointer value
, gpointer pstate
)
119 struct traverse_state
*state
= pstate
;
120 struct event_entry
*e
= key
;
121 struct cbox_midi_event
*event
= &state
->events
[state
->pos
++];
122 event
->time
= e
->time
;
123 event
->size
= midi_cmd_size(e
->data
[0]);
124 memcpy(event
->data_inline
, &e
->data
[0], 3);
128 extern void cbox_song_add_pattern(struct cbox_song
*song
, struct cbox_midi_pattern
*pattern
);
130 struct cbox_midi_pattern
*cbox_midi_pattern_maker_create_pattern(struct cbox_midi_pattern_maker
*maker
, struct cbox_song
*song
, gchar
*name
)
132 struct cbox_midi_pattern
*p
= malloc(sizeof(struct cbox_midi_pattern
));
133 CBOX_OBJECT_HEADER_INIT(p
, cbox_midi_pattern
, CBOX_GET_DOCUMENT(song
));
134 cbox_command_target_init(&p
->cmd_target
, cbox_midi_pattern_process_cmd
, p
);
137 p
->event_count
= g_tree_nnodes(maker
->events
);
138 p
->events
= malloc(sizeof(struct cbox_midi_event
[1]) * p
->event_count
);
140 struct traverse_state st
= { p
->events
, 0 };
142 g_tree_foreach(maker
->events
, traverse_func
, &st
);
144 CBOX_OBJECT_REGISTER(p
);
146 cbox_song_add_pattern(song
, p
);
152 gboolean
cbox_midi_pattern_maker_load_smf(struct cbox_midi_pattern_maker
*maker
, const char *filename
, int *length
, GError
**error
)
154 smf_t
*smf
= smf_load(filename
);
157 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Cannot load SMF file '%s'", filename
);
161 int ppqn
= smf
->ppqn
;
162 smf_event_t
*event
= NULL
;
163 while ((event
= smf_get_next_event(smf
)) != NULL
) {
164 if (smf_event_is_metadata(event
))
167 cbox_midi_pattern_maker_add_mem(maker
, event
->time_pulses
* 1.0 * maker
->ppqn_factor
/ ppqn
, event
->midi_buffer
, event
->midi_buffer_length
);
170 *length
= smf_get_length_pulses(smf
) * 1.0 * maker
->ppqn_factor
/ ppqn
;
177 void cbox_midi_pattern_maker_destroy(struct cbox_midi_pattern_maker
*maker
)
179 g_tree_destroy(maker
->events
);