[PATCH 5/6] winealsa: Add helpers to handle regular and sysex events.

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


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

On Wed, Mar 23, 2022 at 08:16:54AM +0000, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at codeweavers.com>
> ---
>  dlls/winealsa.drv/midi.c | 207 ++++++++++++++++++++-------------------
>  1 file changed, 104 insertions(+), 103 deletions(-)
> 
> diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
> index ca31def8d16..77ab9720bcc 100644
> --- a/dlls/winealsa.drv/midi.c
> +++ b/dlls/winealsa.drv/midi.c
> @@ -170,114 +170,115 @@ 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)
>  {
> -    WORD wDevID;
> +    struct midi_src *src;
>  
>      /* Find the target device */
> -    for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
> -        if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
> -            break;
> -    if ((wDevID == MIDM_NumDevs) || (MidiInDev[wDevID].state != 1))
> -        FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
> -    else {
> -        DWORD dwTime, toSend = 0;
> -        int value = 0;
> -        /* FIXME: Should use ev->time instead for better accuracy */
> -        dwTime = GetTickCount() - MidiInDev[wDevID].startTime;
> -        TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
> -        switch(ev->type)
> -        {
> -        case SND_SEQ_EVENT_NOTEOFF:
> -            toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
> -            break;
> -        case SND_SEQ_EVENT_NOTEON:
> -            toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
> -            break;
> -        case SND_SEQ_EVENT_KEYPRESS:
> -            toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
> +    for (src = MidiInDev; src < MidiInDev + MIDM_NumDevs; src++)
> +        if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port))
>              break;
> -        case SND_SEQ_EVENT_CONTROLLER:
> -            toSend = (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;
> -            toSend = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
> -            break;
> -        case SND_SEQ_EVENT_PGMCHANGE:
> -            toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
> -            break;
> -        case SND_SEQ_EVENT_CHANPRESS:
> -            toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
> -            break;
> -        case SND_SEQ_EVENT_CLOCK:
> -            toSend = 0xF8;
> -            break;
> -        case SND_SEQ_EVENT_START:
> -            toSend = 0xFA;
> -            break;
> -        case SND_SEQ_EVENT_CONTINUE:
> -            toSend = 0xFB;
> -            break;
> -        case SND_SEQ_EVENT_STOP:
> -            toSend = 0xFC;
> -            break;
> -        case SND_SEQ_EVENT_SONGPOS:
> -            toSend = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS;
> -            break;
> -        case SND_SEQ_EVENT_SONGSEL:
> -          toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT;
> -            break;
> -        case SND_SEQ_EVENT_RESET:
> -            toSend = 0xFF;
> -            break;
> -        case SND_SEQ_EVENT_QFRAME:
> -          toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER;
> -            break;
> -        case SND_SEQ_EVENT_SYSEX:
> -            {
> -                int pos = 0;
> -                int len = ev->data.ext.len;
> -                LPBYTE ptr = ev->data.ext.ptr;
> -                LPMIDIHDR lpMidiHdr;
> -
> -                in_buffer_lock();
> -                while (len) {
> -                    if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
> -                        int copylen = min(len, lpMidiHdr->dwBufferLength - lpMidiHdr->dwBytesRecorded);
> -                        memcpy(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded, ptr + pos, copylen);
> -                        lpMidiHdr->dwBytesRecorded += copylen;
> -                        len -= copylen;
> -                        pos += copylen;
> -                        /* We check if we reach the end of buffer or the end of sysex before notifying
> -                         * to handle the case where ALSA split the sysex into several events */
> -                        if ((lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) ||
> -                            (*(BYTE*)(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded - 1) == 0xF7)) {
> -                            MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
> -                            lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
> -                            lpMidiHdr->dwFlags |= MHDR_DONE;
> -                            MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
> -                        }
> -                    } else {
> -                        FIXME("Sysex data received but no buffer to store it!\n");
> -                        break;
> -                    }
> -                }
> -                in_buffer_unlock();
> -            }
> -            break;
> -        case SND_SEQ_EVENT_SENSING:
> -            /* Noting to do */
> -            break;
> -        default:
> -            FIXME("Unhandled event received, type = %x\n", ev->type);
> -            break;
> -        }
> -        if (toSend != 0) {
> -            TRACE("Received event %08x from %d:%d\n", toSend, ev->source.client, ev->source.port);
> -            MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime);
> -        }
> -    }
> +    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)
> -- 
> 2.25.1
> 
> 



More information about the wine-devel mailing list