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
->input_count
= 0;
28 dest
->output
= output
;
30 cbox_midi_buffer_clear(dest
->output
);
33 // void cbox_midi_buffer_merge(struct cbox_midi_buffer *output, struct cbox_midi_buffer **inputs, int count, int *positions)
34 void cbox_midi_merger_render_to(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*output
)
38 cbox_midi_buffer_clear(output
);
39 for (int i
= 0; i
< dest
->input_count
; i
++)
41 if (dest
->inputs
[i
]->streaming
)
42 dest
->inputs
[i
]->bpos
= 0;
47 struct cbox_midi_source
*earliest_source
= NULL
;
48 uint32_t earliest_time
= (uint32_t)-1;
51 int icount
= dest
->input_count
;
54 for (int i
= spos
; i
< icount
; i
++)
58 struct cbox_midi_source
*src
= dest
->inputs
[i
];
59 struct cbox_midi_buffer
*data
= src
->data
;
60 if (src
->bpos
< data
->count
)
62 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(data
, src
->bpos
);
63 if (event
->time
< earliest_time
)
65 earliest_source
= src
;
66 earliest_time
= event
->time
;
72 // Narrow down the range from top and bottom
81 cbox_midi_buffer_copy_event(output
, cbox_midi_buffer_get_event(earliest_source
->data
, earliest_source
->bpos
), earliest_time
);
82 earliest_source
->bpos
++;
89 int cbox_midi_merger_find_source(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
)
91 for (int i
= 0; i
< dest
->input_count
; i
++)
92 if (dest
->inputs
[i
]->data
== buffer
)
97 void cbox_midi_merger_connect(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
99 if (cbox_midi_merger_find_source(dest
, buffer
) != -1)
102 struct cbox_midi_source
*src
= calloc(1, sizeof(struct cbox_midi_source
));
105 src
->streaming
= TRUE
;
106 cbox_rt_array_insert(rt
, (void ***)&dest
->inputs
, &dest
->input_count
, dest
->input_count
, src
);
109 void cbox_midi_merger_disconnect(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
111 int pos
= cbox_midi_merger_find_source(dest
, buffer
);
115 cbox_rt_array_remove(rt
, (void ***)&dest
->inputs
, &dest
->input_count
, pos
);
118 void cbox_midi_merger_push(struct cbox_midi_merger
*dest
, struct cbox_midi_buffer
*buffer
, struct cbox_rt
*rt
)
122 struct cbox_midi_source src
;
125 src
.streaming
= FALSE
;
126 cbox_rt_array_insert(rt
, (void ***)&dest
->inputs
, &dest
->input_count
, dest
->input_count
, &src
);
127 while(src
.bpos
< buffer
->count
)
128 cbox_rt_handle_cmd_queue(rt
);
129 cbox_rt_array_remove(rt
, (void ***)&dest
->inputs
, &dest
->input_count
, dest
->input_count
- 1);
132 void cbox_midi_merger_close(struct cbox_midi_merger
*dest
)
134 for (int i
= 0; i
< dest
->input_count
; i
++)
135 free(dest
->inputs
[i
]);
139 ////////////////////////////////////////////////////////////////////////////////////////
141 void cbox_midi_appsink_init(struct cbox_midi_appsink
*appsink
, struct cbox_rt
*rt
)
144 cbox_midi_buffer_init(&appsink
->midibufs
[0]);
145 cbox_midi_buffer_init(&appsink
->midibufs
[1]);
146 appsink
->current_buffer
= 0;
149 void cbox_midi_appsink_supply(struct cbox_midi_appsink
*appsink
, struct cbox_midi_buffer
*buffer
)
151 struct cbox_midi_buffer
*sinkbuf
= &appsink
->midibufs
[appsink
->current_buffer
];
152 for (int i
= 0; i
< buffer
->count
; i
++)
154 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(buffer
, i
);
157 if (!cbox_midi_buffer_can_store_msg(sinkbuf
, event
->size
))
159 cbox_midi_buffer_copy_event(sinkbuf
, event
, 0);
164 #define cbox_midi_appsink_get_input_midi_data__args(ARG)
166 DEFINE_RT_FUNC(const struct cbox_midi_buffer
*, cbox_midi_appsink
, appsink
, cbox_midi_appsink_get_input_midi_data_
)
168 const struct cbox_midi_buffer
*ret
= NULL
;
169 if (appsink
->midibufs
[appsink
->current_buffer
].count
)
171 // return the current buffer, switch to the new, empty one
172 ret
= &appsink
->midibufs
[appsink
->current_buffer
];
173 appsink
->current_buffer
= 1 - appsink
->current_buffer
;
174 cbox_midi_buffer_clear(&appsink
->midibufs
[appsink
->current_buffer
]);
180 const struct cbox_midi_buffer
*cbox_midi_appsink_get_input_midi_data(struct cbox_midi_appsink
*appsink
)
182 // This checks the counter from the 'wrong' thread, but that's OK, it's
183 // just to avoid doing any RT work when input buffer is completely empty.
184 // Any further access/manipulation is done via RT cmd.
185 if (!appsink
->midibufs
[appsink
->current_buffer
].count
)
187 return cbox_midi_appsink_get_input_midi_data_(appsink
);
190 gboolean
cbox_midi_appsink_send_to(struct cbox_midi_appsink
*appsink
, struct cbox_command_target
*fb
, GError
**error
)
192 const struct cbox_midi_buffer
*midi_in
= cbox_midi_appsink_get_input_midi_data(appsink
);
193 // If no feedback, the input events are lost - probably better than if
194 // they filled up the input buffer needlessly.
197 for (int i
= 0; i
< midi_in
->count
; i
++)
199 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(midi_in
, i
);
200 const uint8_t *data
= cbox_midi_event_get_data(event
);
201 // XXXKF doesn't handle SysEx properly yet, only 3-byte values
202 if (event
->size
<= 3)
204 if (!cbox_execute_on(fb
, NULL
, "/io/midi/simple_event", "iii" + (3 - event
->size
), error
, data
[0], data
[1], data
[2]))
209 struct cbox_blob blob
;
210 blob
.data
= (uint8_t *)data
;
211 blob
.size
= event
->size
;
212 if (!cbox_execute_on(fb
, NULL
, "/io/midi/long_event", "b", error
, &blob
))