Implement egN_vel2freq and egN_vel2gain. Tighten EQ-change logic.
[calfbox.git] / mididest.c
blob39f8d485b9ec89b06439a6858c6de39092323e18
1 /*
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/>.
19 #include "blob.h"
20 #include "mididest.h"
21 #include "rt.h"
22 #include "stm.h"
24 void cbox_midi_merger_init(struct cbox_midi_merger *dest, struct cbox_midi_buffer *output)
26 dest->inputs = NULL;
27 dest->input_count = 0;
28 dest->output = output;
29 if (dest->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)
36 if (!output)
37 return;
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;
45 while(1)
47 struct cbox_midi_source *earliest_source = NULL;
48 uint32_t earliest_time = (uint32_t)-1;
50 uint32_t mask = 0;
51 int icount = dest->input_count;
52 int spos = 0;
54 for (int i = spos; i < icount; i++)
56 if (mask & (1 << i))
57 continue;
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;
69 else
71 mask |= 1 << i;
72 // Narrow down the range from top and bottom
73 if (i == spos)
74 spos = i + 1;
75 if (i == icount - 1)
76 icount = i;
79 if (earliest_source)
81 cbox_midi_buffer_copy_event(output, cbox_midi_buffer_get_event(earliest_source->data, earliest_source->bpos), earliest_time);
82 earliest_source->bpos++;
84 else
85 break;
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)
93 return i;
94 return -1;
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)
100 return;
102 struct cbox_midi_source *src = calloc(1, sizeof(struct cbox_midi_source));
103 src->data = buffer;
104 src->bpos = 0;
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);
112 if (pos == -1)
113 return;
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)
120 if (!buffer->count)
121 return;
122 struct cbox_midi_source src;
123 src.data = buffer;
124 src.bpos = 0;
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]);
136 free(dest->inputs);
139 ////////////////////////////////////////////////////////////////////////////////////////
141 void cbox_midi_appsink_init(struct cbox_midi_appsink *appsink, struct cbox_rt *rt)
143 appsink->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);
155 if (event)
157 if (!cbox_midi_buffer_can_store_msg(sinkbuf, event->size))
158 break;
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]);
177 return ret;
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)
186 return NULL;
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.
195 if (fb && midi_in)
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]))
205 return FALSE;
207 else
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))
213 return FALSE;
217 return TRUE;