summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/fluidsynth/src/fluid_event.c')
-rw-r--r--libs/fluidsynth/src/fluid_event.c781
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
+}