2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2013 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/>.
24 void cbox_midi_merger_init(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*output
)
27 dest
->output
= output
;
29 cbox_midi_buffer_clear(dest
->output
);
32 // void cbox_midi_buffer_merge(struct cbox_midi_buffer *output, struct cbox_midi_buffer **inputs, int count, int *positions)
33 void cbox_midi_merger_render_to(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*output
)
37 cbox_midi_buffer_clear(output
);
38 for (struct cbox_midi_source
*p
= dest
->inputs
; p
; p
= p
->next
)
44 struct cbox_midi_source
*first
= dest
->inputs
;
45 struct cbox_midi_source
*first_not
= NULL
;
48 struct cbox_midi_source
*earliest_source
= NULL
;
49 uint32_t earliest_time
= (uint32_t)-1;
51 for (struct cbox_midi_source
*p
= first
; p
!= first_not
; p
= p
->next
)
53 struct cbox_midi_buffer
*data
= p
->data
;
54 if (p
->bpos
< data
->count
)
56 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(data
, p
->bpos
);
57 if (event
->time
< earliest_time
)
60 earliest_time
= event
->time
;
65 // Narrow down the range from top and bottom
68 if (p
->next
== first_not
)
77 cbox_midi_buffer_copy_event(output
, cbox_midi_buffer_get_event(earliest_source
->data
, earliest_source
->bpos
), earliest_time
);
78 earliest_source
->bpos
++;
85 struct cbox_midi_source
**cbox_midi_merger_find_source(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
)
87 for (struct cbox_midi_source
**pp
= &dest
->inputs
; *pp
; pp
= &((*pp
)->next
))
88 if ((*pp
)->data
== buffer
)
93 void cbox_midi_merger_connect(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
95 if (cbox_midi_merger_find_source(dest
, buffer
) != NULL
)
98 struct cbox_midi_source
*src
= calloc(1, sizeof(struct cbox_midi_source
));
101 src
->streaming
= TRUE
;
102 src
->next
= dest
->inputs
;
103 cbox_rt_swap_pointers(rt
, (void **)&dest
->inputs
, src
);
106 void cbox_midi_merger_disconnect(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
108 struct cbox_midi_source
**pp
= cbox_midi_merger_find_source(dest
, buffer
);
112 struct cbox_midi_source
*ms
= *pp
;
113 cbox_rt_swap_pointers(rt
, (void **)pp
, ms
->next
);
117 void cbox_midi_merger_push(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
121 struct cbox_midi_source src
;
124 src
.streaming
= FALSE
;
125 src
.next
= dest
->inputs
;
126 cbox_rt_swap_pointers(rt
, (void **)&dest
->inputs
, &src
);
127 while(src
.bpos
< buffer
->count
)
128 cbox_rt_handle_cmd_queue(rt
);
129 cbox_rt_swap_pointers(rt
, (void **)&dest
->inputs
, src
.next
);
132 void cbox_midi_merger_close(struct cbox_midi_merger
*dest
)
134 struct cbox_midi_source
*p
;
138 dest
->inputs
= p
->next
;
143 ////////////////////////////////////////////////////////////////////////////////////////
145 void cbox_midi_appsink_init(struct cbox_midi_appsink
*appsink
, struct cbox_rt
*rt
)
148 cbox_midi_buffer_init(&appsink
->midibufs
[0]);
149 cbox_midi_buffer_init(&appsink
->midibufs
[1]);
150 appsink
->current_buffer
= 0;
153 void cbox_midi_appsink_supply(struct cbox_midi_appsink
*appsink
, struct cbox_midi_buffer
*buffer
)
155 struct cbox_midi_buffer
*sinkbuf
= &appsink
->midibufs
[appsink
->current_buffer
];
156 for (int i
= 0; i
< buffer
->count
; i
++)
158 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(buffer
, i
);
161 if (!cbox_midi_buffer_can_store_msg(sinkbuf
, event
->size
))
163 cbox_midi_buffer_copy_event(sinkbuf
, event
, 0);
168 #define cbox_midi_appsink_get_input_midi_data__args(ARG)
170 DEFINE_RT_FUNC(const struct cbox_midi_buffer
*, cbox_midi_appsink
, appsink
, cbox_midi_appsink_get_input_midi_data_
)
172 const struct cbox_midi_buffer
*ret
= NULL
;
173 if (appsink
->midibufs
[appsink
->current_buffer
].count
)
175 // return the current buffer, switch to the new, empty one
176 ret
= &appsink
->midibufs
[appsink
->current_buffer
];
177 appsink
->current_buffer
= 1 - appsink
->current_buffer
;
178 cbox_midi_buffer_clear(&appsink
->midibufs
[appsink
->current_buffer
]);
184 const struct cbox_midi_buffer
*cbox_midi_appsink_get_input_midi_data(struct cbox_midi_appsink
*appsink
)
186 // This checks the counter from the 'wrong' thread, but that's OK, it's
187 // just to avoid doing any RT work when input buffer is completely empty.
188 // Any further access/manipulation is done via RT cmd.
189 if (!appsink
->midibufs
[appsink
->current_buffer
].count
)
191 return cbox_midi_appsink_get_input_midi_data_(appsink
);
194 gboolean
cbox_midi_appsink_send_to(struct cbox_midi_appsink
*appsink
, struct cbox_command_target
*fb
, GError
**error
)
196 const struct cbox_midi_buffer
*midi_in
= cbox_midi_appsink_get_input_midi_data(appsink
);
197 // If no feedback, the input events are lost - probably better than if
198 // they filled up the input buffer needlessly.
201 for (int i
= 0; i
< midi_in
->count
; i
++)
203 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(midi_in
, i
);
204 const uint8_t *data
= cbox_midi_event_get_data(event
);
205 // XXXKF doesn't handle SysEx properly yet, only 3-byte values
206 if (event
->size
<= 3)
208 if (!cbox_execute_on(fb
, NULL
, "/io/midi/simple_event", "iii" + (3 - event
->size
), error
, data
[0], data
[1], data
[2]))
213 struct cbox_blob blob
;
214 blob
.data
= (uint8_t *)data
;
215 blob
.size
= event
->size
;
216 if (!cbox_execute_on(fb
, NULL
, "/io/midi/long_event", "b", error
, &blob
))