Path: blob/master/libs/fluidsynth/src/synth/fluid_chan.c
4396 views
/* FluidSynth - A Software Synthesizer1*2* Copyright (C) 2003 Peter Hanappe and others.3*4* This library is free software; you can redistribute it and/or5* modify it under the terms of the GNU Lesser General Public License6* as published by the Free Software Foundation; either version 2.1 of7* the License, or (at your option) any later version.8*9* This library is distributed in the hope that it will be useful, but10* WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12* Lesser General Public License for more details.13*14* You should have received a copy of the GNU Lesser General Public15* License along with this library; if not, write to the Free16* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA17* 02110-1301, USA18*/1920#include "fluid_chan.h"21#include "fluid_mod.h"22#include "fluid_synth.h"23#include "fluid_sfont.h"2425/* Field shift amounts for sfont_bank_prog bit field integer */26#define PROG_SHIFTVAL 027#define BANK_SHIFTVAL 828#define SFONT_SHIFTVAL 222930/* Field mask values for sfont_bank_prog bit field integer */31#define PROG_MASKVAL 0x000000FF /* Bit 7 is used to indicate unset state */32#define BANK_MASKVAL 0x003FFF0033#define BANKLSB_MASKVAL 0x00007F0034#define BANKMSB_MASKVAL 0x003F800035#define SFONT_MASKVAL 0xFFC00000363738static void fluid_channel_init(fluid_channel_t *chan);394041fluid_channel_t *42new_fluid_channel(fluid_synth_t *synth, int num)43{44fluid_channel_t *chan;4546chan = FLUID_NEW(fluid_channel_t);4748if(chan == NULL)49{50FLUID_LOG(FLUID_ERR, "Out of memory");51return NULL;52}5354chan->synth = synth;55chan->channum = num;56chan->preset = NULL;57chan->tuning = NULL;5859fluid_channel_init(chan);60fluid_channel_init_ctrl(chan, 0);6162return chan;63}6465static void66fluid_channel_init(fluid_channel_t *chan)67{68fluid_preset_t *newpreset;69int i, prognum, banknum;7071chan->sostenuto_orderid = 0;72/*--- Init poly/mono modes variables --------------------------------------*/73chan->mode = 0;74chan->mode_val = 0;7576/* monophonic list initialization */77for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++)78{79chan->monolist[i].next = i + 1;80}8182chan->monolist[FLUID_CHANNEL_SIZE_MONOLIST - 1].next = 0; /* ending element chained to the 1st */83chan->i_last = chan->n_notes = 0; /* clears the list */84chan->i_first = chan->monolist[chan->i_last].next; /* first note index in the list */85fluid_channel_clear_prev_note(chan); /* Mark previous note invalid */86/*---*/87chan->key_mono_sustained = INVALID_NOTE; /* No previous mono note sustained */88chan->legatomode = FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER; /* Default mode */89chan->portamentomode = FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY; /* Default mode */90/*--- End of poly/mono initialization --------------------------------------*/9192chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;93prognum = 0;94banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;9596chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL97| prognum << PROG_SHIFTVAL;9899newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);100fluid_channel_set_preset(chan, newpreset);101102chan->interp_method = FLUID_INTERP_DEFAULT;103chan->tuning_bank = 0;104chan->tuning_prog = 0;105chan->nrpn_select = 0;106chan->nrpn_active = 0;107108if(chan->tuning)109{110fluid_tuning_unref(chan->tuning, 1);111chan->tuning = NULL;112}113}114115/*116@param is_all_ctrl_off if nonzero, only resets some controllers, according to117https://www.midi.org/techspecs/rp15.php118*/119void120fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)121{122int i;123124chan->channel_pressure = 0;125chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */126127for(i = 0; i < GEN_LAST; i++)128{129chan->gen[i] = 0.0f;130chan->override_gen_default[i].flags = GEN_UNUSED;131chan->override_gen_default[i].val = 0.0f;132}133// Not all MIDIs initialize the IIR filter coefficient, e.g. Uplift.mid.134// A default value is not documented, hence I'm assuming zero here.135chan->awe32_filter_coeff = 0;136137if(is_all_ctrl_off)138{139for(i = 0; i < ALL_SOUND_OFF; i++)140{141if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5)142{143continue;144}145146if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10)147{148continue;149}150151if(i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||152i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB ||153i == BALANCE_MSB || i == BALANCE_LSB154)155{156continue;157}158159fluid_channel_set_cc(chan, i, 0);160}161}162else163{164for(i = 0; i < 128; i++)165{166fluid_channel_set_cc(chan, i, 0);167}168169chan->previous_cc_breath = 0;/* Reset previous breath */170}171/* Unconditionally clear PTC receive (issue #1050) */172fluid_channel_clear_portamento(chan);173174/* Reset polyphonic key pressure on all voices */175for(i = 0; i < 128; i++)176{177fluid_channel_set_key_pressure(chan, i, 0);178}179180/* Set RPN controllers to NULL state */181fluid_channel_set_cc(chan, RPN_LSB, 127);182fluid_channel_set_cc(chan, RPN_MSB, 127);183184/* Set NRPN controllers to NULL state */185fluid_channel_set_cc(chan, NRPN_LSB, 127);186fluid_channel_set_cc(chan, NRPN_MSB, 127);187188/* Expression (MSB & LSB) */189fluid_channel_set_cc(chan, EXPRESSION_MSB, 127);190fluid_channel_set_cc(chan, EXPRESSION_LSB, 127);191192if(!is_all_ctrl_off)193{194195chan->pitch_wheel_sensitivity = 2; /* two semi-tones */196197/* Just like panning, a value of 64 indicates no change for sound ctrls */198for(i = SOUND_CTRL1; i <= SOUND_CTRL10; i++)199{200fluid_channel_set_cc(chan, i, 64);201}202203/* Volume / initial attenuation (MSB & LSB) */204fluid_channel_set_cc(chan, VOLUME_MSB, 100);205fluid_channel_set_cc(chan, VOLUME_LSB, 0);206207/* Pan (MSB & LSB) */208fluid_channel_set_cc(chan, PAN_MSB, 64);209fluid_channel_set_cc(chan, PAN_LSB, 0);210211/* Balance (MSB & LSB) */212fluid_channel_set_cc(chan, BALANCE_MSB, 64);213fluid_channel_set_cc(chan, BALANCE_LSB, 0);214215/* Reverb */216/* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */217/* Note: although XG standard specifies the default amount of reverb to218be 40, most people preferred having it at zero.219See https://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */220}221}222223/* Only called by delete_fluid_synth(), so no need to queue a preset free event */224void225delete_fluid_channel(fluid_channel_t *chan)226{227fluid_return_if_fail(chan != NULL);228229FLUID_FREE(chan);230}231232void233fluid_channel_reset(fluid_channel_t *chan)234{235fluid_channel_init(chan);236fluid_channel_init_ctrl(chan, 0);237}238239/* Should only be called from synthesis context */240int241fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset)242{243fluid_sfont_t *sfont;244245if(chan->preset == preset)246{247return FLUID_OK;248}249250if(chan->preset)251{252sfont = chan->preset->sfont;253sfont->refcount--;254}255256fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);257258chan->preset = preset;259260if(preset)261{262sfont = preset->sfont;263sfont->refcount++;264}265266fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);267268return FLUID_OK;269}270271/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */272void273fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfontnum,274int banknum, int prognum)275{276int oldval, newval, oldmask;277278newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)279| ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)280| ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);281282oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)283| ((banknum != -1) ? 0 : BANK_MASKVAL)284| ((prognum != -1) ? 0 : PROG_MASKVAL);285286oldval = chan->sfont_bank_prog;287newval = (newval & ~oldmask) | (oldval & oldmask);288chan->sfont_bank_prog = newval;289}290291/* Set bank LSB 7 bits */292void293fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb)294{295int oldval, newval, style;296297style = chan->synth->bank_select;298299if(style == FLUID_BANK_STYLE_GM ||300style == FLUID_BANK_STYLE_GS)301{302return; /* ignored */303}304305oldval = chan->sfont_bank_prog;306307if(style == FLUID_BANK_STYLE_XG)308{309newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);310}311else /* style == FLUID_BANK_STYLE_MMA */312{313newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);314}315316chan->sfont_bank_prog = newval;317}318319/* Set bank MSB 7 bits */320void321fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb)322{323int oldval, newval, style;324325style = chan->synth->bank_select;326327if(style == FLUID_BANK_STYLE_XG)328{329/* XG bank, do drum-channel auto-switch */330/* The number "120" was based on several keyboards having drums at 120 - 127,331reference: https://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */332chan->channel_type = (120 == bankmsb || 126 == bankmsb || 127 == bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;333return;334}335336if(style == FLUID_BANK_STYLE_GM ||337chan->channel_type == CHANNEL_TYPE_DRUM)338{339return; /* ignored */340}341342oldval = chan->sfont_bank_prog;343344if(style == FLUID_BANK_STYLE_GS)345{346newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);347}348else /* style == FLUID_BANK_STYLE_MMA */349{350newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));351}352353chan->sfont_bank_prog = newval;354355}356357/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */358void359fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,360int *bank, int *prog)361{362int sfont_bank_prog;363364sfont_bank_prog = chan->sfont_bank_prog;365366if(sfont)367{368*sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;369}370371if(bank)372{373*bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;374}375376if(prog)377{378*prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;379}380}381382/**383* Compute the pitch for a key after applying Fluidsynth's tuning functionality384* and channel coarse/fine tunings.385* @param chan fluid_channel_t386* @param key MIDI note number (0-127)387* @return the pitch of the key388*/389fluid_real_t fluid_channel_get_key_pitch(fluid_channel_t *chan, int key)390{391if(chan->tuning)392{393return fluid_tuning_get_pitch(chan->tuning, key)394+ 100.0f * fluid_channel_get_gen(chan, GEN_COARSETUNE)395+ fluid_channel_get_gen(chan, GEN_FINETUNE);396}397else398{399return key * 100.0f;400}401}402403/**404* Updates legato/ staccato playing state405* The function is called:406* - on noteon before adding a note into the monolist.407* - on noteoff after removing a note out of the monolist.408* @param chan fluid_channel_t.409*/410static void411fluid_channel_update_legato_staccato_state(fluid_channel_t *chan)412{413/* Updates legato/ staccato playing state */414if(chan->n_notes)415{416chan->mode |= FLUID_CHANNEL_LEGATO_PLAYING; /* Legato state */417}418else419{420chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */421}422}423424/**425* Adds a note into the monophonic list. The function is part of the legato426* detector. fluid_channel_add_monolist() is intended to be called by427* fluid_synth_noteon_mono_LOCAL().428*429* When a note is added at noteOn each element is use in the forward direction430* and indexed by i_last variable.431*432* @param chan fluid_channel_t.433* @param key MIDI note number (0-127).434* @param vel MIDI velocity (0-127, 0=noteoff).435* @param onenote. When 1 the function adds the note but the monophonic list436* keeps only one note (used on noteOn poly).437* Note: i_last index keeps a trace of the most recent note added.438* prev_note keeps a trace of the note prior i_last note.439* FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state.440*441* More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).442*/443void444fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key,445unsigned char vel, unsigned char onenote)446{447unsigned char i_last = chan->i_last;448/* Updates legato/ staccato playing state */449fluid_channel_update_legato_staccato_state(chan);450451if(chan->n_notes)452{453/* keeps trace of the note prior last note */454chan->prev_note = chan->monolist[i_last].note;455}456457/* moves i_last forward before writing new note */458i_last = chan->monolist[i_last].next;459chan->i_last = i_last; /* now ilast indexes the last note */460chan->monolist[i_last].note = key; /* we save note and velocity */461chan->monolist[i_last].vel = vel;462463if(onenote)464{465/* clears monolist before one note addition */466chan->i_first = i_last;467chan->n_notes = 0;468}469470if(chan->n_notes < FLUID_CHANNEL_SIZE_MONOLIST)471{472chan->n_notes++; /* updates n_notes */473}474else475{476/* The end of buffer is reach. So circular motion for i_first */477/* i_first index is moved forward */478chan->i_first = chan->monolist[i_last].next;479}480}481482/**483* Searching a note in the monophonic list. The function is part of the legato484* detector. fluid_channel_search_monolist() is intended to be called by485* fluid_synth_noteoff_mono_LOCAL().486*487* The search starts from the first note in the list indexed by i_first488489* @param chan fluid_channel_t.490* @param key MIDI note number (0-127) to search.491* @param i_prev pointer on returned index of the note prior the note to search.492* @return index of the note if find, FLUID_FAILED otherwise.493*494*/495int496fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev)497{498short n = chan->n_notes; /* number of notes in monophonic list */499short j, i = chan->i_first; /* searching starts from i_first included */500501for(j = 0 ; j < n ; j++)502{503if(chan->monolist[i].note == key)504{505if(i == chan->i_first)506{507/* tracking index of the previous note (i_prev) */508for(j = chan->i_last ; n < FLUID_CHANNEL_SIZE_MONOLIST; n++)509{510j = chan->monolist[j].next;511}512513* i_prev = j; /* returns index of the previous note */514}515516return i; /* returns index of the note to search */517}518519* i_prev = i; /* tracking index of the previous note (i_prev) */520i = chan->monolist[i].next; /* next element */521}522523return FLUID_FAILED; /* not found */524}525526/**527* removes a note from the monophonic list. The function is part of528* the legato detector.529* fluid_channel_remove_monolist() is intended to be called by530* fluid_synth_noteoff_mono_LOCAL().531*532* When a note is removed at noteOff the element concerned is fast unlinked533* and relinked after the i_last element.534*535* @param chan fluid_channel_t.536* @param537* i, index of the note to remove. If i is invalid or the list is538* empty, the function do nothing and returns FLUID_FAILED.539* @param540* On input, i_prev is a pointer on index of the note previous i.541* On output i_prev is a pointer on index of the note previous i if i is the last note542* in the list,FLUID_FAILED otherwise. When the returned index is valid it means543* a legato detection on noteoff.544*545* Note: the following variables in Channel keeps trace of the situation.546* - i_last index keeps a trace of the most recent note played even if547* the list is empty.548* - prev_note keeps a trace of the note removed if it is i_last.549* - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state.550*551* More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).552*/553void554fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev)555{556unsigned char i_last = chan->i_last;557558/* checks if index is valid */559if(i < 0 || i >= FLUID_CHANNEL_SIZE_MONOLIST || !chan->n_notes)560{561* i_prev = FLUID_FAILED;562}563564/* The element is about to be removed and inserted between i_last and next */565/* Note: when i is egal to i_last or egal to i_first, removing/inserting566isn't necessary */567if(i == i_last)568{569/* Removing/Inserting isn't necessary */570/* keeps trace of the note prior last note */571chan->prev_note = chan->monolist[i_last].note;572/* moves i_last backward to the previous */573chan->i_last = *i_prev; /* i_last index is moved backward */574}575else576{577/* i is before i_last */578if(i == chan->i_first)579{580/* Removing/inserting isn't necessary */581/* i_first index is moved forward to the next element*/582chan->i_first = chan->monolist[i].next;583}584else585{586/* i is between i_first and i_last */587/* Unlinks element i and inserts after i_last */588chan->monolist[* i_prev].next = chan->monolist[i].next; /* unlinks i */589/*inserts i after i_last */590chan->monolist[i].next = chan->monolist[i_last].next;591chan->monolist[i_last].next = i;592}593594* i_prev = FLUID_FAILED;595}596597chan->n_notes--; /* updates the number of note in the list */598/* Updates legato/ staccato playing state */599fluid_channel_update_legato_staccato_state(chan);600}601602/**603* On noteOff on a polyphonic channel,the monophonic list is fully flushed.604*605* @param chan fluid_channel_t.606* Note: i_last index keeps a trace of the most recent note played even if607* the list is empty.608* prev_note keeps a trace of the note i_last .609* FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing.610*/611void fluid_channel_clear_monolist(fluid_channel_t *chan)612{613/* keeps trace off the most recent note played */614chan->prev_note = chan->monolist[chan->i_last].note;615616/* flushes the monolist */617chan->i_first = chan->monolist[chan->i_last].next;618chan->n_notes = 0;619/* Update legato/ sataccato playing state */620chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */621}622623/**624* On noteOn on a polyphonic channel,adds the note into the monophonic list625* keeping only this note.626* @param627* chan fluid_channel_t.628* key, vel, note and velocity added in the monolist629* Note: i_last index keeps a trace of the most recent note inserted.630* prev_note keeps a trace of the note prior i_last note.631* FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.632*/633void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key,634unsigned char vel)635{636fluid_channel_add_monolist(chan, key, vel, 1);637}638639/**640* The function changes the state (Valid/Invalid) of the previous note played in641* a staccato manner (fluid_channel_prev_note()).642* When potamento mode 'each note' or 'staccato only' is selected, on next643* noteOn a portamento will be started from the most recent note played644* staccato.645* It will be possible that it isn't appropriate. To give the musician the646* possibility to choose a portamento from this note , prev_note will be forced647* to invalid state on noteOff if portamento pedal is Off.648*649* The function is intended to be called when the following event occurs:650* - On noteOff (in poly or mono mode), to mark prev_note invalid.651* - On Portamento Off(in poly or mono mode), to mark prev_note invalid.652* @param chan fluid_channel_t.653*/654void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan)655{656/* checks if the playing is staccato */657if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))658{659660/* checks if portamento pedal is off */661if(! fluid_channel_portamento(chan))662{663/* forces prev_note invalid */664fluid_channel_clear_prev_note(chan);665}666}667668/* else prev_note still remains valid for next fromkey portamento */669}670671/**672* The function handles poly/mono commutation on legato pedal On/Off.673* @param chan fluid_channel_t.674* @param value, value of the CC legato.675*/676void fluid_channel_cc_legato(fluid_channel_t *chan, int value)677{678/* Special handling of the monophonic list */679if(!(chan->mode & FLUID_CHANNEL_POLY_OFF) && chan->n_notes) /* The monophonic list have notes */680{681if(value < 64) /* legato is released */682{683/* returns from monophonic to polyphonic with notes in the monophonic list */684685/* The monophonic list is flushed keeping last note only686Note: i_last index keeps a trace of the most recent note played.687prev_note keeps a trace of the note i_last.688FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.689*/690chan->i_first = chan->i_last;691chan->n_notes = 1;692}693else /* legato is depressed */694{695/* Inters in monophonic from polyphonic with note in monophonic list */696/* Stops the running note to remain coherent with Breath Sync mode */697if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && !fluid_channel_breath_msb(chan))698{699fluid_synth_noteoff_monopoly(chan->synth, chan->channum,700fluid_channel_last_note(chan), 1);701}702}703}704}705706/**707* The function handles CC Breath On/Off detection. When a channel is in708* Breath Sync mode and in monophonic playing, the breath controller allows709* to trigger noteon/noteoff note when the musician starts to breath (noteon) and710* stops to breath (noteoff).711* @param chan fluid_channel_t.712* @param value, value of the CC Breath..713*/714void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value)715{716if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && fluid_channel_is_playing_mono(chan) &&717(chan->n_notes))718{719/* The monophonic list isn't empty */720if((value > 0) && (chan->previous_cc_breath == 0))721{722/* CC Breath On detection */723fluid_synth_noteon_mono_staccato(chan->synth, chan->channum,724fluid_channel_last_note(chan),725fluid_channel_last_vel(chan));726}727else if((value == 0) && (chan->previous_cc_breath > 0))728{729/* CC Breath Off detection */730fluid_synth_noteoff_monopoly(chan->synth, chan->channum,731fluid_channel_last_note(chan), 1);732}733}734735chan->previous_cc_breath = value;736}737738int fluid_channel_get_override_gen_default(fluid_channel_t *chan, int gen, fluid_real_t* val)739{740if(chan->override_gen_default[gen].flags != GEN_UNUSED)741{742*val = chan->override_gen_default[gen].val;743return TRUE;744}745746return FALSE;747}748749void fluid_channel_set_override_gen_default(fluid_channel_t *chan, int gen, fluid_real_t val)750{751chan->override_gen_default[gen].flags = GEN_SET;752chan->override_gen_default[gen].val = val;753}754755756