mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
Make winmidi driver multi devices capable. (#677)
This commit is contained in:
parent
83394ab286
commit
b55884b273
2 changed files with 348 additions and 108 deletions
|
@ -683,7 +683,7 @@ Developers: Settings can be deprecated by adding: <deprecated>SOME TEXT</depreca
|
|||
<name>winmidi.device</name>
|
||||
<type>str</type>
|
||||
<def>default</def>
|
||||
<desc>The hardware device to use for Windows MIDI driver (not to be confused with the MIDI port).</desc>
|
||||
<desc>The hardware device to use for Windows MIDI driver (not to be confused with the MIDI port). Multiple devices can be specified by a list of devices index separated by a semicolon (e.g "2;0", which is equivalent to one device with 32 MIDI channels).</desc>
|
||||
</setting>
|
||||
</midi>
|
||||
|
||||
|
|
|
@ -27,6 +27,36 @@
|
|||
* 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. Lame-o API! :(
|
||||
*
|
||||
* Multiple/single devices handling capabilities:
|
||||
* This driver is able to handle multiple devices chosen by the user trough
|
||||
* the settings midi.winmidi.device.
|
||||
* For example, let the following device names:
|
||||
* 0:Port MIDI SB Live! [CE00], 1:SB PCI External MIDI, default, x[;y;z;..]
|
||||
* Then the driver is able receive MIDI messages comming from distinct devices
|
||||
* and forward these messages on distinct MIDI channels set.
|
||||
* 1.1)For example, if the user chooses 2 devices at index 0 and 1, the user
|
||||
* must specify this by putting the name "0;1" in midi.winmidi.device setting.
|
||||
* We get a fictif device composed of real devices (0,1). This fictif device
|
||||
* behaves like a device with 32 MIDI channels whose messages are forwarded to
|
||||
* driver output as this:
|
||||
* - MIDI messages from real device 0 are output to MIDI channels set 0 to 15.
|
||||
* - MIDI messages from real device 1 are output to MIDI channels set 15 to 31.
|
||||
*
|
||||
* 1.2)Now another example with the name "1;0". The driver will forward
|
||||
* MIDI messages as this:
|
||||
* - MIDI messages from real device 1 are output to MIDI channels set 0 to 15.
|
||||
* - MIDI messages from real device 0 are output to MIDI channels set 15 to 31.
|
||||
* So, the device order specified in the setting allows the user to choose the
|
||||
* MIDI channel set associated with this real device at the driver output
|
||||
* according this formula: output_channel = input_channel + device_order * 16.
|
||||
*
|
||||
* 2)Note also that the driver handles single device by putting the device name
|
||||
* in midi.winmidi.device setting.
|
||||
* The user can set the device name "0:Port MIDI SB Live! [CE00]" in the setting.
|
||||
* or use the multi device naming "0" (specifying only device index 0).
|
||||
* Both naming choice allows the driver to handle the same single device.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
@ -40,22 +70,35 @@
|
|||
#define MIDI_SYSEX_MAX_SIZE 512
|
||||
#define MIDI_SYSEX_BUF_COUNT 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fluid_midi_driver_t driver;
|
||||
HMIDIIN hmidiin;
|
||||
typedef struct fluid_winmidi_driver fluid_winmidi_driver_t;
|
||||
|
||||
/* device infos structure for only one midi device */
|
||||
typedef struct device_infos
|
||||
{
|
||||
fluid_winmidi_driver_t *dev; /* driver structure*/
|
||||
unsigned char midi_num; /* device order number */
|
||||
unsigned char channel_map; /* MIDI channel mapping from input to output */
|
||||
UINT dev_idx; /* device index */
|
||||
HMIDIIN hmidiin; /* device handle */
|
||||
/* MIDI HDR for SYSEX buffer */
|
||||
MIDIHDR sysExHdrs[MIDI_SYSEX_BUF_COUNT];
|
||||
/* Sysex data buffer */
|
||||
unsigned char sysExBuf[MIDI_SYSEX_BUF_COUNT * MIDI_SYSEX_MAX_SIZE];
|
||||
} device_infos_t;
|
||||
|
||||
/* driver structure */
|
||||
struct fluid_winmidi_driver
|
||||
{
|
||||
fluid_midi_driver_t driver;
|
||||
|
||||
/* Thread for SYSEX re-add thread */
|
||||
HANDLE hThread;
|
||||
DWORD dwThread;
|
||||
|
||||
/* Sysex data buffer */
|
||||
unsigned char sysExBuf[MIDI_SYSEX_BUF_COUNT * MIDI_SYSEX_MAX_SIZE];
|
||||
|
||||
} fluid_winmidi_driver_t;
|
||||
/* devices informations table */
|
||||
int dev_count; /* device informations count in dev_infos[] table */
|
||||
device_infos_t dev_infos[1];
|
||||
};
|
||||
|
||||
#define msg_type(_m) ((unsigned char)(_m & 0xf0))
|
||||
#define msg_chan(_m) ((unsigned char)(_m & 0x0f))
|
||||
|
@ -77,11 +120,17 @@ fluid_winmidi_input_error(char *strError, MMRESULT no)
|
|||
return strError;
|
||||
}
|
||||
|
||||
/*
|
||||
callback function called by any MIDI device sending a MIDI message.
|
||||
@param dwInstance, pointer on device_infos structure of this
|
||||
device.
|
||||
*/
|
||||
static void CALLBACK
|
||||
fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
|
||||
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
|
||||
{
|
||||
fluid_winmidi_driver_t *dev = (fluid_winmidi_driver_t *) dwInstance;
|
||||
device_infos_t *dev_infos = (device_infos_t *) dwInstance;
|
||||
fluid_winmidi_driver_t *dev = dev_infos->dev;
|
||||
fluid_midi_event_t event;
|
||||
LPMIDIHDR pMidiHdr;
|
||||
unsigned char *data;
|
||||
|
@ -97,7 +146,10 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
|
|||
|
||||
case MIM_DATA:
|
||||
event.type = msg_type(msg_param);
|
||||
event.channel = msg_chan(msg_param);
|
||||
event.channel = msg_chan(msg_param) + dev_infos->channel_map;
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "\ndevice at index %d sending MIDI message on channel %d, forwarded on channel: %d",
|
||||
dev_infos->dev_idx, msg_chan(msg_param), event.channel);
|
||||
|
||||
if(event.type != PITCH_BEND)
|
||||
{
|
||||
|
@ -114,6 +166,9 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
|
|||
break;
|
||||
|
||||
case MIM_LONGDATA: /* SYSEX data */
|
||||
FLUID_LOG(FLUID_DBG, "\ndevice at index %d sending MIDI sysex message",
|
||||
dev_infos->dev_idx);
|
||||
|
||||
if(dev->hThread == NULL)
|
||||
{
|
||||
break;
|
||||
|
@ -131,7 +186,8 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
|
|||
(*dev->driver.handler)(dev->driver.data, &event);
|
||||
}
|
||||
|
||||
PostThreadMessage(dev->dwThread, MM_MIM_LONGDATA, 0, dwParam1);
|
||||
/* request the sysex thread to re-add this buffer into the device dev_infos->midi_num */
|
||||
PostThreadMessage(dev->dwThread, MM_MIM_LONGDATA, dev_infos->midi_num, dwParam1);
|
||||
break;
|
||||
|
||||
case MIM_ERROR:
|
||||
|
@ -145,11 +201,70 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build a device name prefixed by its index. The format of the returned
|
||||
* name is: dev_idx:dev_name
|
||||
* The name returned is convenient for midi.winmidi.device setting.
|
||||
* It allows the user to identify a device index through its name or vise
|
||||
* versa. This allows the user to specify a multi device name using a list of
|
||||
* devices index (see fluid_winmidi_midi_driver_settings()).
|
||||
*
|
||||
* @param dev_idx, device index.
|
||||
* @param dev_name, name of the device.
|
||||
* @return the new device name (that must be freed when finish with it) or
|
||||
* NULL if memory allocation error.
|
||||
*/
|
||||
static char *fluid_winmidi_get_device_name(int dev_idx, char *dev_name)
|
||||
{
|
||||
char *new_dev_name;
|
||||
|
||||
int i = dev_idx;
|
||||
size_t size = 0; /* index size */
|
||||
|
||||
do
|
||||
{
|
||||
size++;
|
||||
i = i / 10 ;
|
||||
}
|
||||
while(i);
|
||||
|
||||
/* index size + separator + name length + zero termination */
|
||||
new_dev_name = FLUID_MALLOC(size + 2 + FLUID_STRLEN(dev_name));
|
||||
|
||||
if(new_dev_name)
|
||||
{
|
||||
/* the name is filled if allocation is successful */
|
||||
FLUID_SPRINTF(new_dev_name, "%d:%s", dev_idx, dev_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
}
|
||||
|
||||
return new_dev_name;
|
||||
}
|
||||
|
||||
/*
|
||||
Add setting midi.winmidi.device in the settings.
|
||||
|
||||
MIDI devices names are enumerated and added to midi.winmidi.device setting
|
||||
options. Example:
|
||||
0:Port MIDI SB Live! [CE00], 1:SB PCI External MIDI, default, x[;y;z;..]
|
||||
|
||||
Devices name prefixed by index (i.e 1:SB PCI External MIDI) are real devices.
|
||||
"default" name is the default device.
|
||||
"x[;y;z;..]" is the multi device naming. Its purpose is to indicate to
|
||||
the user how he must specify a multi device name in the setting.
|
||||
A multi devices name must be a list of real devices index separated by semicolon:
|
||||
Example: "5;3;0"
|
||||
*/
|
||||
void fluid_winmidi_midi_driver_settings(fluid_settings_t *settings)
|
||||
{
|
||||
MMRESULT res;
|
||||
MIDIINCAPS in_caps;
|
||||
UINT i, num;
|
||||
|
||||
/* register midi.winmidi.device */
|
||||
fluid_settings_register_str(settings, "midi.winmidi.device", "default", 0);
|
||||
num = midiInGetNumDevs();
|
||||
|
||||
|
@ -157,13 +272,24 @@ void fluid_winmidi_midi_driver_settings(fluid_settings_t *settings)
|
|||
{
|
||||
fluid_settings_add_option(settings, "midi.winmidi.device", "default");
|
||||
|
||||
/* add real devices names in options list */
|
||||
for(i = 0; i < num; i++)
|
||||
{
|
||||
res = midiInGetDevCaps(i, &in_caps, sizeof(MIDIINCAPS));
|
||||
|
||||
if(res == MMSYSERR_NOERROR)
|
||||
{
|
||||
fluid_settings_add_option(settings, "midi.winmidi.device", in_caps.szPname);
|
||||
/* add new device name (prefixed by its index) */
|
||||
char *new_dev_name = fluid_winmidi_get_device_name(i, in_caps.szPname);
|
||||
|
||||
if(!new_dev_name)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fluid_settings_add_option(settings, "midi.winmidi.device",
|
||||
new_dev_name);
|
||||
FLUID_FREE(new_dev_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +320,9 @@ static DWORD WINAPI fluid_winmidi_add_sysex_thread(void *data)
|
|||
switch(msg.message)
|
||||
{
|
||||
case MM_MIM_LONGDATA:
|
||||
midiInAddBuffer(dev->hmidiin, (LPMIDIHDR)msg.lParam, sizeof(MIDIHDR));
|
||||
/* re-add the buffer into the device designed by msg.wParam parameter */
|
||||
midiInAddBuffer(dev->dev_infos[msg.wParam].hmidiin,
|
||||
(LPMIDIHDR)msg.lParam, sizeof(MIDIHDR));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +330,134 @@ static DWORD WINAPI fluid_winmidi_add_sysex_thread(void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse device name
|
||||
* @param dev if not NULL pointer on driver structure in which device index
|
||||
* are returned.
|
||||
* @param dev_name device name which is expected to be:
|
||||
* - a multi devices naming (i.e "1;0;2") or
|
||||
* - a single device name (i.e "0:Port MIDI SB Live! [CE00]"
|
||||
* @return count of devices parsed or 0 if device name doesn't exist.
|
||||
*/
|
||||
static int
|
||||
fluid_winmidi_parse_device_name(fluid_winmidi_driver_t *dev, char *dev_name)
|
||||
{
|
||||
int dev_count = 0; /* device count */
|
||||
int dev_idx; /* device index */
|
||||
char *cur_idx, *next_idx; /* current and next ascii index pointer */
|
||||
char cpy_dev_name[MAXPNAMELEN];
|
||||
int num = midiInGetNumDevs(); /* get number of real devices installed */
|
||||
|
||||
/* look for a multi device naming */
|
||||
/* multi devices name "x;[y;..]". parse devices index: x;y;..
|
||||
Each ascii index are separated by a semicolon caracter.
|
||||
*/
|
||||
FLUID_STRCPY(cpy_dev_name, dev_name); /* fluid_strtok() will overwrite */
|
||||
next_idx = cpy_dev_name;
|
||||
|
||||
while(cur_idx = fluid_strtok(&next_idx, " ;"))
|
||||
{
|
||||
/* try to convert current ascii index */
|
||||
char *end_idx = cur_idx;
|
||||
dev_idx = g_ascii_strtoll(cur_idx, &end_idx, 10);
|
||||
|
||||
if(cur_idx == end_idx /* not an integer number */
|
||||
|| dev_idx < 0 /* invalid device index */
|
||||
|| dev_idx >= num /* invalid device index */
|
||||
)
|
||||
{
|
||||
if(dev)
|
||||
{
|
||||
dev->dev_count = 0;
|
||||
}
|
||||
|
||||
dev_count = 0; /* error, end of parsing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* memorize device index in dev_infos table */
|
||||
if(dev)
|
||||
{
|
||||
dev->dev_infos[dev->dev_count++].dev_idx = dev_idx;
|
||||
}
|
||||
|
||||
dev_count++;
|
||||
}
|
||||
|
||||
/* look for single device if multi devices not found */
|
||||
if(!dev_count)
|
||||
{
|
||||
/* default device index: dev_idx = 0, dev_count = 1 */
|
||||
dev_count = 1;
|
||||
dev_idx = 0;
|
||||
|
||||
if(FLUID_STRCASECMP("default", dev_name) != 0)
|
||||
{
|
||||
int i;
|
||||
dev_count = 0; /* reset count of devices found */
|
||||
|
||||
for(i = 0; i < num; i++)
|
||||
{
|
||||
char strError[MAXERRORLENGTH];
|
||||
MIDIINCAPS in_caps;
|
||||
MMRESULT res;
|
||||
res = midiInGetDevCaps(i, &in_caps, sizeof(MIDIINCAPS));
|
||||
|
||||
if(res == MMSYSERR_NOERROR)
|
||||
{
|
||||
int str_cmp_res;
|
||||
char *new_dev_name = fluid_winmidi_get_device_name(i, in_caps.szPname);
|
||||
|
||||
if(!new_dev_name)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
WCHAR wDevName[MAXPNAMELEN];
|
||||
MultiByteToWideChar(CP_UTF8, 0, dev_name, -1, wDevName, MAXPNAMELEN);
|
||||
|
||||
str_cmp_res = wcsicmp(wDevName, new_dev_name);
|
||||
#else
|
||||
str_cmp_res = FLUID_STRCASECMP(dev_name, new_dev_name);
|
||||
#endif
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Testing midi device \"%s\"", new_dev_name);
|
||||
FLUID_FREE(new_dev_name);
|
||||
|
||||
if(str_cmp_res == 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Selected midi device number: %u", i);
|
||||
dev_idx = i;
|
||||
dev_count = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Error testing midi device %u of %u: %s (error %d)",
|
||||
i, num, fluid_winmidi_input_error(strError, res), res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dev && dev_count)
|
||||
{
|
||||
dev->dev_infos[0].dev_idx = dev_idx;
|
||||
dev->dev_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(num < dev_count)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "not enough MIDI in devices found. Expected:%d found:%d",
|
||||
dev_count, num);
|
||||
dev_count = 0;
|
||||
}
|
||||
|
||||
return dev_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* new_fluid_winmidi_driver
|
||||
*/
|
||||
|
@ -210,10 +466,9 @@ 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, num, midi_num = 0;
|
||||
MIDIINCAPS in_caps;
|
||||
int i, j;
|
||||
int max_devices; /* maximum number of devices to handle */
|
||||
char strError[MAXERRORLENGTH];
|
||||
char dev_name[MAXPNAMELEN];
|
||||
|
||||
|
@ -231,108 +486,81 @@ new_fluid_winmidi_driver(fluid_settings_t *settings,
|
|||
FLUID_STRCPY(dev_name, "default");
|
||||
}
|
||||
|
||||
/* check if there any midi devices installed */
|
||||
num = midiInGetNumDevs();
|
||||
/* parse device name, get the maximum number of devices to handle */
|
||||
max_devices = fluid_winmidi_parse_device_name(NULL, dev_name);
|
||||
|
||||
if(num == 0)
|
||||
/* check if any device has be found */
|
||||
if(!max_devices)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "no MIDI in devices found");
|
||||
FLUID_LOG(FLUID_ERR, "Device \"%s\" does not exists", dev_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find the device */
|
||||
if(FLUID_STRCASECMP("default", dev_name) != 0)
|
||||
{
|
||||
for(i = 0; i < num; i++)
|
||||
{
|
||||
res = midiInGetDevCaps(i, &in_caps, sizeof(MIDIINCAPS));
|
||||
|
||||
if(res == MMSYSERR_NOERROR)
|
||||
{
|
||||
int str_cmp_res;
|
||||
#ifdef _UNICODE
|
||||
WCHAR wDevName[MAXPNAMELEN];
|
||||
MultiByteToWideChar(CP_UTF8, 0, dev_name, -1, wDevName, MAXPNAMELEN);
|
||||
|
||||
str_cmp_res = wcsicmp(wDevName, in_caps.szPname);
|
||||
#else
|
||||
str_cmp_res = FLUID_STRCASECMP(dev_name, in_caps.szPname);
|
||||
#endif
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Testing midi device \"%s\"", in_caps.szPname);
|
||||
|
||||
if(str_cmp_res == 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Selected midi device number: %u", i);
|
||||
midi_num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Error testing midi device %u of %u: %s (error %d)", i, num, fluid_winmidi_input_error(strError, res), res);
|
||||
}
|
||||
}
|
||||
|
||||
if(midi_num != i)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Device \"%s\" does not exists", dev_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dev = FLUID_MALLOC(sizeof(fluid_winmidi_driver_t));
|
||||
/* allocation of driver structure size dependant of max_devices */
|
||||
i = sizeof(fluid_winmidi_driver_t) + (max_devices - 1) * sizeof(device_infos_t);
|
||||
dev = FLUID_MALLOC(i);
|
||||
|
||||
if(dev == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_winmidi_driver_t));
|
||||
FLUID_MEMSET(dev, 0, i); /* reset structure members */
|
||||
|
||||
/* parse device name, get devices index */
|
||||
fluid_winmidi_parse_device_name(dev, dev_name);
|
||||
|
||||
dev->hmidiin = NULL;
|
||||
dev->driver.handler = handler;
|
||||
dev->driver.data = data;
|
||||
|
||||
/* try opening the device */
|
||||
res = midiInOpen(&dev->hmidiin, midi_num,
|
||||
(DWORD_PTR) fluid_winmidi_callback,
|
||||
(DWORD_PTR) dev, CALLBACK_FUNCTION);
|
||||
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
/* try opening the devices */
|
||||
for(i = 0; i < dev->dev_count; i++)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't open MIDI input: %s (error %d)",
|
||||
fluid_winmidi_input_error(strError, res), res);
|
||||
goto error_recovery;
|
||||
}
|
||||
device_infos_t *dev_infos = &dev->dev_infos[i];
|
||||
dev_infos->dev = dev; /* driver structure */
|
||||
dev_infos->midi_num = i; /* device order number */
|
||||
dev_infos->channel_map = i * 16; /* map from input to output */
|
||||
FLUID_LOG(FLUID_DBG, "opening device at index %d", dev_infos->dev_idx);
|
||||
res = midiInOpen(&dev_infos->hmidiin, dev_infos->dev_idx,
|
||||
(DWORD_PTR) fluid_winmidi_callback,
|
||||
(DWORD_PTR) dev_infos, CALLBACK_FUNCTION);
|
||||
|
||||
/* Prepare and add SYSEX buffers */
|
||||
for(i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
|
||||
{
|
||||
hdr = &dev->sysExHdrs[i];
|
||||
|
||||
hdr->lpData = (LPSTR)&dev->sysExBuf[i * MIDI_SYSEX_MAX_SIZE];
|
||||
hdr->dwBufferLength = MIDI_SYSEX_MAX_SIZE;
|
||||
|
||||
/* Prepare a buffer for SYSEX data and add it */
|
||||
res = midiInPrepareHeader(dev->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
|
||||
if(res == MMSYSERR_NOERROR)
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
{
|
||||
res = midiInAddBuffer(dev->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't open MIDI input: %s (error %d)",
|
||||
fluid_winmidi_input_error(strError, res), res);
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
/* Prepare and add SYSEX buffers */
|
||||
for(j = 0; j < MIDI_SYSEX_BUF_COUNT; j++)
|
||||
{
|
||||
MIDIHDR *hdr = &dev_infos->sysExHdrs[j];
|
||||
|
||||
hdr->lpData = (LPSTR)&dev_infos->sysExBuf[j * MIDI_SYSEX_MAX_SIZE];
|
||||
hdr->dwBufferLength = MIDI_SYSEX_MAX_SIZE;
|
||||
|
||||
/* Prepare a buffer for SYSEX data and add it */
|
||||
res = midiInPrepareHeader(dev_infos->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
|
||||
if(res == MMSYSERR_NOERROR)
|
||||
{
|
||||
res = midiInAddBuffer(dev_infos->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
|
||||
fluid_winmidi_input_error(strError, res), res);
|
||||
midiInUnprepareHeader(dev_infos->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
else
|
||||
FLUID_LOG(FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
|
||||
fluid_winmidi_input_error(strError, res), res);
|
||||
midiInUnprepareHeader(dev->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
else
|
||||
FLUID_LOG(FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
|
||||
fluid_winmidi_input_error(strError, res), res);
|
||||
}
|
||||
|
||||
|
||||
/* Create thread which processes re-adding SYSEX buffers */
|
||||
dev->hThread = CreateThread(
|
||||
NULL,
|
||||
|
@ -350,10 +578,13 @@ new_fluid_winmidi_driver(fluid_settings_t *settings,
|
|||
}
|
||||
|
||||
/* Start the MIDI input interface */
|
||||
if(midiInStart(dev->hmidiin) != MMSYSERR_NOERROR)
|
||||
for(i = 0; i < dev->dev_count; i++)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Failed to start the MIDI input. MIDI input not available.");
|
||||
goto error_recovery;
|
||||
if(midiInStart(dev->dev_infos[i].hmidiin) != MMSYSERR_NOERROR)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Failed to start the MIDI input. MIDI input not available.");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
return (fluid_midi_driver_t *) dev;
|
||||
|
@ -370,11 +601,12 @@ error_recovery:
|
|||
void
|
||||
delete_fluid_winmidi_driver(fluid_midi_driver_t *p)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
fluid_winmidi_driver_t *dev = (fluid_winmidi_driver_t *) p;
|
||||
fluid_return_if_fail(dev != NULL);
|
||||
|
||||
/* request the sysex thread to terminate */
|
||||
if(dev->hThread != NULL)
|
||||
{
|
||||
PostThreadMessage(dev->dwThread, WM_CLOSE, 0, 0);
|
||||
|
@ -384,22 +616,30 @@ delete_fluid_winmidi_driver(fluid_midi_driver_t *p)
|
|||
dev->hThread = NULL;
|
||||
}
|
||||
|
||||
if(dev->hmidiin != NULL)
|
||||
/* stop MIDI in devices and free allocated buffers */
|
||||
for(i = 0; i < dev->dev_count; i++)
|
||||
{
|
||||
midiInStop(dev->hmidiin);
|
||||
midiInReset(dev->hmidiin);
|
||||
device_infos_t *dev_infos = &dev->dev_infos[i];
|
||||
|
||||
for(i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
|
||||
if(dev_infos->hmidiin != NULL)
|
||||
{
|
||||
MIDIHDR *hdr = &dev->sysExHdrs[i];
|
||||
/* stop the device and mark any pending data blocks as being done */
|
||||
midiInReset(dev_infos->hmidiin);
|
||||
|
||||
if ((hdr->dwFlags & MHDR_PREPARED))
|
||||
/* free allocated buffers associated to this device */
|
||||
for(j = 0; j < MIDI_SYSEX_BUF_COUNT; j++)
|
||||
{
|
||||
midiInUnprepareHeader(dev->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
MIDIHDR *hdr = &dev_infos->sysExHdrs[j];
|
||||
|
||||
midiInClose(dev->hmidiin);
|
||||
if((hdr->dwFlags & MHDR_PREPARED))
|
||||
{
|
||||
midiInUnprepareHeader(dev_infos->hmidiin, hdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
|
||||
/* close the device */
|
||||
midiInClose(dev_infos->hmidiin);
|
||||
}
|
||||
}
|
||||
|
||||
FLUID_FREE(dev);
|
||||
|
|
Loading…
Reference in a new issue