mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-22 07:30:50 +00:00
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:
parent
1b425d9e12
commit
3bc6d961a6
16 changed files with 529 additions and 296 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -128,7 +128,6 @@
|
|||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
#define WITHOUT_SERVER 1
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue