mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 23:11:41 +00:00
Enable sequencer to accept all types of events that MIDI threads can generate. Change behavior of fluid_sequencer_send_at to ensure thread safety.
This commit is contained in:
parent
a8bffeb370
commit
e25765e61b
7 changed files with 145 additions and 16 deletions
|
@ -45,7 +45,7 @@ enum fluid_seq_event_type {
|
||||||
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
||||||
FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
|
FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
|
||||||
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
||||||
FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message */
|
FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message TODO: Correct spelling of this event? */
|
||||||
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
||||||
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
||||||
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
||||||
|
@ -55,6 +55,8 @@ enum fluid_seq_event_type {
|
||||||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||||
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
|
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
|
||||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
|
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
|
||||||
|
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
|
||||||
|
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
|
||||||
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
|
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
|
||||||
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
|
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
|
||||||
};
|
};
|
||||||
|
@ -71,7 +73,7 @@ FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t* evt, short dest);
|
||||||
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data);
|
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data);
|
||||||
|
|
||||||
/* Note events */
|
/* Note events */
|
||||||
FLUIDSYNTH_API void fluid_event_note(fluid_event_t* evt, int channel,
|
FLUIDSYNTH_API void fluid_event_nfluid_event_set_timeote(fluid_event_t* evt, int channel,
|
||||||
short key, short vel,
|
short key, short vel,
|
||||||
unsigned int duration);
|
unsigned int duration);
|
||||||
|
|
||||||
|
@ -99,6 +101,10 @@ FLUIDSYNTH_API void fluid_event_volume(fluid_event_t* evt, int channel, short va
|
||||||
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
|
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
|
||||||
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
|
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
|
||||||
|
|
||||||
|
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val);
|
||||||
|
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt);
|
||||||
|
|
||||||
|
|
||||||
/* Only for removing events */
|
/* Only for removing events */
|
||||||
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
|
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ extern "C" {
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth);
|
short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth);
|
||||||
|
|
||||||
|
int
|
||||||
|
fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -107,6 +107,9 @@ FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int ch
|
||||||
/** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */
|
/** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */
|
||||||
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
|
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
|
||||||
|
|
||||||
|
/** Send a channel aftertouch message. Returns 0 if no error occurred, -1 otherwise. */
|
||||||
|
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
|
||||||
|
|
||||||
/** Select a bank. Returns 0 if no error occurred, -1 otherwise. */
|
/** Select a bank. Returns 0 if no error occurred, -1 otherwise. */
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
|
int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
|
||||||
|
|
|
@ -38,6 +38,17 @@
|
||||||
|
|
||||||
/* Event alloc/free */
|
/* 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.
|
* Create a new sequencer event structure.
|
||||||
* @return New sequencer event structure or NULL if out of memory
|
* @return New sequencer event structure or NULL if out of memory
|
||||||
|
@ -52,13 +63,7 @@ new_fluid_event()
|
||||||
fluid_log(FLUID_PANIC, "event: Out of memory\n");
|
fluid_log(FLUID_PANIC, "event: Out of memory\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
fluid_event_clear(evt);
|
||||||
FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
|
|
||||||
|
|
||||||
// by default, no type
|
|
||||||
evt->dest = -1;
|
|
||||||
evt->src = -1;
|
|
||||||
evt->type = -1;
|
|
||||||
|
|
||||||
return(evt);
|
return(evt);
|
||||||
}
|
}
|
||||||
|
@ -402,6 +407,7 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
|
||||||
/**
|
/**
|
||||||
* Set a sequencer event to be an unregistering event.
|
* Set a sequencer event to be an unregistering event.
|
||||||
* @param evt Sequencer event structure
|
* @param evt Sequencer event structure
|
||||||
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fluid_event_unregistering(fluid_event_t* evt)
|
fluid_event_unregistering(fluid_event_t* evt)
|
||||||
|
@ -409,6 +415,34 @@ fluid_event_unregistering(fluid_event_t* evt)
|
||||||
evt->type = FLUID_SEQ_UNREGISTERING;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -46,6 +46,8 @@ struct _fluid_event_t {
|
||||||
unsigned int fluid_event_get_time(fluid_event_t* evt);
|
unsigned int fluid_event_get_time(fluid_event_t* evt);
|
||||||
void fluid_event_set_time(fluid_event_t* evt, unsigned int time);
|
void fluid_event_set_time(fluid_event_t* evt, unsigned int time);
|
||||||
|
|
||||||
|
void fluid_event_clear(fluid_event_t* evt);
|
||||||
|
|
||||||
/* private data for sorter + heap */
|
/* private data for sorter + heap */
|
||||||
enum fluid_evt_entry_type {
|
enum fluid_evt_entry_type {
|
||||||
FLUID_EVT_ENTRY_INSERT = 0,
|
FLUID_EVT_ENTRY_INSERT = 0,
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
/* Private data for SEQUENCER */
|
/* Private data for SEQUENCER */
|
||||||
struct _fluid_sequencer_t {
|
struct _fluid_sequencer_t {
|
||||||
unsigned int startMs;
|
unsigned int startMs;
|
||||||
unsigned int currentMs;
|
gint currentMs;
|
||||||
gboolean useSystemTimer;
|
gboolean useSystemTimer;
|
||||||
double scale; // ticks per second
|
double scale; // ticks per second
|
||||||
fluid_list_t* clients;
|
fluid_list_t* clients;
|
||||||
|
@ -379,6 +379,7 @@ void fluid_sequencer_send_now(fluid_sequencer_t* seq, fluid_event_t* evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt, unsigned int time, int absolute)
|
fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt, unsigned int time, int absolute)
|
||||||
{
|
{
|
||||||
|
@ -392,16 +393,17 @@ fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt, unsigned int
|
||||||
fluid_event_set_time(evt, time);
|
fluid_event_set_time(evt, time);
|
||||||
|
|
||||||
/* process late */
|
/* process late */
|
||||||
if (time < now) {
|
/* Commented out for thread safety - send_at must go via the queue */
|
||||||
|
/* if (time < now) {
|
||||||
fluid_sequencer_send_now(seq, evt);
|
fluid_sequencer_send_now(seq, evt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/* process now */
|
/* process now */
|
||||||
if (time == now) {
|
/* if (time == now) {
|
||||||
fluid_sequencer_send_now(seq, evt);
|
fluid_sequencer_send_now(seq, evt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/* queue for processing later */
|
/* queue for processing later */
|
||||||
return _fluid_seq_queue_pre_insert(seq, evt);
|
return _fluid_seq_queue_pre_insert(seq, evt);
|
||||||
|
@ -419,7 +421,7 @@ fluid_sequencer_remove_events(fluid_sequencer_t* seq, short source, short dest,
|
||||||
**************************************/
|
**************************************/
|
||||||
unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq)
|
unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq)
|
||||||
{
|
{
|
||||||
unsigned int absMs = seq->useSystemTimer ? fluid_curtime() : seq->currentMs;
|
unsigned int absMs = seq->useSystemTimer ? (int) fluid_curtime() : g_atomic_int_get(&seq->currentMs);
|
||||||
double nowFloat;
|
double nowFloat;
|
||||||
unsigned int now;
|
unsigned int now;
|
||||||
nowFloat = ((double)(absMs - seq->startMs))*seq->scale/1000.0f;
|
nowFloat = ((double)(absMs - seq->startMs))*seq->scale/1000.0f;
|
||||||
|
@ -763,7 +765,7 @@ fluid_sequencer_process(fluid_sequencer_t* seq, unsigned int msec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send queued events */
|
/* send queued events */
|
||||||
seq->currentMs = msec;
|
g_atomic_int_set(&seq->currentMs, msec);
|
||||||
_fluid_seq_queue_send_queued_events(seq);
|
_fluid_seq_queue_send_queued_events(seq);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "fluidsynth_priv.h"
|
#include "fluidsynth_priv.h"
|
||||||
#include "fluid_synth.h"
|
#include "fluid_synth.h"
|
||||||
|
#include "fluid_midi.h"
|
||||||
|
#include "fluid_event_priv.h"
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
|
@ -229,6 +231,18 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FLUID_SEQ_CHANNELPRESSURE:
|
||||||
|
{
|
||||||
|
fluid_synth_channel_pressure(synth, fluid_event_get_channel(evt), fluid_event_get_value(evt));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FLUID_SEQ_SYSTEMRESET:
|
||||||
|
{
|
||||||
|
fluid_synth_system_reset(synth);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case FLUID_SEQ_UNREGISTERING: /* free ourselves */
|
case FLUID_SEQ_UNREGISTERING: /* free ourselves */
|
||||||
{
|
{
|
||||||
seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */
|
seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */
|
||||||
|
@ -245,4 +259,70 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_fluidsynth_dest(fluid_sequencer_t* seq)
|
||||||
|
{
|
||||||
|
int i, id;
|
||||||
|
char* name;
|
||||||
|
int j = fluid_sequencer_count_clients(seq);
|
||||||
|
for (i = 0; i < j; i++) {
|
||||||
|
id = fluid_sequencer_get_client_id(seq, i);
|
||||||
|
name = fluid_sequencer_get_client_name(seq, id);
|
||||||
|
if (strcmp(name, "fluidsynth") == 0) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms an incoming midi event (from a midi driver or midi router) to a
|
||||||
|
* sequencer event and adds it to the sequencer queue for sending as soon as possible.
|
||||||
|
* @param data the sequencer, must be a valid fluid_sequencer_t
|
||||||
|
* @param event midi event
|
||||||
|
* @return FLUID_OK or FLUID_FAILED
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event)
|
||||||
|
{
|
||||||
|
fluid_event_t evt;
|
||||||
|
fluid_sequencer_t* seq = (fluid_sequencer_t*) data;
|
||||||
|
int chan = fluid_midi_event_get_channel(event);
|
||||||
|
|
||||||
|
fluid_event_clear(&evt);
|
||||||
|
fluid_event_set_time(&evt, fluid_sequencer_get_tick(seq));
|
||||||
|
fluid_event_set_dest(&evt, get_fluidsynth_dest(seq));
|
||||||
|
|
||||||
|
switch (fluid_midi_event_get_type(event)) {
|
||||||
|
case NOTE_OFF:
|
||||||
|
fluid_event_noteoff(&evt, chan, fluid_midi_event_get_key(event));
|
||||||
|
break;
|
||||||
|
case NOTE_ON:
|
||||||
|
fluid_event_noteon(&evt, fluid_midi_event_get_channel(event),
|
||||||
|
fluid_midi_event_get_key(event), fluid_midi_event_get_velocity(event));
|
||||||
|
break;
|
||||||
|
case CONTROL_CHANGE:
|
||||||
|
fluid_event_control_change(&evt, chan, fluid_midi_event_get_control(event),
|
||||||
|
fluid_midi_event_get_value(event));
|
||||||
|
break;
|
||||||
|
case PROGRAM_CHANGE:
|
||||||
|
fluid_event_program_change(&evt, chan, fluid_midi_event_get_program(event));
|
||||||
|
break;
|
||||||
|
case PITCH_BEND:
|
||||||
|
fluid_event_pitch_bend(&evt, chan, fluid_midi_event_get_pitch(event));
|
||||||
|
break;
|
||||||
|
case CHANNEL_PRESSURE:
|
||||||
|
fluid_event_channel_pressure(&evt, chan, fluid_midi_event_get_program(event));
|
||||||
|
break;
|
||||||
|
case MIDI_SYSTEM_RESET:
|
||||||
|
fluid_event_system_reset(&evt);
|
||||||
|
break;
|
||||||
|
default: /* Not yet implemented */
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Schedule for sending at next call to fluid_sequencer_process */
|
||||||
|
return fluid_sequencer_send_at(seq, &evt, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue