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 <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2021-08-24 11:36:30 +02:00
parent 754c696aef
commit 5e8a5fb754
3 changed files with 58 additions and 36 deletions

View file

@ -93,26 +93,6 @@ typedef enum _snd_rawmidi_framing {
SND_RAWMIDI_FRAMING_TSTAMP = 1, SND_RAWMIDI_FRAMING_TSTAMP = 1,
} snd_rawmidi_framing_t; } 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, int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
const char *name, int mode); const char *name, int mode);
int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, 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); 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_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_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); const char *snd_rawmidi_name(snd_rawmidi_t *rmidi);
snd_rawmidi_type_t snd_rawmidi_type(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); snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi);

View file

@ -1075,6 +1075,41 @@ ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size)
{ {
assert(rawmidi); assert(rawmidi);
assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); 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); assert(buffer || size == 0);
return (rawmidi->ops->read)(rawmidi, buffer, size); 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);
}

View file

@ -179,27 +179,32 @@ int main(int argc,char** argv)
} }
if (handle_in) { if (handle_in) {
unsigned char ch; ssize_t ret, ret2;
snd_rawmidi_framing_tstamp_t frame; unsigned char buf[1024];
while (!stop) { while (!stop) {
if (clock_type != -1) { ret = snd_rawmidi_read(handle_in, &buf, sizeof(buf));
snd_rawmidi_read(handle_in, &frame, sizeof(frame)); if (clock_type != -1 && ret > 0) {
if (verbose) { unsigned char *ptr = buf;
int i; while (ret > 0) {
if (frame.frame_type) { struct timespec tstamp;
fprintf(stderr, "read unknown frame %d", frame.frame_type); unsigned char *data;
continue; 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); ptr += ret2;
for (i = 0; i < frame.length; i++) ret -= ret2;
fprintf(stderr, " %02x", frame.data[i]); 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"); fprintf(stderr, "\n");
} }
} } else {
else {
snd_rawmidi_read(handle_in,&ch,1);
if (verbose) if (verbose)
fprintf(stderr,"read %02x\n",ch); for (i = 0; i < ret; i++)
fprintf(stderr,"read %02x\n",buf[i]);
} }
} }
} }