The syscall itself is temporary.
Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/wineoss.drv/midi.c | 129 +------------------------ dlls/wineoss.drv/oss.c | 2 +- dlls/wineoss.drv/ossmidi.c | 189 +++++++++++++++++++++++++++++++++++-- dlls/wineoss.drv/unixlib.h | 10 +- 4 files changed, 196 insertions(+), 134 deletions(-)
diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c index b3f980ab3da..0afd9985c03 100644 --- a/dlls/wineoss.drv/midi.c +++ b/dlls/wineoss.drv/midi.c @@ -126,16 +126,6 @@ static LRESULT OSS_MidiExit(void) return 0; }
-static void in_buffer_lock(void) -{ - OSS_CALL(midi_in_lock, ULongToPtr(1)); -} - -static void in_buffer_unlock(void) -{ - OSS_CALL(midi_in_lock, ULongToPtr(0)); -} - static void notify_client(struct notify_context *notify) { TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n", @@ -210,123 +200,13 @@ static int midiCloseSeq(int fd) return 0; }
-static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time) -{ - MIDIHDR *hdr; - BOOL done = FALSE; - - src->state |= 2; - src->incLen = 0; - - in_buffer_lock(); - - hdr = src->lpQueueHdr; - if (hdr) - { - BYTE *data = (BYTE *)hdr->lpData; - - data[hdr->dwBytesRecorded++] = value; - if (hdr->dwBytesRecorded == hdr->dwBufferLength) - done = TRUE; - } - - if (value == 0xf7) /* end */ - { - src->state &= ~2; - done = TRUE; - } - - if (done && hdr) - { - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - MIDI_NotifyClient(src - MidiInDev, MIM_LONGDATA, (UINT_PTR)hdr, time); - } - - in_buffer_unlock(); -} - -static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time) -{ - UINT to_send = 0; - -#define IS_CMD(_x) (((_x) & 0x80) == 0x80) -#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0) - - if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */ - { - if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev)) - { - src->incoming[0] = src->incPrev; - src->incLen = 1; - } - else - { - /* FIXME: should generate MIM_ERROR notification */ - return; - } - } - src->incoming[(int)src->incLen++] = value; - if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0])) - /* store new cmd, just in case */ - src->incPrev = src->incoming[0]; - -#undef IS_CMD -#undef IS_SYS_CMD - - switch (src->incoming[0] & 0xF0) - { - case MIDI_NOTEOFF: - case MIDI_NOTEON: - case MIDI_KEY_PRESSURE: - case MIDI_CTL_CHANGE: - case MIDI_PITCH_BEND: - if (src->incLen == 3) - to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) | - src->incoming[0]; - break; - case MIDI_PGM_CHANGE: - case MIDI_CHN_PRESSURE: - if (src->incLen == 2) - to_send = (src->incoming[1] << 8) | src->incoming[0]; - break; - case MIDI_SYSTEM_PREFIX: - if (src->incLen == 1) - to_send = src->incoming[0]; - break; - } - - if (to_send) - { - src->incLen = 0; - MIDI_NotifyClient(src - MidiInDev, MIM_DATA, to_send, time); - } -} - static void handle_midi_data(unsigned char *buffer, unsigned int len) { - unsigned int time = GetTickCount(), i; - struct midi_src *src; - unsigned char value; - WORD dev_id; + struct midi_handle_data_params params;
- for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4) - { - if (buffer[i] != SEQ_MIDIPUTC) continue; - - dev_id = buffer[i + 2]; - value = buffer[i + 1]; - - if (dev_id >= MIDM_NumDevs) continue; - src = MidiInDev + dev_id; - if (src->state <= 0) continue; - - if (value == 0xf0 || src->state & 2) /* system exclusive */ - handle_sysex_data(src, value, time - src->startTime); - else - handle_regular_data(src, value, time - src->startTime); - } + params.buffer = buffer; + params.len = len; + OSS_CALL(midi_handle_data, ¶ms); }
static DWORD WINAPI midRecThread(void *arg) @@ -565,6 +445,7 @@ static DWORD WINAPI notify_thread(void *p) { OSS_CALL(midi_notify_wait, ¶ms); if (quit) break; + if (notify.send_notify) notify_client(¬ify); } return 0; } diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c index 8fda9270a4e..c5b422a60c9 100644 --- a/dlls/wineoss.drv/oss.c +++ b/dlls/wineoss.drv/oss.c @@ -1412,5 +1412,5 @@ unixlib_entry_t __wine_unix_call_funcs[] = midi_notify_wait,
midi_seq_open, - midi_in_lock, + midi_handle_data, }; diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c index 0790eaaec1a..1695f1d2f7b 100644 --- a/dlls/wineoss.drv/ossmidi.c +++ b/dlls/wineoss.drv/ossmidi.c @@ -68,7 +68,11 @@ static struct midi_src srcs[MAX_MIDIINDRV];
static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER; static BOOL notify_quit; +#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */ +static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE]; +static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer;
typedef struct sVoice { @@ -151,19 +155,59 @@ static void in_buffer_unlock(void) pthread_mutex_unlock(&in_buffer_mutex); }
-NTSTATUS midi_in_lock(void *args) +/* + * notify buffer: The notification ring buffer is implemented so that + * there is always at least one unused sentinel before the current + * read position in order to allow detection of the full vs empty + * state. + */ +static struct notify_context *notify_buffer_next(struct notify_context *notify) { - if (args) in_buffer_lock(); - else in_buffer_unlock(); + if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer)) + notify = notify_buffer;
- return STATUS_SUCCESS; + return notify; +} + +static BOOL notify_buffer_empty(void) +{ + return notify_read == notify_write; +} + +static BOOL notify_buffer_full(void) +{ + return notify_buffer_next(notify_write) == notify_read; +} + +static BOOL notify_buffer_add(struct notify_context *notify) +{ + if (notify_buffer_full()) return FALSE; + + *notify_write = *notify; + notify_write = notify_buffer_next(notify_write); + return TRUE; +} + +static BOOL notify_buffer_remove(struct notify_context *notify) +{ + if (notify_buffer_empty()) return FALSE; + + *notify = *notify_read; + notify_read = notify_buffer_next(notify_read); + return TRUE; }
static void notify_post(struct notify_context *notify) { pthread_mutex_lock(¬ify_mutex);
- if (notify) FIXME("Not yet handled\n"); + if (notify) + { + while (notify_buffer_full()) + pthread_cond_wait(¬ify_write_cond, ¬ify_mutex); + + notify_buffer_add(notify); + } else notify_quit = TRUE; pthread_cond_signal(¬ify_read_cond);
@@ -1157,6 +1201,133 @@ static UINT midi_out_reset(WORD dev_id) return MMSYSERR_NOERROR; }
+static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time) +{ + struct notify_context notify; + MIDIHDR *hdr; + BOOL done = FALSE; + + src->state |= 2; + src->incLen = 0; + + in_buffer_lock(); + + hdr = src->lpQueueHdr; + if (hdr) + { + BYTE *data = (BYTE *)hdr->lpData; + + data[hdr->dwBytesRecorded++] = value; + if (hdr->dwBytesRecorded == hdr->dwBufferLength) + done = TRUE; + } + + if (value == 0xf7) /* end */ + { + src->state &= ~2; + done = TRUE; + } + + if (done && hdr) + { + src->lpQueueHdr = hdr->lpNext; + hdr->dwFlags &= ~MHDR_INQUEUE; + hdr->dwFlags |= MHDR_DONE; + set_in_notify(¬ify, src, src - srcs, MIM_LONGDATA, (UINT_PTR)hdr, time); + notify_post(¬ify); + } + + in_buffer_unlock(); +} + +static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time) +{ + struct notify_context notify; + UINT to_send = 0; + +#define IS_CMD(_x) (((_x) & 0x80) == 0x80) +#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0) + + if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */ + { + if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev)) + { + src->incoming[0] = src->incPrev; + src->incLen = 1; + } + else + { + /* FIXME: should generate MIM_ERROR notification */ + return; + } + } + src->incoming[(int)src->incLen++] = value; + if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0])) + /* store new cmd, just in case */ + src->incPrev = src->incoming[0]; + +#undef IS_CMD +#undef IS_SYS_CMD + + switch (src->incoming[0] & 0xF0) + { + case MIDI_NOTEOFF: + case MIDI_NOTEON: + case MIDI_KEY_PRESSURE: + case MIDI_CTL_CHANGE: + case MIDI_PITCH_BEND: + if (src->incLen == 3) + to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) | + src->incoming[0]; + break; + case MIDI_PGM_CHANGE: + case MIDI_CHN_PRESSURE: + if (src->incLen == 2) + to_send = (src->incoming[1] << 8) | src->incoming[0]; + break; + case MIDI_SYSTEM_PREFIX: + if (src->incLen == 1) + to_send = src->incoming[0]; + break; + } + + if (to_send) + { + src->incLen = 0; + set_in_notify(¬ify, src, src - srcs, MIM_DATA, to_send, time); + notify_post(¬ify); + } +} + +NTSTATUS midi_handle_data(void *args) +{ + struct midi_handle_data_params *params = args; + unsigned char *buffer = params->buffer; + unsigned int len = params->len; + unsigned int time = NtGetTickCount(), i; + struct midi_src *src; + unsigned char value; + WORD dev_id; + + for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4) + { + if (buffer[i] != SEQ_MIDIPUTC) continue; + + dev_id = buffer[i + 2]; + value = buffer[i + 1]; + + if (dev_id >= num_srcs) continue; + src = srcs + dev_id; + if (src->state <= 0) continue; + + if (value == 0xf0 || src->state & 2) /* system exclusive */ + handle_sysex_data(src, value, time - src->startTime); + else + handle_regular_data(src, value, time - src->startTime); + } + return STATUS_SUCCESS; +} + static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) { struct midi_src *src; @@ -1397,11 +1568,15 @@ NTSTATUS midi_notify_wait(void *args)
pthread_mutex_lock(¬ify_mutex);
- while (!notify_quit) + while (!notify_quit && notify_buffer_empty()) pthread_cond_wait(¬ify_read_cond, ¬ify_mutex);
*params->quit = notify_quit; - + if (!notify_quit) + { + notify_buffer_remove(params->notify); + pthread_cond_signal(¬ify_write_cond); + } pthread_mutex_unlock(¬ify_mutex);
return STATUS_SUCCESS; diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h index ddeba49556c..90d0c47421c 100644 --- a/dlls/wineoss.drv/unixlib.h +++ b/dlls/wineoss.drv/unixlib.h @@ -279,6 +279,12 @@ struct midi_seq_open_params int fd; };
+struct midi_handle_data_params +{ + unsigned char *buffer; + unsigned int len; +}; + enum oss_funcs { oss_test_connect, @@ -311,7 +317,7 @@ enum oss_funcs oss_midi_notify_wait,
oss_midi_seq_open, /* temporary */ - oss_midi_in_lock, + oss_midi_handle_data, };
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN; @@ -320,7 +326,7 @@ NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN; NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN; NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN; NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN; -NTSTATUS midi_in_lock(void *args) DECLSPEC_HIDDEN; +NTSTATUS midi_handle_data(void *args) DECLSPEC_HIDDEN;
extern unixlib_handle_t oss_handle;