diff options
Diffstat (limited to 'libs/fluidsynth/src/fluid_event.c')
-rw-r--r-- | libs/fluidsynth/src/fluid_event.c | 781 |
1 files changed, 781 insertions, 0 deletions
diff --git a/libs/fluidsynth/src/fluid_event.c b/libs/fluidsynth/src/fluid_event.c new file mode 100644 index 0000000000..b3b0608345 --- /dev/null +++ b/libs/fluidsynth/src/fluid_event.c @@ -0,0 +1,781 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/* + 2002 : API design by Peter Hanappe and Antoine Schmitt + August 2002 : Implementation by Antoine Schmitt as@gratin.org + as part of the infiniteCD author project + http://www.infiniteCD.org/ + Oct4.2002 : AS : corrected bug in heap allocation, that caused a crash during sequencer free. +*/ + + +#include "fluid_event_priv.h" +#include "fluidsynth_priv.h" + +/*************************************************************** + * + * SEQUENCER EVENTS + */ + +/* Event alloc/free */ + +void +fluid_event_clear(fluid_event_t* evt) +{ + FLUID_MEMSET(evt, 0, sizeof(fluid_event_t)); + + // by default, no type + evt->dest = -1; + evt->src = -1; + evt->type = -1; +} + +/** + * Create a new sequencer event structure. + * @return New sequencer event structure or NULL if out of memory + */ +fluid_event_t* +new_fluid_event() +{ + fluid_event_t* evt; + + evt = FLUID_NEW(fluid_event_t); + if (evt == NULL) { + fluid_log(FLUID_PANIC, "event: Out of memory\n"); + return NULL; + } + fluid_event_clear(evt); + + return(evt); +} + +/** + * Delete a sequencer event structure. + * @param evt Sequencer event structure created by new_fluid_event(). + */ +void +delete_fluid_event(fluid_event_t* evt) +{ + + if (evt == NULL) { + return; + } + + FLUID_FREE(evt); +} + +/** + * Set the time field of a sequencer event. + * @internal + * @param evt Sequencer event structure + * @param time Time value to assign + */ +void +fluid_event_set_time(fluid_event_t* evt, unsigned int time) +{ + evt->time = time; +} + +/** + * Set source of a sequencer event (DOCME). + * @param evt Sequencer event structure + * @param src DOCME + */ +void +fluid_event_set_source(fluid_event_t* evt, short src) +{ + evt->src = src; +} + +/** + * Set destination of a sequencer event (DOCME). + * @param evt Sequencer event structure + * @param dest DOCME + */ +void +fluid_event_set_dest(fluid_event_t* evt, short dest) +{ + evt->dest = dest; +} + +/** + * Set a sequencer event to be a timer event. + * @param evt Sequencer event structure + * @param data DOCME + */ +void +fluid_event_timer(fluid_event_t* evt, void* data) +{ + evt->type = FLUID_SEQ_TIMER; + evt->data = data; +} + +/** + * Set a sequencer event to be a note on event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + * @param vel MIDI velocity value (0-127) + */ +void +fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel) +{ + evt->type = FLUID_SEQ_NOTEON; + evt->channel = channel; + evt->key = key; + evt->vel = vel; +} + +/** + * Set a sequencer event to be a note off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + */ +void +fluid_event_noteoff(fluid_event_t* evt, int channel, short key) +{ + evt->type = FLUID_SEQ_NOTEOFF; + evt->channel = channel; + evt->key = key; +} + +/** + * Set a sequencer event to be a note duration event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + * @param vel MIDI velocity value (0-127) + * @param duration Duration of note (DOCME units?) + */ +void +fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration) +{ + evt->type = FLUID_SEQ_NOTE; + evt->channel = channel; + evt->key = key; + evt->vel = vel; + evt->duration = duration; +} + +/** + * Set a sequencer event to be an all sounds off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + */ +void +fluid_event_all_sounds_off(fluid_event_t* evt, int channel) +{ + evt->type = FLUID_SEQ_ALLSOUNDSOFF; + evt->channel = channel; +} + +/** + * Set a sequencer event to be a all notes off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + */ +void +fluid_event_all_notes_off(fluid_event_t* evt, int channel) +{ + evt->type = FLUID_SEQ_ALLNOTESOFF; + evt->channel = channel; +} + +/** + * Set a sequencer event to be a bank select event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param bank_num MIDI bank number (0-16383) + */ +void +fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num) +{ + evt->type = FLUID_SEQ_BANKSELECT; + evt->channel = channel; + evt->control = bank_num; +} + +/** + * Set a sequencer event to be a program change event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI program number (0-127) + */ +void +fluid_event_program_change(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_PROGRAMCHANGE; + evt->channel = channel; + evt->value = val; +} + +/** + * Set a sequencer event to be a program select event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param sfont_id SoundFont ID number + * @param bank_num MIDI bank number (0-16383) + * @param preset_num MIDI preset number (0-127) + */ +void +fluid_event_program_select(fluid_event_t* evt, int channel, + unsigned int sfont_id, short bank_num, short preset_num) +{ + evt->type = FLUID_SEQ_PROGRAMSELECT; + evt->channel = channel; + evt->duration = sfont_id; + evt->value = preset_num; + evt->control = bank_num; +} + +/** + * Set a sequencer event to be an any control change event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * DOCME + */ +void +fluid_event_any_control_change(fluid_event_t* evt, int channel) +{ + evt->type = FLUID_SEQ_ANYCONTROLCHANGE; + evt->channel = channel; +} + +/** + * Set a sequencer event to be a pitch bend event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param pitch MIDI pitch bend value (0-16383, 8192 = no bend) + */ +void +fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch) +{ + evt->type = FLUID_SEQ_PITCHBEND; + evt->channel = channel; + if (pitch < 0) pitch = 0; + if (pitch > 16383) pitch = 16383; + evt->pitch = pitch; +} + +/** + * Set a sequencer event to be a pitch wheel sensitivity event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param value MIDI pitch wheel sensitivity value (DOCME units?) + */ +void +fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value) +{ + evt->type = FLUID_SEQ_PITCHWHHELSENS; + evt->channel = channel; + evt->value = value; +} + +/** + * Set a sequencer event to be a modulation event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI modulation value (0-127) + */ +void +fluid_event_modulation(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_MODULATION; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a MIDI sustain event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI sustain value (0-127) + */ +void +fluid_event_sustain(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_SUSTAIN; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a MIDI control change event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param control MIDI control number (0-127) + * @param val MIDI control value (0-16383 DOCME is that true?) + */ +void +fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val) +{ + evt->type = FLUID_SEQ_CONTROLCHANGE; + evt->channel = channel; + evt->control = control; + evt->value = val; +} + +/** + * Set a sequencer event to be a stereo pan event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right) + */ +void +fluid_event_pan(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_PAN; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a volume event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Volume value (0-127) + */ +void +fluid_event_volume(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_VOLUME; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a reverb send event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Reverb amount (0-127) + */ +void +fluid_event_reverb_send(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_REVERBSEND; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a chorus send event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Chorus amount (0-127) + */ +void +fluid_event_chorus_send(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_CHORUSSEND; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + + +/** + * Set a sequencer event to be an unregistering event. + * @param evt Sequencer event structure + * @since 1.1.0 + */ +void +fluid_event_unregistering(fluid_event_t* evt) +{ + evt->type = FLUID_SEQ_UNREGISTERING; +} + +/** + * Set a sequencer event to be a channel-wide aftertouch event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Aftertouch amount (0-127) + * @since 1.1.0 + */ +void +fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_CHANNELPRESSURE; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a midi system reset event. + * @param evt Sequencer event structure + * @since 1.1.0 + */ +void +fluid_event_system_reset(fluid_event_t* evt) +{ + evt->type = FLUID_SEQ_SYSTEMRESET; +} + + + +/* + * Accessing event data + */ + +/** + * Get the event type (#fluid_seq_event_type) field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Event type (#fluid_seq_event_type). + */ +int fluid_event_get_type(fluid_event_t* evt) +{ + return evt->type; +} + +/** + * Get the time field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Time value (DOCME units?) + */ +unsigned int fluid_event_get_time(fluid_event_t* evt) +{ + return evt->time; +} + +/** + * Get the source field from a sequencer event structure. + * @param evt Sequencer event structure + * @return DOCME + */ +short fluid_event_get_source(fluid_event_t* evt) +{ + return evt->src; +} + +/** + * Get the dest field from a sequencer event structure. + * @param evt Sequencer event structure + * @return DOCME + */ +short fluid_event_get_dest(fluid_event_t* evt) +{ + return evt->dest; +} + +/** + * Get the MIDI channel field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI channel number (DOCME 0-15 or more?) + */ +int fluid_event_get_channel(fluid_event_t* evt) +{ + return evt->channel; +} + +/** + * Get the MIDI note field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI note number (0-127) + */ +short fluid_event_get_key(fluid_event_t* evt) +{ + return evt->key; +} + +/** + * Get the MIDI velocity field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI velocity value (0-127) + */ +short fluid_event_get_velocity(fluid_event_t* evt) + +{ + return evt->vel; +} + +/** + * Get the MIDI control number field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI control number (0-127) + */ +short fluid_event_get_control(fluid_event_t* evt) +{ + return evt->control; +} + +/** + * Get the value field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Value field of event. + * + * The Value field is used by the following event types: + * #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num), + * #FLUID_SEQ_PITCHWHHELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN, + * #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME, + * #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND. + */ +short fluid_event_get_value(fluid_event_t* evt) +{ + return evt->value; +} + +/** + * Get the data field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Data field of event. + * + * Used by the #FLUID_SEQ_TIMER event type. + */ +void* fluid_event_get_data(fluid_event_t* evt) +{ + return evt->data; +} + +/** + * Get the duration field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Note duration value (DOCME units?) + * + * Used by the #FLUID_SEQ_NOTE event type. + */ +unsigned int fluid_event_get_duration(fluid_event_t* evt) +{ + return evt->duration; +} + +/** + * Get the MIDI bank field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI bank number (0-16383) + * + * Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT + * event types. + */ +short fluid_event_get_bank(fluid_event_t* evt) +{ + return evt->control; +} + +/** + * Get the pitch field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI pitch bend pitch value (0-16383, 8192 = no bend) + * + * Used by the #FLUID_SEQ_PITCHBEND event type. + */ +int fluid_event_get_pitch(fluid_event_t* evt) +{ + return evt->pitch; +} + +/** + * Get the MIDI program field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI program number (0-127) + * + * Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT + * event types. + */ +short +fluid_event_get_program(fluid_event_t* evt) +{ + return evt->value; +} + +/** + * Get the SoundFont ID field from a sequencer event structure. + * @param evt Sequencer event structure + * @return SoundFont identifier value. + * + * Used by the #FLUID_SEQ_PROGRAMSELECT event type. + */ +unsigned int +fluid_event_get_sfont_id(fluid_event_t* evt) +{ + return evt->duration; +} + + + +/********************/ +/* heap management */ +/********************/ + +fluid_evt_heap_t* +_fluid_evt_heap_init(int nbEvents) +{ +#ifdef HEAP_WITH_DYNALLOC + + int i; + fluid_evt_heap_t* heap; + fluid_evt_entry *tmp; + + heap = FLUID_NEW(fluid_evt_heap_t); + if (heap == NULL) { + fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); + return NULL; + } + + heap->freelist = NULL; + fluid_mutex_init(heap->mutex); + + /* LOCK */ + fluid_mutex_lock(heap->mutex); + + /* Allocate the event entries */ + for (i = 0; i < nbEvents; i++) { + tmp = FLUID_NEW(fluid_evt_entry); + tmp->next = heap->freelist; + heap->freelist = tmp; + } + + /* UNLOCK */ + fluid_mutex_unlock(heap->mutex); + + +#else + int i; + fluid_evt_heap_t* heap; + int siz = 2*sizeof(fluid_evt_entry *) + sizeof(fluid_evt_entry)*nbEvents; + + heap = (fluid_evt_heap_t *)FLUID_MALLOC(siz); + if (heap == NULL) { + fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); + return NULL; + } + FLUID_MEMSET(heap, 0, siz); + + /* link all heap events */ + { + fluid_evt_entry *tmp = &(heap->pool); + for (i = 0 ; i < nbEvents - 1 ; i++) + tmp[i].next = &(tmp[i+1]); + tmp[nbEvents-1].next = NULL; + + /* set head & tail */ + heap->tail = &(tmp[nbEvents-1]); + heap->head = &(heap->pool); + } +#endif + return (heap); +} + +void +_fluid_evt_heap_free(fluid_evt_heap_t* heap) +{ +#ifdef HEAP_WITH_DYNALLOC + fluid_evt_entry *tmp, *next; + + /* LOCK */ + fluid_mutex_lock(heap->mutex); + + tmp = heap->freelist; + while (tmp) { + next = tmp->next; + FLUID_FREE(tmp); + tmp = next; + } + + /* UNLOCK */ + fluid_mutex_unlock(heap->mutex); + fluid_mutex_destroy(heap->mutex); + + FLUID_FREE(heap); + +#else + FLUID_FREE(heap); +#endif +} + +fluid_evt_entry* +_fluid_seq_heap_get_free(fluid_evt_heap_t* heap) +{ +#ifdef HEAP_WITH_DYNALLOC + fluid_evt_entry* evt = NULL; + + /* LOCK */ + fluid_mutex_lock(heap->mutex); + +#if !defined(MACOS9) + if (heap->freelist == NULL) { + heap->freelist = FLUID_NEW(fluid_evt_entry); + if (heap->freelist != NULL) { + heap->freelist->next = NULL; + } + } +#endif + + evt = heap->freelist; + + if (evt != NULL) { + heap->freelist = heap->freelist->next; + evt->next = NULL; + } + + /* UNLOCK */ + fluid_mutex_unlock(heap->mutex); + + return evt; + +#else + fluid_evt_entry* evt; + if (heap->head == NULL) return NULL; + + /* take from head of the heap */ + /* critical - should threadlock ? */ + evt = heap->head; + heap->head = heap->head->next; + + return evt; +#endif +} + +void +_fluid_seq_heap_set_free(fluid_evt_heap_t* heap, fluid_evt_entry* evt) +{ +#ifdef HEAP_WITH_DYNALLOC + + /* LOCK */ + fluid_mutex_lock(heap->mutex); + + evt->next = heap->freelist; + heap->freelist = evt; + + /* UNLOCK */ + fluid_mutex_unlock(heap->mutex); + +#else + /* append to the end of the heap */ + /* critical - should threadlock ? */ + heap->tail->next = evt; + heap->tail = evt; + evt->next = NULL; +#endif +} |