1 /* FluidSynth - A Software Synthesizer
2 *
3 * Copyright (C) 2003 Peter Hanappe and others.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License
7 * as published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 */
20
21 /* Original author: Markus Nentwig, nentwig@users.sourceforge.net
22 *
23 * Josh Green made it general purpose with a complete usable public API and
24 * cleaned it up a bit.
25 */
26
27 #include "fluid_midi_router.h"
28 #include "fluid_midi.h"
29 #include "fluid_synth.h"
30
31 /*
32 * fluid_midi_router
33 */
34 struct _fluid_midi_router_t {
35 fluid_synth_t* synth;
36
37 fluid_mutex_t rules_mutex;
38 fluid_midi_router_rule_t *rules[FLUID_MIDI_ROUTER_RULE_COUNT]; /* List of rules for each rule type */
39 fluid_midi_router_rule_t *free_rules; /* List of rules to free (was waiting for final events which were received) */
40
41 handle_midi_event_func_t event_handler; /* Callback function for generated events */
42 void* event_handler_data; /* One arg for the callback */
43
44 int nr_midi_channels; /* For clipping the midi channel */
45
46 /* FIXME - If there are multiple command handlers, they will conflict! */
47 fluid_midi_router_rule_t *cmd_rule; /* Rule currently being processed by shell command handler */
48 int cmd_rule_type; /* Type of the rule (fluid_midi_router_rule_type) */
49 };
50
51 struct _fluid_midi_router_rule_t {
52 int chan_min; /* Channel window, for which this rule is valid */
53 int chan_max;
54 fluid_real_t chan_mul; /* Channel multiplier (usually 0 or 1) */
55 int chan_add; /* Channel offset */
56
57 int par1_min; /* Parameter 1 window, for which this rule is valid */
58 int par1_max;
59 fluid_real_t par1_mul;
60 int par1_add;
61
62 int par2_min; /* Parameter 2 window, for which this rule is valid */
63 int par2_max;
64 fluid_real_t par2_mul;
65 int par2_add;
66
67 int pending_events; /* In case of noteon: How many keys are still down? */
68 char keys_cc[128]; /* Flags, whether a key is down / controller is set (sustain) */
69 fluid_midi_router_rule_t* next; /* next entry */
70 int waiting; /* Set to TRUE when rule has been deactivated but there are still pending_events */
71 };
72
73
74 /**
75 * Create a new midi router. The default rules will pass all events unmodified.
76 * @param settings Settings used to configure MIDI router
77 * @param handler MIDI event callback.
78 * @param event_handler_data Caller defined data pointer which gets passed to 'handler'
79 * @return New MIDI router instance or NULL on error
80 *
81 * The MIDI handler callback should process the possibly filtered/modified MIDI
82 * events from the MIDI router and forward them on to a synthesizer for example.
83 * The function fluid_synth_handle_midi_event() can be used for \a handle and
84 * a #fluid_synth_t passed as the \a event_handler_data parameter for this purpose.
85 */
86 fluid_midi_router_t *
new_fluid_midi_router(fluid_settings_t * settings,handle_midi_event_func_t handler,void * event_handler_data)87 new_fluid_midi_router(fluid_settings_t *settings, handle_midi_event_func_t handler,
88 void *event_handler_data)
89 {
90 fluid_midi_router_t *router = NULL;
91 int i;
92
93 router = FLUID_NEW (fluid_midi_router_t);
94
95 if (router == NULL)
96 {
97 FLUID_LOG(FLUID_ERR, "Out of memory");
98 return NULL;
99 }
100
101 FLUID_MEMSET (router, 0, sizeof (fluid_midi_router_t));
102
103 /* Retrieve the number of MIDI channels for range limiting */
104 fluid_settings_getint(settings, "synth.midi-channels", &router->nr_midi_channels);
105
106 fluid_mutex_init (router->rules_mutex);
107
108 router->synth = (fluid_synth_t *)event_handler_data;
109 router->event_handler = handler;
110 router->event_handler_data = event_handler_data;
111
112 /* Create default routing rules which pass all events unmodified */
113 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
114 {
115 router->rules[i] = new_fluid_midi_router_rule ();
116 if (!router->rules[i]) goto error_recovery;
117 }
118
119 return router;
120
121 error_recovery:
122 delete_fluid_midi_router (router);
123 return NULL;
124 }
125
126 /**
127 * Delete a MIDI router instance.
128 * @param router MIDI router to delete
129 * @return Returns #FLUID_OK on success, #FLUID_FAILED otherwise (only if NULL
130 * \a router passed really)
131 */
132 int
delete_fluid_midi_router(fluid_midi_router_t * router)133 delete_fluid_midi_router (fluid_midi_router_t *router)
134 {
135 fluid_midi_router_rule_t *rule;
136 fluid_midi_router_rule_t *next_rule;
137 int i;
138
139 fluid_return_val_if_fail (router != NULL, FLUID_FAILED);
140
141 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
142 {
143 for (rule = router->rules[i]; rule; rule = next_rule)
144 {
145 next_rule = rule->next;
146 FLUID_FREE (rule);
147 }
148 }
149
150 fluid_mutex_destroy (router->rules_mutex);
151 FLUID_FREE (router);
152
153 return FLUID_OK;
154 }
155
156 /**
157 * Set a MIDI router to use default "unity" rules. Such a router will pass all
158 * events unmodified.
159 * @param router Router to set to default rules.
160 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
161 * @since 1.1.0
162 */
163 int
fluid_midi_router_set_default_rules(fluid_midi_router_t * router)164 fluid_midi_router_set_default_rules (fluid_midi_router_t *router)
165 {
166 fluid_midi_router_rule_t *new_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
167 fluid_midi_router_rule_t *del_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
168 fluid_midi_router_rule_t *rule, *next_rule, *prev_rule;
169 int i, i2;
170
171 fluid_return_val_if_fail (router != NULL, FLUID_FAILED);
172
173 /* Allocate new default rules outside of lock */
174
175 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
176 {
177 new_rules[i] = new_fluid_midi_router_rule ();
178
179 if (!new_rules[i])
180 { /* Free already allocated rules */
181 for (i2 = 0; i2 < i; i2++)
182 delete_fluid_midi_router_rule (new_rules[i]);
183
184 return FLUID_FAILED;
185 }
186 }
187
188
189 fluid_mutex_lock (router->rules_mutex); /* ++ lock */
190
191 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
192 {
193 del_rules[i] = NULL;
194 prev_rule = NULL;
195
196 /* Process existing rules */
197 for (rule = router->rules[i]; rule; rule = next_rule)
198 {
199 next_rule = rule->next;
200
201 if (rule->pending_events == 0) /* Rule has no pending events? */
202 { /* Remove rule from rule list */
203 if (prev_rule) prev_rule->next = next_rule;
204 else if (rule == router->rules[i]) router->rules[i] = next_rule;
205
206 /* Prepend to delete list */
207 rule->next = del_rules[i];
208 del_rules[i] = rule;
209 }
210 else
211 {
212 rule->waiting = TRUE; /* Pending events, mark as waiting */
213 prev_rule = rule;
214 }
215 }
216
217 /* Prepend new default rule */
218 new_rules[i]->next = router->rules[i];
219 router->rules[i] = new_rules[i];
220 }
221
222 fluid_mutex_unlock (router->rules_mutex); /* -- unlock */
223
224
225 /* Free old rules outside of lock */
226
227 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
228 {
229 for (rule = del_rules[i]; rule; rule = next_rule)
230 {
231 next_rule = rule->next;
232 FLUID_FREE (rule);
233 }
234 }
235
236 return FLUID_OK;
237 }
238
239 /**
240 * Clear all rules in a MIDI router. Such a router will drop all events until
241 * rules are added.
242 * @param router Router to clear all rules from
243 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
244 * @since 1.1.0
245 */
246 int
fluid_midi_router_clear_rules(fluid_midi_router_t * router)247 fluid_midi_router_clear_rules (fluid_midi_router_t *router)
248 {
249 fluid_midi_router_rule_t *del_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
250 fluid_midi_router_rule_t *rule, *next_rule, *prev_rule;
251 int i;
252
253 fluid_return_val_if_fail (router != NULL, FLUID_FAILED);
254
255 fluid_mutex_lock (router->rules_mutex); /* ++ lock */
256
257 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
258 {
259 del_rules[i] = NULL;
260 prev_rule = NULL;
261
262 /* Process existing rules */
263 for (rule = router->rules[i]; rule; rule = next_rule)
264 {
265 next_rule = rule->next;
266
267 if (rule->pending_events == 0) /* Rule has no pending events? */
268 { /* Remove rule from rule list */
269 if (prev_rule) prev_rule->next = next_rule;
270 else if (rule == router->rules[i]) router->rules[i] = next_rule;
271
272 /* Prepend to delete list */
273 rule->next = del_rules[i];
274 del_rules[i] = rule;
275 }
276 else
277 {
278 rule->waiting = TRUE; /* Pending events, mark as waiting */
279 prev_rule = rule;
280 }
281 }
282 }
283
284 fluid_mutex_unlock (router->rules_mutex); /* -- unlock */
285
286
287 /* Free old rules outside of lock */
288
289 for (i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
290 {
291 for (rule = del_rules[i]; rule; rule = next_rule)
292 {
293 next_rule = rule->next;
294 FLUID_FREE (rule);
295 }
296 }
297
298 return FLUID_OK;
299 }
300
301 /**
302 * Add a rule to a MIDI router.
303 * @param router MIDI router
304 * @param rule Rule to add (used directly and should not be accessed again following a
305 * successful call to this function).
306 * @param type The type of rule to add (#fluid_midi_router_rule_type)
307 * @return #FLUID_OK on success, #FLUID_FAILED otherwise (invalid rule for example)
308 * @since 1.1.0
309 */
310 int
fluid_midi_router_add_rule(fluid_midi_router_t * router,fluid_midi_router_rule_t * rule,int type)311 fluid_midi_router_add_rule (fluid_midi_router_t *router, fluid_midi_router_rule_t *rule,
312 int type)
313 {
314 fluid_midi_router_rule_t *free_rules, *next_rule;
315
316 fluid_return_val_if_fail (router != NULL, FLUID_FAILED);
317 fluid_return_val_if_fail (rule != NULL, FLUID_FAILED);
318 fluid_return_val_if_fail (type >= 0 && type <= FLUID_MIDI_ROUTER_RULE_COUNT, FLUID_FAILED);
319
320
321 fluid_mutex_lock (router->rules_mutex); /* ++ lock */
322
323 /* Take over free rules list, if any (to free outside of lock) */
324 free_rules = router->free_rules;
325 router->free_rules = NULL;
326
327 rule->next = router->rules[type];
328 router->rules[type] = rule;
329
330 fluid_mutex_unlock (router->rules_mutex); /* -- unlock */
331
332
333 /* Free any deactivated rules which were waiting for events and are now done */
334
335 for (; free_rules; free_rules = next_rule)
336 {
337 next_rule = free_rules->next;
338 FLUID_FREE (free_rules);
339 }
340
341 return FLUID_OK;
342 }
343
344 /**
345 * Create a new MIDI router rule.
346 * @return Newly allocated router rule or NULL if out of memory.
347 * @since 1.1.0
348 *
349 * The new rule is a "unity" rule which will accept any values and wont modify
350 * them.
351 */
352 fluid_midi_router_rule_t *
new_fluid_midi_router_rule(void)353 new_fluid_midi_router_rule (void)
354 {
355 fluid_midi_router_rule_t *rule;
356
357 rule = FLUID_NEW (fluid_midi_router_rule_t);
358
359 if (rule == NULL) {
360 FLUID_LOG(FLUID_ERR, "Out of memory");
361 return NULL;
362 }
363
364 FLUID_MEMSET (rule, 0, sizeof (fluid_midi_router_rule_t));
365
366 rule->chan_min = 0;
367 rule->chan_max = 999999;
368 rule->chan_mul = 1.0;
369 rule->chan_add = 0;
370 rule->par1_min = 0;
371 rule->par1_max = 999999;
372 rule->par1_mul = 1.0;
373 rule->par1_add = 0;
374 rule->par2_min = 0;
375 rule->par2_max = 999999;
376 rule->par2_mul = 1.0;
377 rule->par2_add = 0;
378
379 return rule;
380 };
381
382 /**
383 * Free a MIDI router rule.
384 * @param rule Router rule to free
385 * @since 1.1.0
386 *
387 * Note that rules which have been added to a router are managed by the router,
388 * so this function should seldom be needed.
389 */
390 void
delete_fluid_midi_router_rule(fluid_midi_router_rule_t * rule)391 delete_fluid_midi_router_rule (fluid_midi_router_rule_t *rule)
392 {
393 fluid_return_if_fail (rule != NULL);
394 FLUID_FREE (rule);
395 }
396
397 /**
398 * Set the channel portion of a rule.
399 * @param rule MIDI router rule
400 * @param min Minimum value for rule match
401 * @param max Maximum value for rule match
402 * @param mul Value which is multiplied by matching event's channel value (1.0 to not modify)
403 * @param add Value which is added to matching event's channel value (0 to not modify)
404 * @since 1.1.0
405 *
406 * The \a min and \a max parameters define a channel range window to match
407 * incoming events to. If \a min is less than or equal to \a max then an event
408 * is matched if its channel is within the defined range (including \a min
409 * and \a max). If \a min is greater than \a max then rule is inverted and matches
410 * everything except in *between* the defined range (so \a min and \a max would match).
411 *
412 * The \a mul and \a add values are used to modify event channel values prior to
413 * sending the event, if the rule matches.
414 */
415 void
fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t * rule,int min,int max,float mul,int add)416 fluid_midi_router_rule_set_chan (fluid_midi_router_rule_t *rule, int min, int max,
417 float mul, int add)
418 {
419 fluid_return_if_fail (rule != NULL);
420 rule->chan_min = min;
421 rule->chan_max = max;
422 rule->chan_mul = mul;
423 rule->chan_add = add;
424 }
425
426 /**
427 * Set the first parameter portion of a rule.
428 * @param rule MIDI router rule
429 * @param min Minimum value for rule match
430 * @param max Maximum value for rule match
431 * @param mul Value which is multiplied by matching event's 1st parameter value (1.0 to not modify)
432 * @param add Value which is added to matching event's 1st parameter value (0 to not modify)
433 * @since 1.1.0
434 *
435 * The 1st parameter of an event depends on the type of event. For note events
436 * its the MIDI note #, for CC events its the MIDI control number, for program
437 * change events its the MIDI program #, for pitch bend events its the bend value,
438 * for channel pressure its the channel pressure value and for key pressure
439 * its the MIDI note number.
440 *
441 * Pitch bend values have a maximum value of 16383 (8192 is pitch bend center) and all
442 * other events have a max of 127. All events have a minimum value of 0.
443 *
444 * The \a min and \a max parameters define a parameter range window to match
445 * incoming events to. If \a min is less than or equal to \a max then an event
446 * is matched if its 1st parameter is within the defined range (including \a min
447 * and \a max). If \a min is greater than \a max then rule is inverted and matches
448 * everything except in *between* the defined range (so \a min and \a max would match).
449 *
450 * The \a mul and \a add values are used to modify event 1st parameter values prior to
451 * sending the event, if the rule matches.
452 */
453 void
fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t * rule,int min,int max,float mul,int add)454 fluid_midi_router_rule_set_param1 (fluid_midi_router_rule_t *rule, int min, int max,
455 float mul, int add)
456 {
457 fluid_return_if_fail (rule != NULL);
458 rule->par1_min = min;
459 rule->par1_max = max;
460 rule->par1_mul = mul;
461 rule->par1_add = add;
462 }
463
464 /**
465 * Set the second parameter portion of a rule.
466 * @param rule MIDI router rule
467 * @param min Minimum value for rule match
468 * @param max Maximum value for rule match
469 * @param mul Value which is multiplied by matching event's 2nd parameter value (1.0 to not modify)
470 * @param add Value which is added to matching event's 2nd parameter value (0 to not modify)
471 * @since 1.1.0
472 *
473 * The 2nd parameter of an event depends on the type of event. For note events
474 * its the MIDI velocity, for CC events its the control value and for key pressure
475 * events its the key pressure value. All other types lack a 2nd parameter.
476 *
477 * All applicable 2nd parameters have the range 0-127.
478 *
479 * The \a min and \a max parameters define a parameter range window to match
480 * incoming events to. If \a min is less than or equal to \a max then an event
481 * is matched if its 2nd parameter is within the defined range (including \a min
482 * and \a max). If \a min is greater than \a max then rule is inverted and matches
483 * everything except in *between* the defined range (so \a min and \a max would match).
484 *
485 * The \a mul and \a add values are used to modify event 2nd parameter values prior to
486 * sending the event, if the rule matches.
487 */
488 void
fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t * rule,int min,int max,float mul,int add)489 fluid_midi_router_rule_set_param2 (fluid_midi_router_rule_t *rule, int min, int max,
490 float mul, int add)
491 {
492 fluid_return_if_fail (rule != NULL);
493 rule->par2_min = min;
494 rule->par2_max = max;
495 rule->par2_mul = mul;
496 rule->par2_add = add;
497 }
498
499 /**
500 * Handle a MIDI event through a MIDI router instance.
501 * @param data MIDI router instance #fluid_midi_router_t, its a void * so that
502 * this function can be used as a callback for other subsystems
503 * (new_fluid_midi_driver() for example).
504 * @param event MIDI event to handle
505 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
506 *
507 * Purpose: The midi router is called for each event, that is received
508 * via the 'physical' midi input. Each event can trigger an arbitrary number
509 * of generated events (one for each rule that matches).
510 *
511 * In default mode, a noteon event is just forwarded to the synth's 'noteon' function,
512 * a 'CC' event to the synth's 'CC' function and so on.
513 *
514 * The router can be used to:
515 * - filter messages (for example: Pass sustain pedal CCs only to selected channels)
516 * - split the keyboard (noteon with notenr < x: to ch 1, >x to ch 2)
517 * - layer sounds (for each noteon received on ch 1, create a noteon on ch1, ch2, ch3,...)
518 * - velocity scaling (for each noteon event, scale the velocity by 1.27 to give DX7 users
519 * a chance)
520 * - velocity switching ("v <=100: Angel Choir; V > 100: Hell's Bells")
521 * - get rid of aftertouch
522 * - ...
523 */
524 int
fluid_midi_router_handle_midi_event(void * data,fluid_midi_event_t * event)525 fluid_midi_router_handle_midi_event (void* data, fluid_midi_event_t* event)
526 {
527 fluid_midi_router_t* router = (fluid_midi_router_t *)data;
528 fluid_midi_router_rule_t **rulep, *rule, *next_rule, *prev_rule = NULL;
529 int event_has_par2 = 0; /* Flag, indicates that current event needs two parameters */
530 int par1_max = 127; /* Range limit for par1 */
531 int par2_max = 127; /* Range limit for par2 */
532 int ret_val = FLUID_OK;
533
534 int chan; /* Channel of the generated event */
535 int par1; /* par1 of the generated event */
536 int par2;
537 int event_par1;
538 int event_par2;
539 fluid_midi_event_t new_event;
540
541 /* Some keyboards report noteoff through a noteon event with vel=0.
542 * Convert those to noteoff to ease processing. */
543 if (event->type == NOTE_ON && event->param2 == 0)
544 {
545 event->type = NOTE_OFF;
546 event->param2 = 127; /* Release velocity */
547 }
548
549 fluid_mutex_lock (router->rules_mutex); /* ++ lock rules */
550
551 /* Depending on the event type, choose the correct list of rules. */
552 switch (event->type)
553 {
554 case NOTE_ON:
555 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
556 event_has_par2 = 1;
557 break;
558 case NOTE_OFF:
559 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
560 event_has_par2 = 1;
561 break;
562 case CONTROL_CHANGE:
563 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CC];
564 event_has_par2 = 1;
565 break;
566 case PROGRAM_CHANGE:
567 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PROG_CHANGE];
568 break;
569 case PITCH_BEND:
570 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PITCH_BEND];
571 par1_max = 16383;
572 break;
573 case CHANNEL_PRESSURE:
574 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE];
575 break;
576 case KEY_PRESSURE:
577 rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE];
578 event_has_par2 = 1;
579 break;
580 case MIDI_SYSTEM_RESET:
581 case MIDI_SYSEX:
582 ret_val = router->event_handler (router->event_handler_data,event);
583 fluid_mutex_unlock (router->rules_mutex); /* -- unlock rules */
584 return ret_val;
585 default:
586 rulep = NULL; /* Event will not be passed on */
587 break;
588 }
589
590 /* Loop over rules in the list, looking for matches for this event. */
591 for (rule = rulep ? *rulep : NULL; rule; prev_rule = rule, rule = next_rule)
592 {
593 event_par1 = (int)event->param1;
594 event_par2 = (int)event->param2;
595 next_rule = rule->next; /* Rule may get removed from list, so get next here */
596
597 /* Channel window */
598 if (rule->chan_min > rule->chan_max)
599 { /* Inverted rule: Exclude everything between max and min (but not min/max) */
600 if (event->channel > rule->chan_max && event->channel < rule->chan_min)
601 continue;
602 }
603 else /* Normal rule: Exclude everything < max or > min (but not min/max) */
604 {
605 if (event->channel > rule->chan_max || event->channel < rule->chan_min)
606 continue;
607 }
608
609 /* Par 1 window */
610 if (rule->par1_min > rule->par1_max)
611 { /* Inverted rule: Exclude everything between max and min (but not min/max) */
612 if (event_par1 > rule->par1_max && event_par1 < rule->par1_min)
613 continue;
614 }
615 else /* Normal rule: Exclude everything < max or > min (but not min/max)*/
616 {
617 if (event_par1 > rule->par1_max || event_par1 < rule->par1_min)
618 continue;
619 }
620
621 /* Par 2 window (only applies to event types, which have 2 pars)
622 * For noteoff events, velocity switching doesn't make any sense.
623 * Velocity scaling might be useful, though.
624 */
625 if (event_has_par2 && event->type != NOTE_OFF)
626 {
627 if (rule->par2_min > rule->par2_max)
628 { /* Inverted rule: Exclude everything between max and min (but not min/max) */
629 if (event_par2 > rule->par2_max && event_par2 < rule->par2_min)
630 continue;
631 }
632 else /* Normal rule: Exclude everything < max or > min (but not min/max)*/
633 {
634 if (event_par2 > rule->par2_max || event_par2 < rule->par2_min)
635 continue;
636 }
637 }
638
639 /* Channel scaling / offset
640 * Note: rule->chan_mul will probably be 0 or 1. If it's 0, input from all
641 * input channels is mapped to the same synth channel.
642 */
643 chan = (int)((fluid_real_t)event->channel * (fluid_real_t)rule->chan_mul
644 + (fluid_real_t)rule->chan_add + 0.5);
645
646 /* Par 1 scaling / offset */
647 par1 = (int)((fluid_real_t)event_par1 * (fluid_real_t)rule->par1_mul
648 + (fluid_real_t)rule->par1_add + 0.5);
649
650 /* Par 2 scaling / offset, if applicable */
651 if (event_has_par2)
652 par2 = (int)((fluid_real_t)event_par2 * (fluid_real_t)rule->par2_mul
653 + (fluid_real_t)rule->par2_add + 0.5);
654 else par2 = 0;
655
656 /* Channel range limiting */
657 if (chan < 0)
658 chan = 0;
659 else if (chan >= router->nr_midi_channels)
660 chan = router->nr_midi_channels - 1;
661
662 /* Par1 range limiting */
663 if (par1 < 0)
664 par1 = 0;
665 else if (par1 > par1_max)
666 par1 = par1_max;
667
668 /* Par2 range limiting */
669 if (event_has_par2)
670 {
671 if (par2 < 0)
672 par2 = 0;
673 else if (par2 > par2_max)
674 par2 = par2_max;
675 }
676
677 /* At this point we have to create an event of event->type on 'chan' with par1 (maybe par2).
678 * We keep track on the state of noteon and sustain pedal events. If the application tries
679 * to delete a rule, it will only be fully removed, if pending noteoff / pedal off events have
680 * arrived. In the meantime while waiting, it will only let through 'negative' events
681 * (noteoff or pedal up).
682 */
683 if (event->type == NOTE_ON || (event->type == CONTROL_CHANGE
684 && par1 == SUSTAIN_SWITCH && par2 >= 64))
685 {
686 /* Noteon or sustain pedal down event generated */
687 if (rule->keys_cc[par1] == 0)
688 {
689 rule->keys_cc[par1] = 1;
690 rule->pending_events++;
691 }
692 }
693 else if (event->type == NOTE_OFF || (event->type == CONTROL_CHANGE
694 && par1 == SUSTAIN_SWITCH && par2 < 64))
695 { /* Noteoff or sustain pedal up event generated */
696 if (rule->keys_cc[par1] > 0)
697 {
698 rule->keys_cc[par1] = 0;
699 rule->pending_events--;
700
701 /* Rule is waiting for negative event to be destroyed? */
702 if (rule->waiting)
703 {
704 if (rule->pending_events == 0)
705 { /* Remove rule from rule list */
706 if (prev_rule) prev_rule->next = next_rule;
707 else *rulep = next_rule;
708
709 /* Add to free list */
710 rule->next = router->free_rules;
711 router->free_rules = rule;
712
713 rule = prev_rule; /* Set rule to previous rule, which gets assigned to the next prev_rule value (in for() statement) */
714 }
715
716 goto send_event; /* Pass the event to complete the cycle */
717 }
718 }
719 }
720
721 /* Rule is still waiting for negative event? (note off or pedal up) */
722 if (rule->waiting)
723 continue; /* Skip (rule is inactive except for matching negative event) */
724
725 send_event:
726
727 /* At this point it is decided, what is sent to the synth.
728 * Create a new event and make the appropriate call */
729
730 fluid_midi_event_set_type (&new_event, event->type);
731 fluid_midi_event_set_channel (&new_event, chan);
732 new_event.param1 = par1;
733 new_event.param2 = par2;
734
735 /* FIXME - What should be done on failure? For now continue to process events, but return failure to caller. */
736 if (router->event_handler (router->event_handler_data, &new_event) != FLUID_OK)
737 ret_val = FLUID_FAILED;
738 }
739
740 fluid_mutex_unlock (router->rules_mutex); /* -- unlock rules */
741
742 return ret_val;
743 }
744
745 #define CHECK_VALID_ROUTER(_router, _out) \
746 if (router == NULL) { \
747 fluid_ostream_printf(out, "cannot execute router command without a midi router.\n"); \
748 return FLUID_FAILED; \
749 }
750
751 /* Command handler for "router_clear" command */
752 int
fluid_midi_router_handle_clear(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)753 fluid_midi_router_handle_clear (fluid_synth_t* synth, int ac, char** av,
754 fluid_ostream_t out)
755 {
756 fluid_midi_router_t *router = synth->midi_router;
757
758 if (ac != 0) {
759 fluid_ostream_printf (out, "router_clear needs no arguments.\n");
760 return FLUID_FAILED;
761 }
762
763 CHECK_VALID_ROUTER (router, out);
764
765 fluid_midi_router_clear_rules (router);
766
767 return FLUID_OK;
768 }
769
770 /* Command handler for "router_default" command */
771 int
fluid_midi_router_handle_default(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)772 fluid_midi_router_handle_default(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
773 {
774 fluid_midi_router_t *router = synth->midi_router;
775
776 if (ac != 0) {
777 fluid_ostream_printf(out, "router_default needs no arguments.\n");
778 return FLUID_FAILED;
779 }
780
781 CHECK_VALID_ROUTER (router, out);
782
783 fluid_midi_router_set_default_rules (router);
784
785 return FLUID_OK;
786 }
787
788 /* Command handler for "router_begin" command */
789 int
fluid_midi_router_handle_begin(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)790 fluid_midi_router_handle_begin (fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
791 {
792 fluid_midi_router_t* router = synth->midi_router;
793
794 if (ac != 1) {
795 fluid_ostream_printf (out, "router_begin requires [note|cc|prog|pbend|cpress|kpress]\n");
796 return FLUID_FAILED;
797 }
798
799 CHECK_VALID_ROUTER (router, out);
800
801 if (FLUID_STRCMP (av[0], "note") == 0)
802 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_NOTE;
803 else if (FLUID_STRCMP (av[0], "cc") == 0)
804 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_CC;
805 else if (FLUID_STRCMP (av[0], "prog") == 0)
806 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_PROG_CHANGE;
807 else if (FLUID_STRCMP (av[0], "pbend") == 0)
808 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_PITCH_BEND;
809 else if (FLUID_STRCMP (av[0], "cpress") == 0)
810 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE;
811 else if (FLUID_STRCMP (av[0], "kpress") == 0)
812 router->cmd_rule_type = FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE;
813 else
814 {
815 fluid_ostream_printf (out, "router_begin requires [note|cc|prog|pbend|cpress|kpress]\n");
816 return FLUID_FAILED;
817 }
818
819 if (router->cmd_rule)
820 delete_fluid_midi_router_rule (router->cmd_rule);
821
822 router->cmd_rule = new_fluid_midi_router_rule ();
823
824 if (!router->cmd_rule)
825 return FLUID_FAILED;
826
827 return FLUID_OK;
828 }
829
830 /* Command handler for "router_end" command */
831 int
fluid_midi_router_handle_end(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)832 fluid_midi_router_handle_end (fluid_synth_t* synth, int ac, char** av,
833 fluid_ostream_t out)
834 {
835 fluid_midi_router_t* router = synth->midi_router;
836
837 if (ac != 0) {
838 fluid_ostream_printf (out, "router_end needs no arguments.\n");
839 return FLUID_FAILED;
840 }
841
842 CHECK_VALID_ROUTER (router, out);
843
844 if (!router->cmd_rule)
845 {
846 fluid_ostream_printf (out, "No active router_begin command.\n");
847 return FLUID_FAILED;
848 }
849
850 /* Add the rule */
851 if (fluid_midi_router_add_rule (router, router->cmd_rule, router->cmd_rule_type) != FLUID_OK)
852 delete_fluid_midi_router_rule (router->cmd_rule); /* Free on failure */
853
854 router->cmd_rule = NULL;
855
856 return FLUID_OK;
857 }
858
859 /* Command handler for "router_chan" command */
860 int
fluid_midi_router_handle_chan(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)861 fluid_midi_router_handle_chan (fluid_synth_t* synth, int ac, char** av,
862 fluid_ostream_t out)
863 {
864 fluid_midi_router_t* router = synth->midi_router;
865
866 if (ac != 4) {
867 fluid_ostream_printf(out, "router_chan needs four args: min, max, mul, add.");
868 return FLUID_FAILED;
869 }
870
871 CHECK_VALID_ROUTER (router, out);
872
873 if (!router->cmd_rule)
874 {
875 fluid_ostream_printf (out, "No active router_begin command.\n");
876 return FLUID_FAILED;
877 }
878
879 fluid_midi_router_rule_set_chan (router->cmd_rule, atoi (av[0]), atoi (av[1]),
880 atof (av[2]), atoi (av[3]));
881 return FLUID_OK;
882 }
883
884 /* Command handler for "router_par1" command */
885 int
fluid_midi_router_handle_par1(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)886 fluid_midi_router_handle_par1 (fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
887 {
888 fluid_midi_router_t* router = synth->midi_router;
889
890 if (ac != 4) {
891 fluid_ostream_printf(out, "router_par1 needs four args: min, max, mul, add.");
892 return FLUID_FAILED;
893 }
894
895 CHECK_VALID_ROUTER (router, out);
896
897 if (!router->cmd_rule)
898 {
899 fluid_ostream_printf (out, "No active router_begin command.\n");
900 return FLUID_FAILED;
901 }
902
903 fluid_midi_router_rule_set_param1 (router->cmd_rule, atoi (av[0]), atoi (av[1]),
904 atof (av[2]), atoi (av[3]));
905 return FLUID_OK;
906 }
907
908 /* Command handler for "router_par2" command */
909 int
fluid_midi_router_handle_par2(fluid_synth_t * synth,int ac,char ** av,fluid_ostream_t out)910 fluid_midi_router_handle_par2 (fluid_synth_t* synth, int ac, char** av,
911 fluid_ostream_t out)
912 {
913 fluid_midi_router_t* router = synth->midi_router;
914
915 if (ac != 4) {
916 fluid_ostream_printf(out, "router_par2 needs four args: min, max, mul, add.");
917 return FLUID_FAILED;
918 }
919
920 CHECK_VALID_ROUTER (router, out);
921
922 if (!router->cmd_rule)
923 {
924 fluid_ostream_printf (out, "No active router_begin command.\n");
925 return FLUID_FAILED;
926 }
927
928 fluid_midi_router_rule_set_param2 (router->cmd_rule, atoi (av[0]), atoi (av[1]),
929 atof (av[2]), atoi (av[3]));
930 return FLUID_OK;
931 }
932
933 /**
934 * MIDI event callback function to display event information to stdout
935 * @param data MIDI router instance
936 * @param event MIDI event data
937 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
938 *
939 * An implementation of the #handle_midi_event_func_t function type, used for
940 * displaying MIDI event information between the MIDI driver and router to
941 * stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
942 */
fluid_midi_dump_prerouter(void * data,fluid_midi_event_t * event)943 int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
944 {
945 switch (event->type) {
946 case NOTE_ON:
947 fprintf(stdout, "event_pre_noteon %i %i %i\n",
948 event->channel, event->param1, event->param2);
949 break;
950 case NOTE_OFF:
951 fprintf(stdout, "event_pre_noteoff %i %i %i\n",
952 event->channel, event->param1, event->param2);
953 break;
954 case CONTROL_CHANGE:
955 fprintf(stdout, "event_pre_cc %i %i %i\n",
956 event->channel, event->param1, event->param2);
957 break;
958 case PROGRAM_CHANGE:
959 fprintf(stdout, "event_pre_prog %i %i\n", event->channel, event->param1);
960 break;
961 case PITCH_BEND:
962 fprintf(stdout, "event_pre_pitch %i %i\n", event->channel, event->param1);
963 break;
964 case CHANNEL_PRESSURE:
965 fprintf(stdout, "event_pre_cpress %i %i\n", event->channel, event->param1);
966 break;
967 case KEY_PRESSURE:
968 fprintf(stdout, "event_pre_kpress %i %i %i\n",
969 event->channel, event->param1, event->param2);
970 break;
971 default:
972 break;
973 }
974 return fluid_midi_router_handle_midi_event((fluid_midi_router_t*) data, event);
975 }
976
977 /**
978 * MIDI event callback function to display event information to stdout
979 * @param data MIDI router instance
980 * @param event MIDI event data
981 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
982 *
983 * An implementation of the #handle_midi_event_func_t function type, used for
984 * displaying MIDI event information between the MIDI driver and router to
985 * stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
986 */
fluid_midi_dump_postrouter(void * data,fluid_midi_event_t * event)987 int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event)
988 {
989 switch (event->type) {
990 case NOTE_ON:
991 fprintf(stdout, "event_post_noteon %i %i %i\n",
992 event->channel, event->param1, event->param2);
993 break;
994 case NOTE_OFF:
995 fprintf(stdout, "event_post_noteoff %i %i %i\n",
996 event->channel, event->param1, event->param2);
997 break;
998 case CONTROL_CHANGE:
999 fprintf(stdout, "event_post_cc %i %i %i\n",
1000 event->channel, event->param1, event->param2);
1001 break;
1002 case PROGRAM_CHANGE:
1003 fprintf(stdout, "event_post_prog %i %i\n", event->channel, event->param1);
1004 break;
1005 case PITCH_BEND:
1006 fprintf(stdout, "event_post_pitch %i %i\n", event->channel, event->param1);
1007 break;
1008 case CHANNEL_PRESSURE:
1009 fprintf(stdout, "event_post_cpress %i %i\n", event->channel, event->param1);
1010 break;
1011 case KEY_PRESSURE:
1012 fprintf(stdout, "event_post_kpress %i %i %i\n",
1013 event->channel, event->param1, event->param2);
1014 break;
1015 default:
1016 break;
1017 }
1018 return fluid_synth_handle_midi_event((fluid_synth_t*) data, event);
1019 }
1020