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

Andrew Eikum aeikum at codeweavers.com
Thu Mar 24 14:05:37 CDT 2022


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Wed, Mar 23, 2022 at 08:16:55AM +0000, Huw Davies wrote:
> 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