[PATCH 6/6] winealsa: Move the midi event handlers to the unixlib.

Huw Davies huw at codeweavers.com
Wed Mar 23 03:16:55 CDT 2022


The MIM_DATA and MIM_LONGDATA notifications are sent via the
notification thread.  The midi_handle_event syscall is temporary.

Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/winealsa.drv/alsa.c     |   2 +-
 dlls/winealsa.drv/alsamidi.c | 172 +++++++++++++++++++++++++++++++++--
 dlls/winealsa.drv/midi.c     | 129 +-------------------------
 dlls/winealsa.drv/unixlib.h  |   4 +-
 4 files changed, 167 insertions(+), 140 deletions(-)

diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index 5b592986c06..b18588ab1c0 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -2451,6 +2451,6 @@ unixlib_entry_t __wine_unix_call_funcs[] =
     midi_notify_wait,
 
     midi_seq_lock, /* temporary */
-    midi_in_lock,
     midi_seq_open,
+    midi_handle_event,
 };
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c
index e10779f63a1..30c46eee64d 100644
--- a/dlls/winealsa.drv/alsamidi.c
+++ b/dlls/winealsa.drv/alsamidi.c
@@ -72,6 +72,9 @@ static int port_in = -1;
 static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t notify_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;
 
 static void seq_lock(void)
 {
@@ -101,14 +104,6 @@ static void in_buffer_unlock(void)
     pthread_mutex_unlock(&in_buffer_mutex);
 }
 
-NTSTATUS midi_in_lock(void *args)
-{
-    if (args) in_buffer_lock();
-    else in_buffer_unlock();
-
-    return STATUS_SUCCESS;
-}
-
 static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg,
                           UINT_PTR param_1, UINT_PTR param_2)
 {
@@ -123,11 +118,49 @@ static void set_in_notify(struct notify_context *notify, struct midi_src *src, W
     notify->instance = src->midiDesc.dwInstance;
 }
 
+/*
+ * 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 (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer))
+        notify = notify_buffer;
+
+    return notify;
+}
+
+static void notify_buffer_add(struct notify_context *notify)
+{
+    struct notify_context *next = notify_buffer_next(notify_write);
+
+    if (next == notify_read) /* buffer is full - we can't issue a WARN() in a non-Win32 thread */
+        notify_read = notify_buffer_next(notify_read); /* drop the oldest notification */
+    *notify_write = *notify;
+    notify_write = next;
+}
+
+static BOOL notify_buffer_empty(void)
+{
+    return notify_read == notify_write;
+}
+
+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(&notify_mutex);
 
-    if (notify) FIXME("Not yet handled\n");
+    if (notify) notify_buffer_add(notify);
     else notify_quit = TRUE;
     pthread_cond_signal(&notify_cond);
 
@@ -889,6 +922,124 @@ static UINT midi_out_reset(WORD dev_id)
     return MMSYSERR_NOERROR;
 }
 
+static void handle_sysex_event(struct midi_src *src, BYTE *data, UINT len)
+{
+    UINT pos = 0, copy_len, current_time = NtGetTickCount() - src->startTime;
+    struct notify_context notify;
+    MIDIHDR *hdr;
+
+    in_buffer_lock();
+
+    while (len)
+    {
+        hdr = src->lpQueueHdr;
+        if (!hdr) break;
+
+        copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded);
+        memcpy(hdr->lpData + hdr->dwBytesRecorded, data + pos, copy_len);
+        hdr->dwBytesRecorded += copy_len;
+        len -= copy_len;
+        pos += copy_len;
+
+        if ((hdr->dwBytesRecorded == hdr->dwBufferLength) ||
+            (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xF7))
+        { /* buffer full or end of sysex message */
+            src->lpQueueHdr = hdr->lpNext;
+            hdr->dwFlags &= ~MHDR_INQUEUE;
+            hdr->dwFlags |= MHDR_DONE;
+            set_in_notify(&notify, src, src - srcs, MIM_LONGDATA, (DWORD_PTR)hdr, current_time);
+            notify_post(&notify);
+        }
+    }
+
+    in_buffer_unlock();
+}
+
+static void handle_regular_event(struct midi_src *src, snd_seq_event_t *ev)
+{
+    UINT data = 0, value, current_time = NtGetTickCount() - src->startTime;
+    struct notify_context notify;
+
+    switch (ev->type)
+    {
+    case SND_SEQ_EVENT_NOTEOFF:
+        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_NOTEON:
+        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_KEYPRESS:
+        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_CONTROLLER:
+        data = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_PITCHBEND:
+        value = ev->data.control.value + 0x2000;
+        data = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_PGMCHANGE:
+        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_CHANPRESS:
+        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
+        break;
+    case SND_SEQ_EVENT_CLOCK:
+        data = 0xF8;
+        break;
+    case SND_SEQ_EVENT_START:
+        data = 0xFA;
+        break;
+    case SND_SEQ_EVENT_CONTINUE:
+        data = 0xFB;
+        break;
+    case SND_SEQ_EVENT_STOP:
+        data = 0xFC;
+        break;
+    case SND_SEQ_EVENT_SONGPOS:
+        data = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS;
+        break;
+    case SND_SEQ_EVENT_SONGSEL:
+        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT;
+        break;
+    case SND_SEQ_EVENT_RESET:
+        data = 0xFF;
+        break;
+    case SND_SEQ_EVENT_QFRAME:
+        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER;
+        break;
+    case SND_SEQ_EVENT_SENSING:
+        /* Noting to do */
+        break;
+    }
+
+    if (data != 0)
+    {
+        set_in_notify(&notify, src, src - srcs, MIM_DATA, data, current_time);
+        notify_post(&notify);
+    }
+}
+
+NTSTATUS midi_handle_event(void *args)
+{
+    snd_seq_event_t *ev = args;
+    struct midi_src *src;
+
+    /* Find the target device */
+    for (src = srcs; src < srcs + num_srcs; src++)
+        if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port))
+            break;
+    if ((src == srcs + num_srcs) || (src->state != 1))
+        return STATUS_SUCCESS;
+
+    if (ev->type == SND_SEQ_EVENT_SYSEX)
+        handle_sysex_event(src, ev->data.ext.ptr, ev->data.ext.len);
+    else
+        handle_regular_event(src, ev);
+
+    return STATUS_SUCCESS;
+}
+
 static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
 {
     struct midi_src *src;
@@ -1131,10 +1282,11 @@ NTSTATUS midi_notify_wait(void *args)
 
     pthread_mutex_lock(&notify_mutex);
 
-    while (!notify_quit)
+    while (!notify_quit && notify_buffer_empty())
         pthread_cond_wait(&notify_cond, &notify_mutex);
 
     *params->quit = notify_quit;
+    if (!notify_quit) notify_buffer_remove(params->notify);
 
     pthread_mutex_unlock(&notify_mutex);
 
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index 77ab9720bcc..8009b23ce3d 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -67,16 +67,6 @@ static void seq_unlock(void)
     ALSA_CALL(midi_seq_lock, (void *)(UINT_PTR)0);
 }
 
-static void in_buffer_lock(void)
-{
-    ALSA_CALL(midi_in_lock, (void *)(UINT_PTR)1);
-}
-
-static void in_buffer_unlock(void)
-{
-    ALSA_CALL(midi_in_lock, (void *)(UINT_PTR)0);
-}
-
 static void notify_client(struct notify_context *notify)
 {
     TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2);
@@ -122,11 +112,6 @@ static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
     switch (wMsg) {
     case MIM_OPEN:
     case MIM_CLOSE:
-    case MIM_DATA:
-    case MIM_LONGDATA:
-    case MIM_ERROR:
-    case MIM_LONGERROR:
-    case MIM_MOREDATA:
 	if (wDevID > MIDM_NumDevs) return;
 
 	dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;
@@ -170,117 +155,6 @@ static int midiCloseSeq(void)
     return 0;
 }
 
-static void handle_sysex_event(struct midi_src *src, BYTE *data, UINT len)
-{
-    UINT pos = 0, copy_len, current_time = NtGetTickCount() - src->startTime;
-    MIDIHDR *hdr;
-
-    in_buffer_lock();
-
-    while (len)
-    {
-        hdr = src->lpQueueHdr;
-        if (!hdr) break;
-
-        copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded);
-        memcpy(hdr->lpData + hdr->dwBytesRecorded, data + pos, copy_len);
-        hdr->dwBytesRecorded += copy_len;
-        len -= copy_len;
-        pos += copy_len;
-
-        if ((hdr->dwBytesRecorded == hdr->dwBufferLength) ||
-            (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xF7))
-        { /* buffer full or end of sysex message */
-            src->lpQueueHdr = hdr->lpNext;
-            hdr->dwFlags &= ~MHDR_INQUEUE;
-            hdr->dwFlags |= MHDR_DONE;
-            MIDI_NotifyClient(src - MidiInDev, MIM_LONGDATA, (DWORD_PTR)hdr, current_time);
-        }
-    }
-
-    in_buffer_unlock();
-}
-
-static void handle_regular_event(struct midi_src *src, snd_seq_event_t *ev)
-{
-    UINT data = 0, value, current_time = NtGetTickCount() - src->startTime;
-
-    switch (ev->type)
-    {
-    case SND_SEQ_EVENT_NOTEOFF:
-        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_NOTEON:
-        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_KEYPRESS:
-        data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_CONTROLLER:
-        data = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_PITCHBEND:
-        value = ev->data.control.value + 0x2000;
-        data = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_PGMCHANGE:
-        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_CHANPRESS:
-        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
-        break;
-    case SND_SEQ_EVENT_CLOCK:
-        data = 0xF8;
-        break;
-    case SND_SEQ_EVENT_START:
-        data = 0xFA;
-        break;
-    case SND_SEQ_EVENT_CONTINUE:
-        data = 0xFB;
-        break;
-    case SND_SEQ_EVENT_STOP:
-        data = 0xFC;
-        break;
-    case SND_SEQ_EVENT_SONGPOS:
-        data = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS;
-        break;
-    case SND_SEQ_EVENT_SONGSEL:
-        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT;
-        break;
-    case SND_SEQ_EVENT_RESET:
-        data = 0xFF;
-        break;
-    case SND_SEQ_EVENT_QFRAME:
-        data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER;
-        break;
-    case SND_SEQ_EVENT_SENSING:
-        /* Noting to do */
-        break;
-    }
-
-    if (data != 0)
-    {
-        MIDI_NotifyClient(src - MidiInDev, MIM_DATA, data, current_time);
-    }
-}
-
-static void handle_midi_event(snd_seq_event_t *ev)
-{
-    struct midi_src *src;
-
-    /* Find the target device */
-    for (src = MidiInDev; src < MidiInDev + MIDM_NumDevs; src++)
-        if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port))
-            break;
-    if ((src == MidiInDev + MIDM_NumDevs) || (src->state != 1))
-        return;
-
-    if (ev->type == SND_SEQ_EVENT_SYSEX)
-        handle_sysex_event(src, ev->data.ext.ptr, ev->data.ext.len);
-    else
-        handle_regular_event(src, ev);
-}
-
 static DWORD WINAPI midRecThread(void *arg)
 {
     snd_seq_t *midi_seq = arg;
@@ -320,7 +194,7 @@ static DWORD WINAPI midRecThread(void *arg)
             seq_unlock();
 
             if (ev) {
-                handle_midi_event(ev);
+                ALSA_CALL(midi_handle_event, ev);
                 snd_seq_free_event(ev);
             }
 
@@ -571,6 +445,7 @@ static DWORD WINAPI notify_thread(void *p)
     {
         ALSA_CALL(midi_notify_wait, &params);
         if (quit) break;
+        if (notify.send_notify) notify_client(&notify);
     }
     return 0;
 }
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index 68ab650d2f6..46f256a1c6a 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -310,8 +310,8 @@ enum alsa_funcs
     alsa_midi_notify_wait,
 
     alsa_midi_seq_lock, /* temporary */
-    alsa_midi_in_lock,
     alsa_midi_seq_open,
+    alsa_midi_handle_event,
 };
 
 NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
@@ -321,8 +321,8 @@ NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
 NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
 
 NTSTATUS midi_seq_lock(void *args) DECLSPEC_HIDDEN;
-NTSTATUS midi_in_lock(void *args) DECLSPEC_HIDDEN;
 NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
+NTSTATUS midi_handle_event(void *args) DECLSPEC_HIDDEN;
 
 extern unixlib_handle_t alsa_handle;
 
-- 
2.25.1




More information about the wine-devel mailing list