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(a)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(¬ify_mutex);
- if (notify) FIXME("Not yet handled\n");
+ if (notify) notify_buffer_add(notify);
else notify_quit = TRUE;
pthread_cond_signal(¬ify_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(¬ify, src, src - srcs, MIM_LONGDATA, (DWORD_PTR)hdr, current_time);
+ notify_post(¬ify);
+ }
+ }
+
+ 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(¬ify, src, src - srcs, MIM_DATA, data, current_time);
+ notify_post(¬ify);
+ }
+}
+
+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(¬ify_mutex);
- while (!notify_quit)
+ while (!notify_quit && notify_buffer_empty())
pthread_cond_wait(¬ify_cond, ¬ify_mutex);
*params->quit = notify_quit;
+ if (!notify_quit) notify_buffer_remove(params->notify);
pthread_mutex_unlock(¬ify_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, ¶ms);
if (quit) break;
+ if (notify.send_notify) notify_client(¬ify);
}
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