Min glib version set to 2.6.5 (latest version for OS2).

Added public function fluid_midi_event_set_sysex().
MIDI sysex events now use param2 to indicate if its dynamically allocated or not.
Added SYSEX handling to alsa sequencer.
Re-wrote fluid_midi_parser_parse to handle SYSEX data (used by ALSA raw MIDI, CoreMidi, Jack and OSS MIDI drivers).
Added 'out' parameter to fluid_istream_readline for displaying the prompt.
Fixed bug in MIDI router where router mutex was left in a locked state with MIDI system reset messages.
Added SYSEX handling to MIDI router.
Added SYSEX handling to MidiShare driver.
Fixed synth->thread_queues free bug caused by order of fluid_private_free and queue frees.
Bug fixes in fluid_synth_sysex() to handle GM ON SYSEX and check length for GS reset message.
WIN32 HACK in fluid_sys.c to OR a flag into fluid_istream_t and fluid_ostream_t on WIN32 to differentiate between file descriptors and sockets.
Bug fix in delete_fluid_timer() where double free would occur if auto destroy was enabled.
Fixed bugs in WIN32 socket server code, which now functions properly.
CR chars are stripped in fluid_istream_gets().
Added SYSEX processing to winmidi driver, which was a non-trivial undertaking!  Fixed allocation bug related to midi.winmidi.device setting.
Command line string option settings are now surrounded by single quotes and separate with commas.
This commit is contained in:
Josh Green 2009-10-12 19:18:06 +00:00
parent 1b425d9e12
commit 3bc6d961a6
16 changed files with 529 additions and 296 deletions

View file

@ -153,7 +153,7 @@ else
fi
dnl Assert that glib and gthread are available
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.10 gthread-2.0 >= 2.10)
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.6.5 gthread-2.0 >= 2.6.5)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)

View file

@ -49,7 +49,8 @@ FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val);
FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val);
FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *data,
int size, int dynamic);
/**
* Generic callback function for MIDI events.

View file

@ -169,9 +169,6 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION

View file

@ -1212,6 +1212,12 @@ fluid_alsa_seq_run(void* d)
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.control.channel;
evt.param1 = seq_ev->data.control.value;
break;
case SND_SEQ_EVENT_SYSEX:
if (seq_ev->data.ext.len < 2) continue;
fluid_midi_event_set_sysex (&evt, (char *)(seq_ev->data.ext.ptr) + 1,
seq_ev->data.ext.len - 2, FALSE);
break;
default:
continue; /* unhandled event, next loop iteration */
}

View file

@ -210,8 +210,19 @@ void fluid_shell_init(fluid_shell_t* shell,
fluid_istream_t in, fluid_ostream_t out);
fluid_shell_t* new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t* handler,
fluid_istream_t in, fluid_ostream_t out, int thread)
/**
* Create a new FluidSynth command shell.
* @param settings Setting parameters to use with the shell
* @param handler Command handler
* @param in Input stream
* @param out Output stream
* @param thread TRUE if shell should be run in a separate thread, FALSE to run
* it in the current thread (function blocks until "quit")
* @return New shell instance or NULL on error
*/
fluid_shell_t *
new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t* handler,
fluid_istream_t in, fluid_ostream_t out, int thread)
{
fluid_shell_t* shell = FLUID_NEW(fluid_shell_t);
if (shell == NULL) {
@ -272,7 +283,7 @@ int fluid_shell_run(fluid_shell_t* shell)
/* handle user input */
while (cont) {
n = fluid_istream_readline(shell->in, prompt ? prompt : "", workline, FLUID_WORKLINELENGTH);
n = fluid_istream_readline(shell->in, shell->out, prompt ? prompt : "", workline, FLUID_WORKLINELENGTH);
if (n < 0) {
break;

View file

@ -67,7 +67,7 @@ BOOL CALLBACK
fluid_dsound_enum_callback(LPGUID guid, LPCTSTR description, LPCTSTR module, LPVOID context)
{
fluid_settings_t* settings = (fluid_settings_t*) context;
fluid_settings_add_option(settings, "audio.dsound.device", (char *)description);
fluid_settings_add_option(settings, "audio.dsound.device", (const char *)description);
return TRUE;
}
@ -320,7 +320,6 @@ DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter)
fluid_dsound_audio_driver_t* dev = (fluid_dsound_audio_driver_t*) lpParameter;
short *buf1, *buf2;
DWORD bytes1, bytes2;
DWORD offset = 0;
DWORD cur_position, frames, play_position, write_position, bytes;
HRESULT res;

View file

@ -23,10 +23,8 @@
#include "fluid_synth.h"
#include "fluid_settings.h"
/* all outgoing user messages are stored in a global text buffer */
#define MIDI_MESSAGE_LENGTH 1024
char midi_message_buffer[MIDI_MESSAGE_LENGTH];
static int fluid_midi_event_length(unsigned char event);
/***************************************************************
@ -348,6 +346,7 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track)
int channel = 0;
int param1 = 0;
int param2 = 0;
int size;
/* read the delta-time of the event */
if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
@ -405,9 +404,13 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track)
}
evt->dtime = mf->dtime;
evt->type = MIDI_SYSEX;
evt->paramptr = metadata;
evt->param1 = metadata[mf->varlen - 1] == MIDI_EOX ? mf->varlen - 1 : mf->varlen;
size = mf->varlen;
if (metadata[mf->varlen - 1] == MIDI_EOX)
size--;
/* Add SYSEX event and indicate that its dynamically allocated and should be freed with event */
fluid_midi_event_set_sysex (evt, metadata, size, TRUE);
fluid_track_add_event (track, evt);
mf->dtime = 0;
}
@ -683,7 +686,8 @@ int delete_fluid_midi_event(fluid_midi_event_t* evt)
{
temp = evt->next;
if (evt->type == MIDI_SYSEX && evt->paramptr)
/* Dynamic SYSEX event? - free (param2 indicates if dynamic) */
if (evt->type == MIDI_SYSEX && evt->paramptr && evt->param2)
FLUID_FREE (evt->paramptr);
FLUID_FREE(evt);
@ -862,7 +866,7 @@ int fluid_midi_event_get_pitch(fluid_midi_event_t* evt)
* Set the pitch field of a MIDI event structure.
* @param evt MIDI event structure
* @param val Pitch value (DOCME units?)
* @return Always returns 0
* @return Always returns FLUID_OK
*/
int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val)
{
@ -870,6 +874,28 @@ int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val)
return FLUID_OK;
}
/**
* Assign sysex data to a MIDI event structure.
* @param evt MIDI event structure
* @param data Pointer to SYSEX data
* @param size Size of SYSEX data
* @param dynamic TRUE if the SYSEX data has been dynamically allocated and
* should be freed when the event is freed (only applies if event gets destroyed
* with delete_fluid_midi_event())
* @return Always returns FLUID_OK
*
* NOTE: Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *data, int size, int dynamic)
{
evt->type = MIDI_SYSEX;
evt->paramptr = data;
evt->param1 = size;
evt->param2 = dynamic;
return FLUID_OK;
}
/******************************************************
*
* fluid_track_t
@ -1493,129 +1519,118 @@ int delete_fluid_midi_parser(fluid_midi_parser_t* parser)
return FLUID_OK;
}
/*
* fluid_midi_parser_parse
*
* Purpose:
* The MIDI byte stream is fed into the parser, one byte at a time.
* As soon as the parser has recognized an event, it will return it.
* Otherwise it returns NULL.
/**
* Parse a MIDI stream one character at a time.
* @param parser Parser instance
* @param c Next character in MIDI stream
* @return A parsed MIDI event or NULL if none. Event is internal and should
* not be modified or freed and is only valid until next call to this function.
*/
fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c)
fluid_midi_event_t *
fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c)
{
/*********************************************************************/
/* 'Process' system real-time messages */
/*********************************************************************/
/* There are not too many real-time messages that are of interest here.
* They can occur anywhere, even in the middle of a noteon message!
* Real-time range: 0xF8 .. 0xFF
* Note: Real-time does not affect (running) status.
*/
if (c >= 0xF8){
if (c == MIDI_SYSTEM_RESET){
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
};
return NULL;
};
fluid_midi_event_t *event;
/*********************************************************************/
/* 'Process' system common messages (again, just skip them) */
/*********************************************************************/
/* There are no system common messages that are of interest here.
* System common range: 0xF0 .. 0xF7
*/
/* Real-time messages (0xF8-0xFF) can occur anywhere, even in the middle
* of another message. */
if (c >= 0xF8)
{
if (c == MIDI_SYSTEM_RESET)
{
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
}
if (c > 0xF0){
/* MIDI specs say: To ignore a non-real-time message, just discard all data up to
* the next status byte.
* And our parser will ignore data that is received without a valid status.
* Note: system common cancels running status. */
parser->status = 0;
return NULL;
};
return NULL;
}
/*********************************************************************/
/* Process voice category messages: */
/*********************************************************************/
/* Now that we have handled realtime and system common messages, only
* voice messages are left.
* Only a status byte has bit # 7 set.
* So no matter the status of the parser (in case we have lost sync),
* as soon as a byte >= 0x80 comes in, we are dealing with a status byte
* and start a new event.
*/
/* Status byte? - If previous message not yet complete, it is discarded (re-sync). */
if (c & 0x80)
{
/* Any status byte terminates SYSEX messages (not just 0xF7) */
if (parser->status == MIDI_SYSEX && parser->nr_bytes > 0)
{
event = &parser->event;
fluid_midi_event_set_sysex (event, parser->data, parser->nr_bytes, FALSE);
}
else event = NULL;
if (c & 0x80){
parser->channel = c & 0x0F;
parser->status = c & 0xF0;
/* The event consumes x bytes of data... (subtract 1 for the status byte) */
parser->nr_bytes_total=fluid_midi_event_length(parser->status)-1;
/* of which we have read 0 at this time. */
parser->nr_bytes = 0;
return NULL;
};
if (c < 0xF0) /* Voice category message? */
{
parser->channel = c & 0x0F;
parser->status = c & 0xF0;
/*********************************************************************/
/* Process data */
/*********************************************************************/
/* If we made it this far, then the received char belongs to the data
* of the last event. */
if (parser->status == 0){
/* We are not interested in the event currently received.
* Discard the data. */
return NULL;
};
/* The event consumes x bytes of data... (subtract 1 for the status byte) */
parser->nr_bytes_total = fluid_midi_event_length (parser->status) - 1;
/* Store the first couple of bytes */
if (parser->nr_bytes < FLUID_MIDI_PARSER_MAX_PAR){
parser->p[parser->nr_bytes]=c;
};
parser->nr_bytes++;
parser->nr_bytes = 0; /* 0 bytes read so far */
}
else if (c == MIDI_SYSEX)
{
parser->status = MIDI_SYSEX;
parser->nr_bytes = 0;
}
else parser->status = 0; /* Discard other system messages (0xF1-0xF7) */
/* Do we still need more data to get this event complete? */
if (parser->nr_bytes < parser->nr_bytes_total){
return NULL;
};
return event; /* Return SYSEX event or NULL */
}
/*********************************************************************/
/* Send the event */
/*********************************************************************/
/* The event is ready-to-go.
* About 'running status':
* The MIDI protocol has a built-in compression mechanism. If several similar events are sent
* in-a-row, for example note-ons, then the event type is only sent once. For this case,
* the last event type (status) is remembered.
* We simply keep the status as it is, just reset
* the parameter counter. If another status byte comes in, it will overwrite the status. */
parser->event.type = parser->status;
parser->event.channel = parser->channel;
parser->nr_bytes = 0; /* Related to running status! */
switch (parser->status){
case NOTE_OFF:
case NOTE_ON:
case KEY_PRESSURE:
case CONTROL_CHANGE:
case PROGRAM_CHANGE:
case CHANNEL_PRESSURE:
parser->event.param1 = parser->p[0]; /* For example key number */
parser->event.param2 = parser->p[1]; /* For example velocity */
break;
case PITCH_BEND:
/* Pitch-bend is transmitted with 14-bit precision. */
parser->event.param1 = ((parser->p[1] << 7) | parser->p[0]); /* Note: '|' does here the same as '+' (no common bits), but might be faster */
break;
default:
/* Unlikely */
return NULL;
};
return &parser->event;
};
/* Data/parameter byte */
/* Discard data bytes for events we don't care about */
if (parser->status == 0)
return NULL;
/* Max data size exceeded? (SYSEX messages only really) */
if (parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE)
{
parser->status = 0; /* Discard the rest of the message */
return NULL;
}
/* Store next byte */
parser->data[parser->nr_bytes++] = c;
/* Do we still need more data to get this event complete? */
if (parser->nr_bytes < parser->nr_bytes_total)
return NULL;
/* Event is complete, return it.
* Running status byte MIDI feature is also handled here. */
parser->event.type = parser->status;
parser->event.channel = parser->channel;
parser->nr_bytes = 0; /* Reset data size, in case there are additional running status messages */
switch (parser->status)
{
case NOTE_OFF:
case NOTE_ON:
case KEY_PRESSURE:
case CONTROL_CHANGE:
case PROGRAM_CHANGE:
case CHANNEL_PRESSURE:
parser->event.param1 = parser->data[0]; /* For example key number */
parser->event.param2 = parser->data[1]; /* For example velocity */
break;
case PITCH_BEND:
/* Pitch-bend is transmitted with 14-bit precision. */
parser->event.param1 = (parser->data[1] << 7) | parser->data[0];
break;
default: /* Unlikely */
return NULL;
}
return &parser->event;
}
/* Purpose:
* Returns the length of the MIDI message. */
int fluid_midi_event_length(unsigned char event){
* Returns the length of a MIDI message. */
static int
fluid_midi_event_length(unsigned char event)
{
switch (event & 0xF0) {
case NOTE_OFF:
case NOTE_ON:
@ -1628,8 +1643,6 @@ int fluid_midi_event_length(unsigned char event){
return 2;
}
switch (event) {
case MIDI_SYSEX:
return 0;
case MIDI_TIME_CODE:
case MIDI_SONG_SELECT:
case 0xF4:
@ -1637,7 +1650,7 @@ int fluid_midi_event_length(unsigned char event){
return 2;
case MIDI_TUNE_REQUEST:
return 1;
case MIDI_SONG_POSITION:
case MIDI_SONG_POSITION:
return 3;
}
return 1;

View file

@ -224,7 +224,7 @@ enum fluid_driver_status
*/
struct _fluid_midi_event_t {
fluid_midi_event_t* next; /* Link to next event */
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1 */
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
unsigned int param1; /* First parameter */
unsigned int param2; /* Second parameter */
@ -339,10 +339,9 @@ int fluid_midi_file_skip(fluid_midi_file* mf, int len);
int fluid_midi_file_read_tracklen(fluid_midi_file* mf);
int fluid_midi_file_eot(fluid_midi_file* mf);
int fluid_midi_file_get_division(fluid_midi_file* midifile);
int fluid_midi_event_length(unsigned char status);
/* How many parameters may a MIDI event have? */
#define FLUID_MIDI_PARSER_MAX_PAR 3
#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */
/*
* fluid_midi_parser_t
@ -352,7 +351,7 @@ struct _fluid_midi_parser_t {
unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
unsigned int nr_bytes; /* How many bytes have been read for the current event? */
unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
unsigned short p[FLUID_MIDI_PARSER_MAX_PAR]; /* The parameters */
unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
};

View file

@ -295,7 +295,7 @@ fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event)
/* Lock the rules table, so that for example the shell thread doesn't
* clear the rules we are just working with */
fluid_mutex_lock(router->ruletables_mutex);
fluid_mutex_lock(router->ruletables_mutex); /* ++ lock rules */
/* Depending on the event type, choose the correct table of rules.
* Also invoke the appropriate callback function for the event type
@ -331,7 +331,10 @@ fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event)
event_has_par2=1;
break;
case MIDI_SYSTEM_RESET:
return router->event_handler(router->event_handler_data,event);
case MIDI_SYSEX:
ret_val = router->event_handler (router->event_handler_data,event);
fluid_mutex_unlock (router->ruletables_mutex); /* -- unlock rules */
return ret_val;
default:
break;
}
@ -515,7 +518,7 @@ fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event)
};
/* We are finished with the rule tables. Allow the other threads to do their job. */
fluid_mutex_unlock(router->ruletables_mutex);
fluid_mutex_unlock(router->ruletables_mutex); /* -- unlock rules */
return ret_val;
}

View file

@ -61,6 +61,7 @@ typedef struct {
UPPTaskPtr upp_task_ptr;
#endif
SlotRefNum slotRef;
unsigned char sysexbuf[FLUID_MIDI_PARSER_MAX_DATA_SIZE];
} fluid_midishare_midi_driver_t;
@ -72,10 +73,14 @@ int delete_fluid_midishare_midi_driver(fluid_midi_driver_t* p);
int fluid_midishare_midi_driver_status(fluid_midi_driver_t* p);
static void fluid_midishare_midi_driver_receive(short ref);
static int fluid_midishare_open_appl (fluid_midishare_midi_driver_t* dev);
#if defined(MIDISHARE_DRIVER)
static int fluid_midishare_open_driver (fluid_midishare_midi_driver_t* dev);
static void fluid_midishare_close_driver (fluid_midishare_midi_driver_t* dev);
#else
static int fluid_midishare_open_appl (fluid_midishare_midi_driver_t* dev);
static void fluid_midishare_close_appl (fluid_midishare_midi_driver_t* dev);
#endif
/*
* new_fluid_midishare_midi_driver
@ -135,6 +140,7 @@ new_fluid_midishare_midi_driver(fluid_settings_t* settings,
MidiAcceptType(dev->filter, typeCtrlChange, 1);
MidiAcceptType(dev->filter, typeProgChange, 1);
MidiAcceptType(dev->filter, typePitchWheel, 1);
MidiAcceptType(dev->filter, typeSysEx, 1);
/* set the filter */
MidiSetFilter(dev->refnum, dev->filter);
@ -217,104 +223,110 @@ static void fluid_midishare_keyoff_task (long date, short ref, long a1, long a2,
*/
static void fluid_midishare_midi_driver_receive(short ref)
{
fluid_midishare_midi_driver_t* dev = (fluid_midishare_midi_driver_t*)MidiGetInfo(ref);
fluid_midi_event_t new_event;
MidiEvPtr e;
fluid_midishare_midi_driver_t* dev = (fluid_midishare_midi_driver_t*)MidiGetInfo(ref);
fluid_midi_event_t new_event;
MidiEvPtr e;
int count, i;
while ((e = MidiGetEv(ref))){
while ((e = MidiGetEv (ref)))
{
switch (EvType (e))
{
case typeNote:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_ON);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e));
switch (EvType (e)){
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
case typeNote:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_ON);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e));
#if defined(MACINTOSH) && defined(MACOS9)
MidiTask(dev->upp_task_ptr, MidiGetTime()+Dur(e), ref, (long)e, 0, 0);
#else
MidiTask(fluid_midishare_keyoff_task, MidiGetTime()+Dur(e), ref, (long)e, 0, 0);
#endif
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
/* e gets freed in fluid_midishare_keyoff_task */
continue;
#if defined(MACINTOSH) && defined(MACOS9)
MidiTask(dev->upp_task_ptr, MidiGetTime()+Dur(e), ref, (long)e, 0, 0);
#else
MidiTask(fluid_midishare_keyoff_task, MidiGetTime()+Dur(e), ref, (long)e, 0, 0);
#endif
break;
case typeKeyOn:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_ON);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e));
break;
case typeKeyOn:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_ON);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e));
case typeKeyOff:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_OFF);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e)); /* release vel */
break;
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
case typeCtrlChange:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, CONTROL_CHANGE);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_control(&new_event, MidiGetField(e,0));
fluid_midi_event_set_value(&new_event, MidiGetField(e,1));
break;
MidiFreeEv(e);
break;
case typeProgChange:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, PROGRAM_CHANGE);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_program(&new_event, MidiGetField(e,0));
break;
case typeKeyOff:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, NOTE_OFF);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_pitch(&new_event, Pitch(e));
fluid_midi_event_set_velocity(&new_event, Vel(e)); /* release vel */
case typePitchWheel:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, PITCH_BEND);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_value(&new_event, ((MidiGetField(e,0)
+ (MidiGetField(e,1) << 7))
- 8192));
break;
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
case typeSysEx:
count = MidiCountFields (e);
MidiFreeEv(e);
break;
/* Discard empty or too large SYSEX messages */
if (count == 0 || count > FLUID_MIDI_PARSER_MAX_DATA_SIZE)
{
MidiFreeEv (e);
continue;
}
case typeCtrlChange:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, CONTROL_CHANGE);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_control(&new_event, MidiGetField(e,0));
fluid_midi_event_set_value(&new_event, MidiGetField(e,1));
/* Copy SYSEX data, one byte at a time */
for (i = 0; i < count; i++)
dev->sysexbuf[i] = MidiGetField (e, i);
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
fluid_midi_event_set_sysex (&new_event, dev->sysexbuf, count, FALSE);
break;
MidiFreeEv(e);
break;
default:
MidiFreeEv (e);
continue;
}
case typeProgChange:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, PROGRAM_CHANGE);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_program(&new_event, MidiGetField(e,0));
MidiFreeEv (e);
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
MidiFreeEv(e);
break;
case typePitchWheel:
/* Copy the data to fluid_midi_event_t */
fluid_midi_event_set_type(&new_event, PITCH_BEND);
fluid_midi_event_set_channel(&new_event, Chan(e));
fluid_midi_event_set_value(&new_event, ((MidiGetField(e,0)
+ (MidiGetField(e,1) << 7))
- 8192));
/* and send it on its way to the router */
(*dev->driver.handler)(dev->driver.data, &new_event);
MidiFreeEv(e);
break;
}
}
/* Send the MIDI event */
(*dev->driver.handler)(dev->driver.data, &new_event);
}
}
#if defined(MIDISHARE_DRIVER)
/*
* fluid_midishare_wakeup
*/
static void fluid_midishare_wakeup (short r)
static void fluid_midishare_wakeup (short r)
{
MidiConnect (MidiShareDrvRef, r, true);
MidiConnect (r, MidiShareDrvRef, true);
@ -323,7 +335,7 @@ static void fluid_midishare_midi_driver_receive(short ref)
/*
* fluid_midishare_sleep
*/
static void fluid_midishare_sleep (short r){}
static void fluid_midishare_sleep (short r){}
/*
* fluid_midishare_open_driver
@ -371,6 +383,8 @@ static void fluid_midishare_close_driver (fluid_midishare_midi_driver_t* dev)
if (dev->refnum > 0) MidiUnregisterDriver(dev->refnum);
}
#else /* #if defined(MIDISHARE_DRIVER) */
/*
* fluid_midishare_open_appl
*/
@ -406,4 +420,6 @@ static void fluid_midishare_close_appl (fluid_midishare_midi_driver_t* dev)
if (dev->refnum > 0) MidiClose(dev->refnum);
}
#endif /* #if defined(MIDISHARE_DRIVER) */
#endif /* MIDISHARE_SUPPORT */

View file

@ -1051,6 +1051,8 @@ delete_fluid_synth(fluid_synth_t* synth)
FLUID_FREE(synth->LADSPA_FxUnit);
#endif
fluid_private_free (synth->thread_queues);
/* free any queues in pool */
for (list = synth->queue_pool; list; list = list->next) {
queue = (fluid_event_queue_t *)(list->data);
@ -1065,7 +1067,6 @@ delete_fluid_synth(fluid_synth_t* synth)
if (synth->queues[i]) fluid_event_queue_free (synth->queues[i]);
delete_fluid_list (synth->queue_pool);
fluid_private_free (synth->thread_queues);
fluid_rec_mutex_destroy(synth->mutex);
@ -1713,7 +1714,7 @@ fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
fluid_return_val_if_fail (len > 0, FLUID_FAILED);
fluid_return_val_if_fail (!response || response_len, FLUID_FAILED);
if (len < 6) return FLUID_OK;
if (len < 4) return FLUID_OK;
/* MIDI tuning SYSEX message? */
if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
@ -1742,10 +1743,12 @@ fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
if (handled) *handled = FALSE;
break;
}
return FLUID_OK;
}
/* GS reset message? */
if (data[0] == MIDI_SYSEX_MANUF_ROLAND
if (len == 9 && data[0] == MIDI_SYSEX_MANUF_ROLAND
&& data[1] == 0x10 && data[2] == 0x42 && data[3] == 0x12 && data[4] == 0x40
&& data[5] == 0x00 && data[6] == 0x7F && data[7] == 0x00 && data[8] == 0x41)
{
@ -1753,6 +1756,8 @@ fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
fluid_synth_setstr (synth, "synth.midi-mode", "gs");
if (handled) *handled = FALSE;
return FLUID_OK;
}
return FLUID_OK;
@ -3874,7 +3879,7 @@ new_fluid_sfont_info (fluid_synth_t *synth, fluid_sfont_t *sfont)
int
fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets)
{
fluid_sfont_info_t *sfont_info;
fluid_sfont_info_t *sfont_info = NULL;
fluid_list_t *list;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
@ -5792,7 +5797,7 @@ fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id)
{
fluid_sfont_info_t *sfont_info;
fluid_list_t *list;
int offset;
int offset = 0;
fluid_return_val_if_fail (synth != NULL, 0);

View file

@ -26,6 +26,9 @@
#include <readline/history.h>
#endif
/* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
* Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
#define WIN32_SOCKET_FLAG 0x40000000
struct _fluid_server_socket_t
{
@ -388,7 +391,6 @@ struct _fluid_timer_t
int auto_destroy;
};
static int fluid_timer_count = 0;
DWORD WINAPI fluid_timer_run(LPVOID data);
fluid_timer_t*
@ -470,9 +472,13 @@ fluid_timer_run(LPVOID data)
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
FLUID_FREE(timer);
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
@ -518,7 +524,6 @@ struct _fluid_timer_t
int auto_destroy;
};
static int fluid_timer_count = 0;
void fluid_timer_run(void *data);
fluid_timer_t*
@ -599,9 +604,13 @@ fluid_timer_run(void *data)
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
FLUID_FREE(timer);
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
@ -748,10 +757,14 @@ new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
FLUID_LOG(FLUID_DBG, "Joined player thread");
FLUID_FREE(timer);
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
@ -1009,7 +1022,8 @@ fluid_get_stdout (void)
* @return 0 if end-of-stream, -1 if error, non zero otherwise
*/
int
fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len)
fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
char* buf, int len)
{
#if WITH_READLINE
if (in == fluid_get_stdin ())
@ -1028,10 +1042,11 @@ fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len)
return 1;
}
else
return fluid_istream_gets(in, buf, len);
#else
return fluid_istream_gets(in, buf, len);
#endif
{
fluid_ostream_printf (out, "%s", prompt);
return fluid_istream_gets (in, buf, len);
}
}
/**
@ -1051,8 +1066,22 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len)
while (--len > 0)
{
#ifndef WIN32
n = read(in, &c, 1);
if (n == -1) return -1;
#else
/* Handle read differently depending on if its a socket or file descriptor */
if (!(in & WIN32_SOCKET_FLAG))
{
n = read(in, &c, 1);
if (n == -1) return -1;
}
else
{
n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
if (n == SOCKET_ERROR) return -1;
}
#endif
if (n == 0)
{
@ -1060,13 +1089,14 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len)
return 0;
}
if ((c == '\n') || (c == '\r'))
if ((c == '\n'))
{
*buf++ = 0;
return 1;
}
*buf++ = c;
/* Store all characters excluding CR */
if (c != '\r') *buf++ = c;
}
return -1;
@ -1104,23 +1134,18 @@ fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
{
int retval;
retval = send (out, buf, strlen (buf), 0);
/* Handle write differently depending on if its a socket or file descriptor */
if (!(out & WIN32_SOCKET_FLAG))
return write(out, buf, strlen (buf));
/* Socket */
retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
return retval != SOCKET_ERROR ? retval : -1;
}
#endif
}
fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
{
return sock;
}
fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
{
return sock;
}
int fluid_server_socket_join(fluid_server_socket_t *server_socket)
{
return fluid_thread_join (server_socket->thread);
@ -1131,6 +1156,16 @@ int fluid_server_socket_join(fluid_server_socket_t *server_socket)
#define SOCKET_ERROR -1
fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
{
return sock;
}
fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
{
return sock;
}
void fluid_socket_close(fluid_socket_t sock)
{
if (sock != INVALID_SOCKET)
@ -1252,6 +1287,16 @@ int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
#include <winsock2.h>
#include <ws2tcpip.h>
fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
{
return sock | WIN32_SOCKET_FLAG;
}
fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
{
return sock | WIN32_SOCKET_FLAG;
}
void fluid_socket_close (fluid_socket_t sock)
{
if (sock != INVALID_SOCKET)
@ -1270,7 +1315,7 @@ static void fluid_server_socket_run (void *data)
while (server_socket->cont)
{
client_socket = accept (server_socket->socket, &addr, &addrlen);
client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
FLUID_LOG (FLUID_DBG, "New client connection");
@ -1301,7 +1346,6 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
struct sockaddr_in addr;
fluid_socket_t sock;
WSADATA wsaData;
struct addrinfo *result = NULL, *ptr = NULL, hints;
int retval;
g_return_val_if_fail (func != NULL, NULL);
@ -1315,45 +1359,29 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
return NULL;
}
ZeroMemory (&hints, sizeof (hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
retval = getaddrinfo (NULL, port, &hints, &result); // ++ alloc 'result'
if (retval != 0)
{
FLUID_LOG(FLUID_ERR, "Server socket creation error: getaddrinfo failed: %d", retval);
WSACleanup ();
return NULL;
}
sock = socket (result->ai_family, result->ai_socktype, result->ai_protocol);
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
freeaddrinfo (result); // -- free result
WSACleanup ();
return NULL;
}
retval = bind (sock, result->ai_addr, (int)result->ai_addrlen);
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = htonl (INADDR_ANY);
retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
if (retval == SOCKET_ERROR)
{
FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
freeaddrinfo (result); // -- free result
fluid_socket_close (sock);
WSACleanup ();
return NULL;
}
freeaddrinfo (result); // -- free result
if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
{
FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
@ -1377,8 +1405,8 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
server_socket->data = data;
server_socket->cont = 1;
server_socket->thread = new_fluid_thread (fluid_server_socket_run, server_socket, FALSE);
server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
if (server_socket->thread == NULL)
{
FLUID_FREE (server_socket);

View file

@ -231,7 +231,7 @@ int fluid_thread_join(fluid_thread_t* thread);
fluid_istream_t fluid_get_stdin (void);
fluid_ostream_t fluid_get_stdout (void);
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len);
int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char* prompt, char* buf, int len);
int fluid_ostream_printf (fluid_ostream_t out, char* format, ...);
/* The function should return 0 if no error occured, non-zero

View file

@ -21,7 +21,13 @@
/* fluid_winmidi.c
*
* Drivers for Windows MIDI
* Driver for Windows MIDI
*
* NOTE: Unfortunately midiInAddBuffer(), for SYSEX data, should not be called
* from within the MIDI input callback, despite many examples contrary to that
* on the Internet. Some MIDI devices will deadlock. Therefore we add MIDIHDR
* pointers to a queue and re-add them in a separate thread, using a mutex and
* conditional to wake up the thread. Lame-o API! :(
*/
#include "fluidsynth_priv.h"
@ -33,11 +39,28 @@
#include "fluid_settings.h"
#include <windows.h>
#define BUFFER_LENGTH 512
#define MIDI_SYSEX_MAX_SIZE 512
#define MIDI_SYSEX_BUF_COUNT 16
typedef struct {
fluid_midi_driver_t driver;
HMIDIIN hmidiin;
int closing; /* Set to TRUE when closing driver, to prevent endless SYSEX lockup loop */
fluid_thread_t *sysExAddThread; /* Thread for SYSEX re-add thread */
fluid_cond_mutex_t *mutex; /* Lock for condition */
fluid_cond_t *cond; /* Condition to signal MIDI event thread of available events */
/* MIDI HDR for SYSEX buffer */
MIDIHDR sysExHdrs[MIDI_SYSEX_BUF_COUNT];
/* TRUE for each MIDIHDR buffer which should be re-added to MIDI device */
int sysExHdrAdd[MIDI_SYSEX_BUF_COUNT];
/* Sysex data buffer */
unsigned char sysExBuf[MIDI_SYSEX_BUF_COUNT * MIDI_SYSEX_MAX_SIZE];
int sysExOffset; /* Current offset in sysex buffer (for message continuation) */
} fluid_winmidi_driver_t;
static char fluid_winmidi_error_buffer[256];
@ -54,9 +77,11 @@ int delete_fluid_winmidi_driver(fluid_midi_driver_t* p);
void CALLBACK fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance,
DWORD msg, DWORD extra);
static void fluid_winmidi_add_sysex_thread (void *data);
static char* fluid_winmidi_input_error(int no);
int fluid_winmidi_driver_status(fluid_midi_driver_t* p);
void fluid_winmidi_midi_driver_settings(fluid_settings_t* settings)
{
MMRESULT res;
@ -83,10 +108,10 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler, void* data)
{
fluid_winmidi_driver_t* dev;
MIDIHDR *hdr;
MMRESULT res;
UINT i, err, num;
UINT i, err, num, midi_num = 0;
MIDIINCAPS in_caps;
int midi_num = 0;
char* devname = NULL;
/* not much use doing anything */
@ -100,13 +125,16 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
return NULL;
}
memset (dev, 0, sizeof (fluid_winmidi_driver_t));
dev->hmidiin = NULL;
dev->driver.handler = handler;
dev->driver.data = data;
dev->closing = FALSE;
/* get the device name. if none is specified, use the default device. */
if(!fluid_settings_getstr(settings, "midi.winmidi.device", &devname) || !devname) {
devname = FLUID_DUPSTR ("default");
if(!fluid_settings_dupstr(settings, "midi.winmidi.device", &devname) || !devname) {
devname = FLUID_STRDUP ("default");
if (!devname)
{
@ -146,16 +174,63 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
(DWORD) fluid_winmidi_callback,
(DWORD) dev, CALLBACK_FUNCTION);
if (err != MMSYSERR_NOERROR) {
FLUID_LOG(FLUID_WARN, "Couldn't open MIDI input: %s (error %d)",
FLUID_LOG(FLUID_ERR, "Couldn't open MIDI input: %s (error %d)",
fluid_winmidi_input_error(err), err);
goto error_recovery;
}
/* Prepare and add SYSEX buffers */
for (i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
{
dev->sysExHdrAdd[i] = FALSE;
hdr = &dev->sysExHdrs[i];
hdr->lpData = &dev->sysExBuf[i * MIDI_SYSEX_MAX_SIZE];
hdr->dwBufferLength = MIDI_SYSEX_MAX_SIZE;
/* Prepare a buffer for SYSEX data and add it */
err = midiInPrepareHeader (dev->hmidiin, hdr, sizeof (MIDIHDR));
if (err == MMSYSERR_NOERROR)
{
err = midiInAddBuffer (dev->hmidiin, hdr, sizeof (MIDIHDR));
if (err != MMSYSERR_NOERROR)
{
FLUID_LOG (FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
fluid_winmidi_input_error (err), err);
midiInUnprepareHeader (dev->hmidiin, hdr, sizeof (MIDIHDR));
}
}
else FLUID_LOG (FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
fluid_winmidi_input_error (err), err);
}
/* Start the MIDI input interface */
if (midiInStart(dev->hmidiin) != MMSYSERR_NOERROR) {
FLUID_LOG(FLUID_ERR, "Failed to start the MIDI input. MIDI input not available.");
goto error_recovery;
}
/* Create mutex and condition */
dev->mutex = new_fluid_cond_mutex ();
dev->cond = new_fluid_cond ();
if (!dev->mutex || !dev->cond)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
/* Create thread which processes re-adding SYSEX buffers */
dev->sysExAddThread = new_fluid_thread (fluid_winmidi_add_sysex_thread,
dev, FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
if (!dev->sysExAddThread)
{
FLUID_LOG(FLUID_ERR, "Failed to create SYSEX buffer processing thread");
goto error_recovery;
}
if (devname) FLUID_FREE (devname); /* -- free device name */
return (fluid_midi_driver_t*) dev;
@ -174,18 +249,38 @@ delete_fluid_winmidi_driver(fluid_midi_driver_t* p)
{
fluid_winmidi_driver_t* dev = (fluid_winmidi_driver_t*) p;
if (dev->hmidiin != NULL) {
fluid_atomic_int_set (&dev->closing, TRUE);
if (dev->sysExAddThread)
{
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_signal (dev->cond);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
fluid_thread_join (dev->sysExAddThread);
}
midiInStop(dev->hmidiin);
midiInReset(dev->hmidiin);
midiInClose(dev->hmidiin);
}
if (dev->mutex) delete_fluid_cond_mutex (dev->mutex);
if (dev->cond) delete_fluid_cond (dev->cond);
FLUID_FREE(dev);
return 0;
}
void CALLBACK
fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance, DWORD msg, DWORD extra)
fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance,
DWORD dwParam1, DWORD dwParam2)
{
fluid_winmidi_driver_t* dev = (fluid_winmidi_driver_t *) dwInstance;
fluid_midi_event_t event;
LPMIDIHDR pMidiHdr;
unsigned char *data;
int index;
switch (wMsg) {
case MIM_OPEN:
@ -195,22 +290,41 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance, DWORD msg, DWOR
break;
case MIM_DATA:
{
fluid_midi_event_t event;
event.type = msg_type(dwParam1);
event.channel = msg_chan(dwParam1);
event.type = msg_type(msg);
event.channel = msg_chan(msg);
event.param1 = msg_p1(msg);
event.param2 = msg_p2(msg);
if(event.type==PITCH_BEND){
event.param1 = ((event.param2 & 0x7f) << 7) | (event.param1 & 0x7f);
event.param2 = 0;
}
(*dev->driver.handler)(dev->driver.data, &event);
if (event.type != PITCH_BEND) {
event.param1 = msg_p1(dwParam1);
event.param2 = msg_p2(dwParam1);
} else { /* Pitch bend is a 14 bit value */
event.param1 = (msg_p2 (dwParam1) << 7) | msg_p1 (dwParam1);
event.param2 = 0;
}
(*dev->driver.handler)(dev->driver.data, &event);
break;
case MIM_LONGDATA:
case MIM_LONGDATA: /* SYSEX data */
if (dev->closing) break; /* Prevent MIM_LONGDATA endless loop, don't re-add buffer if closing */
pMidiHdr = (LPMIDIHDR)dwParam1;
data = (unsigned char *)(pMidiHdr->lpData);
/* We only process complete SYSEX messages (discard those that are too small or too large) */
if (pMidiHdr->dwBytesRecorded > 2 && data[0] == 0xF0
&& data[pMidiHdr->dwBytesRecorded - 1] == 0xF7)
{
fluid_midi_event_set_sysex (&event, pMidiHdr->lpData + 1,
pMidiHdr->dwBytesRecorded - 2, FALSE);
(*dev->driver.handler)(dev->driver.data, &event);
}
index = (pMidiHdr - dev->sysExHdrs) / sizeof (MIDIHDR);
fluid_atomic_int_set (&dev->sysExHdrAdd[index], TRUE);
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_signal (dev->cond);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
break;
case MIM_ERROR:
@ -224,6 +338,30 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance, DWORD msg, DWOR
}
}
/* Thread for re-adding SYSEX buffers */
static void
fluid_winmidi_add_sysex_thread (void *data)
{
fluid_winmidi_driver_t *dev = data;
int i;
while (!fluid_atomic_int_get (&dev->closing))
{
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_wait (dev->cond, dev->mutex);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
for (i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
{
if (fluid_atomic_int_get (&dev->sysExHdrAdd[i]))
{
fluid_atomic_int_set (&dev->sysExHdrAdd[i], FALSE);
midiInAddBuffer (dev->hmidiin, &dev->sysExHdrs[i], sizeof (MIDIHDR));
}
}
}
}
int
fluid_winmidi_driver_status(fluid_midi_driver_t* p)
{

View file

@ -129,11 +129,23 @@ print_pretty_int (int i)
else printf ("%d", i);
}
typedef struct
{
int count; /* Total count of options */
int curindex; /* Current index in options */
} OptionBag;
/* Function to display each string option value */
static void
settings_option_foreach_func (void *data, char *name, char *option)
{
printf (" %s", option);
OptionBag *bag = data;
bag->curindex++;
if (bag->curindex < bag->count)
printf ("'%s',", option);
else printf ("'%s'", option);
}
/* fluid_settings_foreach function for displaying option help "-o help" */
@ -145,6 +157,7 @@ settings_foreach_func (void *data, char *name, int type)
int imin, imax, idef;
char *defstr;
int count;
OptionBag bag;
switch (type)
{
@ -178,8 +191,13 @@ settings_foreach_func (void *data, char *name, int type)
else printf (" [vals:");
if (count > 0)
fluid_settings_foreach_option_alpha (settings, name, NULL,
{
bag.count = count;
bag.curindex = 0;
fluid_settings_foreach_option_alpha (settings, name, &bag,
settings_option_foreach_func);
}
printf ("]\n");
}
else printf ("\n");
@ -655,7 +673,7 @@ int main(int argc, char** argv)
}
/* run the server, if requested */
#if !defined(MACINTOSH) && !defined(WIN32)
#if !defined(MACINTOSH)
if (with_server) {
server = new_fluid_server(settings, newclient, synth);
if (server == NULL) {

View file

@ -128,7 +128,6 @@
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define WITHOUT_SERVER 1
#endif