diff --git a/src/drivers/fluid_winmidi.c b/src/drivers/fluid_winmidi.c index c910a241..b568bcca 100644 --- a/src/drivers/fluid_winmidi.c +++ b/src/drivers/fluid_winmidi.c @@ -57,17 +57,93 @@ typedef struct } fluid_winmidi_driver_t; -static char fluid_winmidi_error_buffer[256]; - #define msg_type(_m) ((unsigned char)(_m & 0xf0)) #define msg_chan(_m) ((unsigned char)(_m & 0x0f)) #define msg_p1(_m) ((_m >> 8) & 0x7f) #define msg_p2(_m) ((_m >> 16) & 0x7f) -void CALLBACK fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance, - DWORD_PTR msg, DWORD_PTR extra); -static char *fluid_winmidi_input_error(MMRESULT no); +static char * +fluid_winmidi_input_error(char *strError, MMRESULT no) +{ +#ifdef _UNICODE + WCHAR wStr[MAXERRORLENGTH]; + midiInGetErrorText(no, wStr, MAXERRORLENGTH); + WideCharToMultiByte(CP_UTF8, 0, wStr, -1, strError, MAXERRORLENGTH, 0, 0); +#else + midiInGetErrorText(no, strError, MAXERRORLENGTH); +#endif + + return strError; +} + +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; + fluid_midi_event_t event; + LPMIDIHDR pMidiHdr; + unsigned char *data; + unsigned int msg_param = (unsigned int) dwParam1; + + switch(wMsg) + { + case MIM_OPEN: + break; + + case MIM_CLOSE: + break; + + case MIM_DATA: + event.type = msg_type(msg_param); + event.channel = msg_chan(msg_param); + + if(event.type != PITCH_BEND) + { + event.param1 = msg_p1(msg_param); + event.param2 = msg_p2(msg_param); + } + else /* Pitch bend is a 14 bit value */ + { + event.param1 = (msg_p2(msg_param) << 7) | msg_p1(msg_param); + event.param2 = 0; + } + + (*dev->driver.handler)(dev->driver.data, &event); + break; + + case MIM_LONGDATA: /* SYSEX data */ + if(dev->hThread == NULL) + { + break; + } + + 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); + } + + PostThreadMessage(dev->dwThread, MM_MIM_LONGDATA, 0, dwParam1); + break; + + case MIM_ERROR: + break; + + case MIM_LONGERROR: + break; + + case MIM_MOREDATA: + break; + } +} void fluid_winmidi_midi_driver_settings(fluid_settings_t *settings) { @@ -138,7 +214,8 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, MMRESULT res; UINT i, num, midi_num = 0; MIDIINCAPS in_caps; - char *devname = NULL; + char strError[MAXERRORLENGTH]; + char dev_name[MAXPNAMELEN]; /* not much use doing anything */ if(handler == NULL) @@ -147,6 +224,49 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, return NULL; } + /* get the device name. if none is specified, use the default device. */ + if(fluid_settings_copystr(settings, "midi.winmidi.device", dev_name, MAXPNAMELEN) != FLUID_OK) + { + FLUID_LOG(FLUID_DBG, "No MIDI in device selected, using \"default\""); + FLUID_STRCPY(dev_name, "default"); + } + + /* check if there any midi devices installed */ + num = midiInGetNumDevs(); + + if(num == 0) + { + FLUID_LOG(FLUID_ERR, "no MIDI in devices found"); + 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) + { + FLUID_LOG(FLUID_DBG, "Testing midi device: %s\n", in_caps.szPname); + + if(FLUID_STRCASECMP(dev_name, in_caps.szPname) == 0) + { + FLUID_LOG(FLUID_DBG, "Selected midi device number: %d\n", i); + midi_num = i; + break; + } + } + } + + 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)); if(dev == NULL) @@ -160,54 +280,6 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, dev->driver.handler = handler; dev->driver.data = data; - /* get the device name. if none is specified, use the default device. */ - if(fluid_settings_dupstr(settings, "midi.winmidi.device", &devname) != FLUID_OK || !devname) - { - devname = FLUID_STRDUP("default"); - - if(!devname) - { - FLUID_LOG(FLUID_ERR, "Out of memory"); - goto error_recovery; - } - } - - /* check if there any midi devices installed */ - num = midiInGetNumDevs(); - - if(num == 0) - { - FLUID_LOG(FLUID_ERR, "no MIDI in devices found"); - goto error_recovery; - } - - /* find the device */ - if(FLUID_STRCASECMP("default", devname) != 0) - { - for(i = 0; i < num; i++) - { - res = midiInGetDevCaps(i, &in_caps, sizeof(MIDIINCAPS)); - - if(res == MMSYSERR_NOERROR) - { - FLUID_LOG(FLUID_DBG, "Testing midi device: %s\n", in_caps.szPname); - - if(FLUID_STRCASECMP(devname, in_caps.szPname) == 0) - { - FLUID_LOG(FLUID_DBG, "Selected midi device number: %d\n", i); - midi_num = i; - break; - } - } - } - - if(midi_num != i) - { - FLUID_LOG(FLUID_ERR, "Device <%s> does not exists", devname); - goto error_recovery; - } - } - /* try opening the device */ res = midiInOpen(&dev->hmidiin, midi_num, (DWORD_PTR) fluid_winmidi_callback, @@ -216,7 +288,7 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, if(res != MMSYSERR_NOERROR) { FLUID_LOG(FLUID_ERR, "Couldn't open MIDI input: %s (error %d)", - fluid_winmidi_input_error(res), res); + fluid_winmidi_input_error(strError, res), res); goto error_recovery; } @@ -238,13 +310,13 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, if(res != MMSYSERR_NOERROR) { FLUID_LOG(FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)", - fluid_winmidi_input_error(res), res); + 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(res), res); + fluid_winmidi_input_error(strError, res), res); } /* Create thread which processes re-adding SYSEX buffers */ @@ -270,20 +342,10 @@ new_fluid_winmidi_driver(fluid_settings_t *settings, goto error_recovery; } - if(devname) - { - FLUID_FREE(devname); /* -- free device name */ - } - return (fluid_midi_driver_t *) dev; error_recovery: - if(devname) - { - FLUID_FREE(devname); /* -- free device name */ - } - delete_fluid_winmidi_driver((fluid_midi_driver_t *) dev); return NULL; } @@ -294,6 +356,8 @@ error_recovery: void delete_fluid_winmidi_driver(fluid_midi_driver_t *p) { + int i; + fluid_winmidi_driver_t *dev = (fluid_winmidi_driver_t *) p; fluid_return_if_fail(dev != NULL); @@ -310,85 +374,21 @@ delete_fluid_winmidi_driver(fluid_midi_driver_t *p) { midiInStop(dev->hmidiin); midiInReset(dev->hmidiin); + + for(i = 0; i < MIDI_SYSEX_BUF_COUNT; i++) + { + MIDIHDR *hdr = &dev->sysExHdrs[i]; + + if ((hdr->dwFlags & MHDR_PREPARED)) + { + midiInUnprepareHeader(dev->hmidiin, hdr, sizeof(MIDIHDR)); + } + } + midiInClose(dev->hmidiin); } FLUID_FREE(dev); } -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; - fluid_midi_event_t event; - LPMIDIHDR pMidiHdr; - unsigned char *data; - unsigned int msg_param = (unsigned int) dwParam1; - - switch(wMsg) - { - case MIM_OPEN: - break; - - case MIM_CLOSE: - break; - - case MIM_DATA: - event.type = msg_type(msg_param); - event.channel = msg_chan(msg_param); - - if(event.type != PITCH_BEND) - { - event.param1 = msg_p1(msg_param); - event.param2 = msg_p2(msg_param); - } - else /* Pitch bend is a 14 bit value */ - { - event.param1 = (msg_p2(msg_param) << 7) | msg_p1(msg_param); - event.param2 = 0; - } - - (*dev->driver.handler)(dev->driver.data, &event); - break; - - case MIM_LONGDATA: /* SYSEX data */ - if(dev->hThread == NULL) - { - break; - } - - 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); - } - - PostThreadMessage(dev->dwThread, MM_MIM_LONGDATA, 0, dwParam1); - break; - - case MIM_ERROR: - break; - - case MIM_LONGERROR: - break; - - case MIM_MOREDATA: - break; - } -} - -static char * -fluid_winmidi_input_error(MMRESULT no) -{ - midiInGetErrorText(no, fluid_winmidi_error_buffer, 256); - return fluid_winmidi_error_buffer; -} - #endif /* WINMIDI_SUPPORT */