From 5e8a5fb754836c307c34870afa49f53a8ea8d8c9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 24 Aug 2021 11:36:30 +0200 Subject: [PATCH] rawmidi: hide the frame structure using a decoder function The frame structure should be hidden. Remove it and add snd_rawmidi_decode_frame0() which returns the timestamp and the midi chunk pointer to the application. BugLink: https://github.com/alsa-project/alsa-lib/issues/172 Signed-off-by: Jaroslav Kysela --- include/rawmidi.h | 22 ++-------------------- src/rawmidi/rawmidi.c | 35 +++++++++++++++++++++++++++++++++++ test/rawmidi.c | 37 +++++++++++++++++++++---------------- 3 files changed, 58 insertions(+), 36 deletions(-) diff --git a/include/rawmidi.h b/include/rawmidi.h index 5866d133..ae0b37ff 100644 --- a/include/rawmidi.h +++ b/include/rawmidi.h @@ -93,26 +93,6 @@ typedef enum _snd_rawmidi_framing { SND_RAWMIDI_FRAMING_TSTAMP = 1, } snd_rawmidi_framing_t; -#define SND_RAWMIDI_FRAME_TYPE_DEFAULT 0 - -#define SND_RAWMIDI_FRAMING_DATA_LENGTH 16 - -/** Incoming RawMidi bytes is put inside this container if tstamp type framing is enabled. */ -struct _snd_rawmidi_framing_tstamp { - /** - * For now, frame_type is always SND_RAWMIDI_FRAME_TYPE_DEFAULT. - * Midi 2.0 is expected to add new types here. - * Applications are expected to skip unknown frame types. - */ - uint8_t frame_type; - uint8_t length; /* number of valid bytes in data field */ - uint8_t reserved[2]; - uint32_t tv_nsec; /* nanoseconds */ - uint64_t tv_sec; /* seconds */ - uint8_t data[SND_RAWMIDI_FRAMING_DATA_LENGTH]; -} __attribute__((packed)); -typedef struct _snd_rawmidi_framing_tstamp snd_rawmidi_framing_tstamp_t; - int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode); int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, @@ -184,6 +164,8 @@ int snd_rawmidi_drain(snd_rawmidi_t *rmidi); int snd_rawmidi_drop(snd_rawmidi_t *rmidi); ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size); ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size); +ssize_t snd_rawmidi_decode_frame0(snd_rawmidi_t *rmidi, void *buffer, size_t size, + struct timespec *tstamp, void *data, size_t *data_size); const char *snd_rawmidi_name(snd_rawmidi_t *rmidi); snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rmidi); snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi); diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index ae4b2600..2a65c0cb 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -1075,6 +1075,41 @@ ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size) { assert(rawmidi); assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); + if ((rawmidi->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + size &= ~(sizeof(struct snd_rawmidi_framing_tstamp) - 1); assert(buffer || size == 0); return (rawmidi->ops->read)(rawmidi, buffer, size); } + +/** + * \brief decode the MIDI frame with timestamp + * \param rawmidi RawMidi handle + * \param buffer frame buffer with the frame stream + * \param size frame buffer size in bytes + * \param tstamp returned timestamp + * \param data returned pointer to the midi data + * \param data_size returned size of the midi data + * \return number of consumed bytes otherwise a negative error code + */ +ssize_t snd_rawmidi_decode_frame0(snd_rawmidi_t *rawmidi, void *buffer, size_t size, + struct timespec *tstamp, void *data, size_t *data_size) +{ + struct snd_rawmidi_framing_tstamp *f; + + assert(rawmidi && buffer && tstamp && data && data_size); + assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); + if (size < sizeof(*data)) + return 0; + if ((rawmidi->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) != SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + return -EINVAL; + f = buffer; + if (f->frame_type != 0) + return -EINVAL; + if (f->length == 0 || f->length > SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) + return -EINVAL; + tstamp->tv_sec = f->tv_sec; + tstamp->tv_nsec = f->tv_nsec; + *(void **)data = f->data; + *data_size = f->length; + return sizeof(*f); +} diff --git a/test/rawmidi.c b/test/rawmidi.c index 1090d44b..e7dd5832 100644 --- a/test/rawmidi.c +++ b/test/rawmidi.c @@ -179,27 +179,32 @@ int main(int argc,char** argv) } if (handle_in) { - unsigned char ch; - snd_rawmidi_framing_tstamp_t frame; + ssize_t ret, ret2; + unsigned char buf[1024]; while (!stop) { - if (clock_type != -1) { - snd_rawmidi_read(handle_in, &frame, sizeof(frame)); - if (verbose) { - int i; - if (frame.frame_type) { - fprintf(stderr, "read unknown frame %d", frame.frame_type); - continue; + ret = snd_rawmidi_read(handle_in, &buf, sizeof(buf)); + if (clock_type != -1 && ret > 0) { + unsigned char *ptr = buf; + while (ret > 0) { + struct timespec tstamp; + unsigned char *data; + size_t j, data_size; + ret2 = snd_rawmidi_decode_frame0(handle_in, ptr, ret, &tstamp, &data, &data_size); + if (ret2 <= 0) { + fprintf(stderr, "read unknown frame %zd\n", ret2); + break; } - fprintf(stderr, "read [%lld:%09d]", frame.tv_sec, frame.tv_nsec); - for (i = 0; i < frame.length; i++) - fprintf(stderr, " %02x", frame.data[i]); + ptr += ret2; + ret -= ret2; + fprintf(stderr, "read [%lld:%09lld]", (long long)tstamp.tv_sec, (long long)tstamp.tv_nsec); + for (j = 0; j < data_size; j++) + fprintf(stderr, " %02x", data[j]); fprintf(stderr, "\n"); } - } - else { - snd_rawmidi_read(handle_in,&ch,1); + } else { if (verbose) - fprintf(stderr,"read %02x\n",ch); + for (i = 0; i < ret; i++) + fprintf(stderr,"read %02x\n",buf[i]); } } }