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 Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 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  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser 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 #include "fluid_chan.h"
22 #include "fluid_mod.h"
23 #include "fluid_synth.h"
24 #include "fluid_sfont.h"
25 
26 /* Field shift amounts for sfont_bank_prog bit field integer */
27 #define PROG_SHIFTVAL   0
28 #define BANK_SHIFTVAL   8
29 #define SFONT_SHIFTVAL  22
30 
31 /* Field mask values for sfont_bank_prog bit field integer */
32 #define PROG_MASKVAL    0x000000FF      /* Bit 7 is used to indicate unset state */
33 #define BANK_MASKVAL    0x003FFF00
34 #define BANKLSB_MASKVAL 0x00007F00
35 #define BANKMSB_MASKVAL 0x003F8000
36 #define SFONT_MASKVAL   0xFFC00000
37 
38 
39 static void fluid_channel_init(fluid_channel_t *chan);
40 
41 
42 fluid_channel_t *
new_fluid_channel(fluid_synth_t * synth,int num)43 new_fluid_channel(fluid_synth_t *synth, int num)
44 {
45     fluid_channel_t *chan;
46 
47     chan = FLUID_NEW(fluid_channel_t);
48 
49     if(chan == NULL)
50     {
51         FLUID_LOG(FLUID_ERR, "Out of memory");
52         return NULL;
53     }
54 
55     chan->synth = synth;
56     chan->channum = num;
57     chan->preset = NULL;
58     chan->tuning = NULL;
59 
60     fluid_channel_init(chan);
61     fluid_channel_init_ctrl(chan, 0);
62 
63     return chan;
64 }
65 
66 static void
fluid_channel_init(fluid_channel_t * chan)67 fluid_channel_init(fluid_channel_t *chan)
68 {
69     fluid_preset_t *newpreset;
70     int i, prognum, banknum;
71 
72     chan->sostenuto_orderid = 0;
73     /*--- Init poly/mono modes variables --------------------------------------*/
74     chan->mode = 0;
75     chan->mode_val = 0;
76 
77     /* monophonic list initialization */
78     for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++)
79     {
80         chan->monolist[i].next = i + 1;
81     }
82 
83     chan->monolist[FLUID_CHANNEL_SIZE_MONOLIST - 1].next = 0; /* ending element chained to the 1st */
84     chan->i_last = chan->n_notes = 0; /* clears the list */
85     chan->i_first = chan->monolist[chan->i_last].next; /* first note index in the list */
86     fluid_channel_clear_prev_note(chan); /* Mark previous note invalid */
87     /*---*/
88     chan->key_mono_sustained = INVALID_NOTE; /* No previous mono note sustained */
89     chan->legatomode = FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER;		/* Default mode */
90     chan->portamentomode = FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY;	/* Default mode */
91     /*--- End of poly/mono initialization --------------------------------------*/
92 
93     chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
94     prognum = 0;
95     banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
96 
97     chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
98                             | prognum << PROG_SHIFTVAL;
99 
100     newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
101     fluid_channel_set_preset(chan, newpreset);
102 
103     chan->interp_method = FLUID_INTERP_DEFAULT;
104     chan->tuning_bank = 0;
105     chan->tuning_prog = 0;
106     chan->nrpn_select = 0;
107     chan->nrpn_active = 0;
108 
109     if(chan->tuning)
110     {
111         fluid_tuning_unref(chan->tuning, 1);
112         chan->tuning = NULL;
113     }
114 }
115 
116 /*
117   @param is_all_ctrl_off if nonzero, only resets some controllers, according to
118   https://www.midi.org/techspecs/rp15.php
119 */
120 void
fluid_channel_init_ctrl(fluid_channel_t * chan,int is_all_ctrl_off)121 fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
122 {
123     int i;
124 
125     chan->channel_pressure = 0;
126     chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
127 
128     for(i = 0; i < GEN_LAST; i++)
129     {
130         chan->gen[i] = 0.0f;
131     }
132 
133     if(is_all_ctrl_off)
134     {
135         for(i = 0; i < ALL_SOUND_OFF; i++)
136         {
137             if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5)
138             {
139                 continue;
140             }
141 
142             if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10)
143             {
144                 continue;
145             }
146 
147             if(i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
148                     i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB ||
149                     i == BALANCE_MSB || i == BALANCE_LSB
150               )
151             {
152                 continue;
153             }
154 
155             fluid_channel_set_cc(chan, i, 0);
156         }
157     }
158     else
159     {
160         for(i = 0; i < 128; i++)
161         {
162             fluid_channel_set_cc(chan, i, 0);
163         }
164 
165         fluid_channel_clear_portamento(chan); /* Clear PTC receive */
166         chan->previous_cc_breath = 0;/* Reset previous breath */
167     }
168 
169     /* Reset polyphonic key pressure on all voices */
170     for(i = 0; i < 128; i++)
171     {
172         fluid_channel_set_key_pressure(chan, i, 0);
173     }
174 
175     /* Set RPN controllers to NULL state */
176     fluid_channel_set_cc(chan, RPN_LSB, 127);
177     fluid_channel_set_cc(chan, RPN_MSB, 127);
178 
179     /* Set NRPN controllers to NULL state */
180     fluid_channel_set_cc(chan, NRPN_LSB, 127);
181     fluid_channel_set_cc(chan, NRPN_MSB, 127);
182 
183     /* Expression (MSB & LSB) */
184     fluid_channel_set_cc(chan, EXPRESSION_MSB, 127);
185     fluid_channel_set_cc(chan, EXPRESSION_LSB, 127);
186 
187     if(!is_all_ctrl_off)
188     {
189 
190         chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
191 
192         /* Just like panning, a value of 64 indicates no change for sound ctrls */
193         for(i = SOUND_CTRL1; i <= SOUND_CTRL10; i++)
194         {
195             fluid_channel_set_cc(chan, i, 64);
196         }
197 
198         /* Volume / initial attenuation (MSB & LSB) */
199         fluid_channel_set_cc(chan, VOLUME_MSB, 100);
200         fluid_channel_set_cc(chan, VOLUME_LSB, 0);
201 
202         /* Pan (MSB & LSB) */
203         fluid_channel_set_cc(chan, PAN_MSB, 64);
204         fluid_channel_set_cc(chan, PAN_LSB, 0);
205 
206         /* Balance (MSB & LSB) */
207         fluid_channel_set_cc(chan, BALANCE_MSB, 64);
208         fluid_channel_set_cc(chan, BALANCE_LSB, 0);
209 
210         /* Reverb */
211         /* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
212         /* Note: although XG standard specifies the default amount of reverb to
213            be 40, most people preferred having it at zero.
214            See https://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
215     }
216 }
217 
218 /* Only called by delete_fluid_synth(), so no need to queue a preset free event */
219 void
delete_fluid_channel(fluid_channel_t * chan)220 delete_fluid_channel(fluid_channel_t *chan)
221 {
222     fluid_return_if_fail(chan != NULL);
223 
224     FLUID_FREE(chan);
225 }
226 
227 void
fluid_channel_reset(fluid_channel_t * chan)228 fluid_channel_reset(fluid_channel_t *chan)
229 {
230     fluid_channel_init(chan);
231     fluid_channel_init_ctrl(chan, 0);
232 }
233 
234 /* Should only be called from synthesis context */
235 int
fluid_channel_set_preset(fluid_channel_t * chan,fluid_preset_t * preset)236 fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset)
237 {
238     fluid_sfont_t *sfont;
239 
240     if(chan->preset == preset)
241     {
242         return FLUID_OK;
243     }
244 
245     if(chan->preset)
246     {
247         sfont = chan->preset->sfont;
248         sfont->refcount--;
249     }
250 
251     fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
252 
253     chan->preset = preset;
254 
255     if(preset)
256     {
257         sfont = preset->sfont;
258         sfont->refcount++;
259     }
260 
261     fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
262 
263     return FLUID_OK;
264 }
265 
266 /* Set SoundFont ID, MIDI bank and/or program.  Use -1 to use current value. */
267 void
fluid_channel_set_sfont_bank_prog(fluid_channel_t * chan,int sfontnum,int banknum,int prognum)268 fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfontnum,
269                                   int banknum, int prognum)
270 {
271     int oldval, newval, oldmask;
272 
273     newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
274              | ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
275              | ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
276 
277     oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
278               | ((banknum != -1) ? 0 : BANK_MASKVAL)
279               | ((prognum != -1) ? 0 : PROG_MASKVAL);
280 
281     oldval = chan->sfont_bank_prog;
282     newval = (newval & ~oldmask) | (oldval & oldmask);
283     chan->sfont_bank_prog = newval;
284 }
285 
286 /* Set bank LSB 7 bits */
287 void
fluid_channel_set_bank_lsb(fluid_channel_t * chan,int banklsb)288 fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb)
289 {
290     int oldval, newval, style;
291 
292     style = chan->synth->bank_select;
293 
294     if(style == FLUID_BANK_STYLE_GM ||
295             style == FLUID_BANK_STYLE_GS)
296     {
297         return;    /* ignored */
298     }
299 
300     oldval = chan->sfont_bank_prog;
301 
302     if(style == FLUID_BANK_STYLE_XG)
303     {
304         newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
305     }
306     else /* style == FLUID_BANK_STYLE_MMA */
307     {
308         newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
309     }
310 
311     chan->sfont_bank_prog = newval;
312 }
313 
314 /* Set bank MSB 7 bits */
315 void
fluid_channel_set_bank_msb(fluid_channel_t * chan,int bankmsb)316 fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb)
317 {
318     int oldval, newval, style;
319 
320     style = chan->synth->bank_select;
321 
322     if(style == FLUID_BANK_STYLE_XG)
323     {
324         /* XG bank, do drum-channel auto-switch */
325         /* The number "120" was based on several keyboards having drums at 120 - 127,
326            reference: https://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
327         chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
328         return;
329     }
330 
331     if(style == FLUID_BANK_STYLE_GM ||
332             chan->channel_type == CHANNEL_TYPE_DRUM)
333     {
334         return;    /* ignored */
335     }
336 
337     oldval = chan->sfont_bank_prog;
338 
339     if(style == FLUID_BANK_STYLE_GS)
340     {
341         newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
342     }
343     else /* style == FLUID_BANK_STYLE_MMA */
344     {
345         newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
346     }
347 
348     chan->sfont_bank_prog = newval;
349 
350 }
351 
352 /* Get SoundFont ID, MIDI bank and/or program.  Use NULL to ignore a value. */
353 void
fluid_channel_get_sfont_bank_prog(fluid_channel_t * chan,int * sfont,int * bank,int * prog)354 fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
355                                   int *bank, int *prog)
356 {
357     int sfont_bank_prog;
358 
359     sfont_bank_prog = chan->sfont_bank_prog;
360 
361     if(sfont)
362     {
363         *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
364     }
365 
366     if(bank)
367     {
368         *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
369     }
370 
371     if(prog)
372     {
373         *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
374     }
375 }
376 
377 /**
378  * Updates legato/ staccato playing state
379  * The function is called:
380  * - on noteon before adding a note into the monolist.
381  * - on noteoff after removing a note out of the monolist.
382  * @param chan  fluid_channel_t.
383 */
384 static void
fluid_channel_update_legato_staccato_state(fluid_channel_t * chan)385 fluid_channel_update_legato_staccato_state(fluid_channel_t *chan)
386 {
387     /* Updates legato/ staccato playing state */
388     if(chan->n_notes)
389     {
390         chan->mode |= FLUID_CHANNEL_LEGATO_PLAYING; /* Legato state */
391     }
392     else
393     {
394         chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
395     }
396 }
397 
398 /**
399  * Adds a note into the monophonic list. The function is part of the legato
400  * detector. fluid_channel_add_monolist() is intended to be called by
401  * fluid_synth_noteon_mono_LOCAL().
402  *
403  * When a note is added at noteOn each element is use in the forward direction
404  * and indexed by i_last variable.
405  *
406  * @param chan  fluid_channel_t.
407  * @param key MIDI note number (0-127).
408  * @param vel MIDI velocity (0-127, 0=noteoff).
409  * @param onenote. When 1 the function adds the note but the monophonic list
410  *                 keeps only one note (used on noteOn poly).
411  * Note: i_last index keeps a trace of the most recent note added.
412  *       prev_note keeps a trace of the note prior i_last note.
413  *       FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state.
414  *
415  * More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
416 */
417 void
fluid_channel_add_monolist(fluid_channel_t * chan,unsigned char key,unsigned char vel,unsigned char onenote)418 fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key,
419                            unsigned char vel, unsigned char onenote)
420 {
421     unsigned char i_last = chan->i_last;
422     /* Updates legato/ staccato playing state */
423     fluid_channel_update_legato_staccato_state(chan);
424 
425     if(chan->n_notes)
426     {
427         /* keeps trace of the note prior last note */
428         chan->prev_note = chan->monolist[i_last].note;
429     }
430 
431     /* moves i_last forward before writing new note */
432     i_last = chan->monolist[i_last].next;
433     chan->i_last = i_last; 			/* now ilast indexes the last note */
434     chan->monolist[i_last].note = key; /* we save note and velocity */
435     chan->monolist[i_last].vel = vel;
436 
437     if(onenote)
438     {
439         /* clears monolist before one note addition */
440         chan->i_first = i_last;
441         chan->n_notes = 0;
442     }
443 
444     if(chan->n_notes < FLUID_CHANNEL_SIZE_MONOLIST)
445     {
446         chan->n_notes++; /* updates n_notes */
447     }
448     else
449     {
450         /* The end of buffer is reach. So circular motion for i_first */
451         /* i_first index is moved forward */
452         chan->i_first = chan->monolist[i_last].next;
453     }
454 }
455 
456 /**
457  * Searching a note in the monophonic list. The function is part of the legato
458  * detector. fluid_channel_search_monolist() is intended to be called by
459  * fluid_synth_noteoff_mono_LOCAL().
460  *
461  * The search starts from the first note in the list indexed by i_first
462 
463  * @param chan  fluid_channel_t.
464  * @param key MIDI note number (0-127) to search.
465  * @param i_prev pointer on returned index of the note prior the note to search.
466  * @return index of the note if find, FLUID_FAILED otherwise.
467  *
468  */
469 int
fluid_channel_search_monolist(fluid_channel_t * chan,unsigned char key,int * i_prev)470 fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev)
471 {
472     short n = chan->n_notes; /* number of notes in monophonic list */
473     short j, i = chan->i_first; /* searching starts from i_first included */
474 
475     for(j = 0 ; j < n ; j++)
476     {
477         if(chan->monolist[i].note == key)
478         {
479             if(i == chan->i_first)
480             {
481                 /* tracking index of the previous note (i_prev) */
482                 for(j = chan->i_last ; n < FLUID_CHANNEL_SIZE_MONOLIST; n++)
483                 {
484                     j = chan->monolist[j].next;
485                 }
486 
487                 * i_prev = j; /* returns index of the previous note */
488             }
489 
490             return i; /* returns index of the note to search */
491         }
492 
493         * i_prev = i; /* tracking index of the previous note (i_prev) */
494         i = chan->monolist[i].next; /* next element */
495     }
496 
497     return FLUID_FAILED; /* not found */
498 }
499 
500 /**
501  * removes a note from the monophonic list. The function is part of
502  * the legato detector.
503  * fluid_channel_remove_monolist() is intended to be called by
504  * fluid_synth_noteoff_mono_LOCAL().
505  *
506  * When a note is removed at noteOff the element concerned is fast unlinked
507  * and relinked after the i_last element.
508  *
509  * @param chan  fluid_channel_t.
510  * @param
511  *   i, index of the note to remove. If i is invalid or the list is
512  *      empty, the function do nothing and returns FLUID_FAILED.
513  * @param
514  *   On input, i_prev is a pointer on index of the note previous i.
515  *   On output i_prev is a pointer on index of the note previous i if i is the last note
516  *   in the list,FLUID_FAILED otherwise. When the returned index is valid it means
517  *   a legato detection on noteoff.
518  *
519  * Note: the following variables in Channel keeps trace of the situation.
520  *       - i_last index keeps a trace of the most recent note played even if
521  *       the list is empty.
522  *       - prev_note keeps a trace of the note removed if it is i_last.
523  *       - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state.
524  *
525  * More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
526  */
527 void
fluid_channel_remove_monolist(fluid_channel_t * chan,int i,int * i_prev)528 fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev)
529 {
530     unsigned char i_last = chan->i_last;
531 
532     /* checks if index is valid */
533     if(i < 0 || i >= FLUID_CHANNEL_SIZE_MONOLIST || !chan->n_notes)
534     {
535         * i_prev =  FLUID_FAILED;
536     }
537 
538     /* The element is about to be removed and inserted between i_last and next */
539     /* Note: when i is egal to i_last or egal to i_first, removing/inserting
540        isn't necessary */
541     if(i == i_last)
542     {
543         /* Removing/Inserting isn't necessary */
544         /* keeps trace of the note prior last note */
545         chan->prev_note = chan->monolist[i_last].note;
546         /* moves i_last backward to the previous  */
547         chan->i_last = *i_prev; /* i_last index is moved backward */
548     }
549     else
550     {
551         /* i is before i_last */
552         if(i == chan->i_first)
553         {
554             /* Removing/inserting isn't necessary */
555             /* i_first index is moved forward to the next element*/
556             chan->i_first = chan->monolist[i].next;
557         }
558         else
559         {
560             /* i is between i_first and i_last */
561             /* Unlinks element i and inserts after i_last */
562             chan->monolist[* i_prev].next = chan->monolist[i].next; /* unlinks i */
563             /*inserts i after i_last */
564             chan->monolist[i].next = chan->monolist[i_last].next;
565             chan->monolist[i_last].next = i;
566         }
567 
568         * i_prev =  FLUID_FAILED;
569     }
570 
571     chan->n_notes--; /* updates the number of note in the list */
572     /* Updates legato/ staccato playing state */
573     fluid_channel_update_legato_staccato_state(chan);
574 }
575 
576 /**
577  * On noteOff on a polyphonic channel,the monophonic list is fully flushed.
578  *
579  * @param chan  fluid_channel_t.
580  * Note: i_last index keeps a trace of the most recent note played even if
581  *       the list is empty.
582  *       prev_note keeps a trace of the note i_last .
583  *       FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing.
584  */
fluid_channel_clear_monolist(fluid_channel_t * chan)585 void fluid_channel_clear_monolist(fluid_channel_t *chan)
586 {
587     /* keeps trace off the most recent note played */
588     chan->prev_note = chan->monolist[chan->i_last].note;
589 
590     /* flushes the monolist */
591     chan->i_first = chan->monolist[chan->i_last].next;
592     chan->n_notes = 0;
593     /* Update legato/ sataccato playing state */
594     chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
595 }
596 
597 /**
598  * On noteOn on a polyphonic channel,adds the note into the monophonic list
599  * keeping only this note.
600  * @param
601  *   chan  fluid_channel_t.
602  *   key, vel, note and velocity added in the monolist
603  * Note: i_last index keeps a trace of the most recent note inserted.
604  *       prev_note keeps a trace of the note prior i_last note.
605  *       FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
606  */
fluid_channel_set_onenote_monolist(fluid_channel_t * chan,unsigned char key,unsigned char vel)607 void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key,
608                                         unsigned char vel)
609 {
610     fluid_channel_add_monolist(chan, key, vel, 1);
611 }
612 
613 /**
614  * The function changes the state (Valid/Invalid) of the previous note played in
615  * a staccato manner (fluid_channel_prev_note()).
616  * When potamento mode 'each note' or 'staccato only' is selected, on next
617  * noteOn a portamento will be started from the most recent note played
618  * staccato.
619  * It will be possible that it isn't appropriate. To give the musician the
620  * possibility to choose a portamento from this note , prev_note will be forced
621  * to invalid state on noteOff if portamento pedal is Off.
622  *
623  * The function is intended to be called when the following event occurs:
624  * - On noteOff (in poly or mono mode), to mark prev_note invalid.
625  * - On Portamento Off(in poly or mono mode), to mark prev_note invalid.
626  * @param chan  fluid_channel_t.
627  */
fluid_channel_invalid_prev_note_staccato(fluid_channel_t * chan)628 void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan)
629 {
630     /* checks if the playing is staccato */
631     if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
632     {
633 
634         /* checks if portamento pedal is off */
635         if(! fluid_channel_portamento(chan))
636         {
637             /* forces prev_note invalid */
638             fluid_channel_clear_prev_note(chan);
639         }
640     }
641 
642     /* else prev_note still remains valid for next fromkey portamento */
643 }
644 
645 /**
646  * The function handles poly/mono commutation on legato pedal On/Off.
647  * @param chan  fluid_channel_t.
648  * @param value, value of the CC legato.
649  */
fluid_channel_cc_legato(fluid_channel_t * chan,int value)650 void fluid_channel_cc_legato(fluid_channel_t *chan, int value)
651 {
652     /* Special handling of the monophonic list  */
653     if(!(chan->mode & FLUID_CHANNEL_POLY_OFF) && chan->n_notes)  /* The monophonic list have notes */
654     {
655         if(value < 64)   /* legato is released */
656         {
657             /* returns from monophonic to polyphonic with notes in the monophonic list */
658 
659             /* The monophonic list is flushed keeping last note only
660                Note: i_last index keeps a trace of the most recent note played.
661                prev_note keeps a trace of the note i_last.
662                FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
663             */
664             chan->i_first = chan->i_last;
665             chan->n_notes = 1;
666         }
667         else /* legato is depressed */
668         {
669             /* Inters in monophonic from polyphonic with note in monophonic list */
670             /* Stops the running note to remain coherent with Breath Sync mode */
671             if((chan->mode &  FLUID_CHANNEL_BREATH_SYNC) && !fluid_channel_breath_msb(chan))
672             {
673                 fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
674                                              fluid_channel_last_note(chan), 1);
675             }
676         }
677     }
678 }
679 
680 /**
681  * The function handles CC Breath On/Off detection. When a channel is in
682  * Breath Sync mode and in monophonic playing, the breath controller allows
683  * to trigger noteon/noteoff note when the musician starts to breath (noteon) and
684  * stops to breath (noteoff).
685  * @param chan  fluid_channel_t.
686  * @param value, value of the CC Breath..
687  */
fluid_channel_cc_breath_note_on_off(fluid_channel_t * chan,int value)688 void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value)
689 {
690     if((chan->mode &  FLUID_CHANNEL_BREATH_SYNC)  && fluid_channel_is_playing_mono(chan) &&
691             (chan->n_notes))
692     {
693         /* The monophonic list isn't empty */
694         if((value > 0) && (chan->previous_cc_breath == 0))
695         {
696             /* CC Breath On detection */
697             fluid_synth_noteon_mono_staccato(chan->synth, chan->channum,
698                                              fluid_channel_last_note(chan),
699                                              fluid_channel_last_vel(chan));
700         }
701         else if((value == 0) && (chan->previous_cc_breath > 0))
702         {
703             /* CC Breath Off detection */
704             fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
705                                          fluid_channel_last_note(chan), 1);
706         }
707     }
708 
709     chan->previous_cc_breath = value;
710 }
711