1 /**
2 * \file rawmidi/rawmidi.c
3 * \brief RawMidi Interface
4 * \author Jaroslav Kysela <perex@perex.cz>
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
7 *
8 * See the \ref rawmidi page for more details.
9 */
10 /*
11 *
12 * This library is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as
14 * published by the Free Software Foundation; either version 2.1 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 *
26 */
27
28 /*! \page rawmidi RawMidi interface
29
30 <P>RawMidi Interface is designed to write or read raw (unchanged) MIDI
31 data over the MIDI line without any timestamps defined in interface. MIDI
32 stands Musical Instrument Digital Interface and more information about
33 this standard can be found at http://www.midi.org.
34
35 \section rawmidi_general_overview General overview
36
37 The rawmidi implementation uses ring buffers to store outgoing and incoming
38 MIDI stream. The buffer size is tunable and drivers report underruns for incoming
39 stream as well.
40
41 \section rawmidi_open Open handling
42
43 RawMidi devices are opened exclusively for a selected direction.
44 While more than one process may not open a given MIDI device in the same
45 direction simultaneously, separate processes may open a single MIDI device
46 in different directions (i.e. process one opens a MIDI device in write
47 direction and process two opens the same device in read direction).
48
49 \subsection rawmidi_open_nonblock Nonblocking open (flag)
50
51 Using #SND_RAWMIDI_NONBLOCK flag for snd_rawmidi_open() or snd_rawmidi_open_lconf()
52 instruct device driver to return the -EBUSY error when device is already occupied
53 with another application. This flag also changes behaviour of snd_rawmidi_write()
54 and snd_rawmidi_read() returning -EAGAIN when no more bytes can be processed.
55
56 Note: In opposite (default) behaviour, application is blocked until device resources
57 are free.
58
59 \subsection rawmidi_open_append Append open (flag)
60
61 Using #SND_RAWMIDI_APPEND flag (output only) instruct device driver to append
62 contents of written buffer - passed by snd_rawmidi_write() - atomically
63 to output ring buffer in the kernel space. This flag also means that device
64 is not opened exclusively, so more applications can share given rawmidi device.
65 Note that applications must send the whole MIDI message including the running status,
66 because another writing application might break the MIDI message in the output
67 buffer.
68
69 \subsection rawmidi_open_sync Sync open (flag)
70
71 Using #SND_RAWMIDI_SYNC flag (output only) assures that the contents of output
72 buffer specified using snd_rawmidi_write() is always drained before the function
73 exits. This behaviour is same like 'snd_rawmidi_write() followed by
74 snd_rawmidi_drain() immediately'.
75
76 \subsection rawmidi_io I/O handling
77
78 There is only standard read/write access to device internal ring buffer. Use
79 snd_rawmidi_read() and snd_rawmidi_write() functions to obtain / write MIDI bytes.
80
81 \subsection rawmidi_dev_names RawMidi naming conventions
82
83 The ALSA library uses a generic string representation for names of devices.
84 The devices might be virtual, physical or a mix of both. The generic string
85 is passed to \link ::snd_rawmidi_open() \endlink or \link ::snd_rawmidi_open_lconf() \endlink.
86 It contains two parts: device name and arguments. Devices and arguments are described
87 in configuration files. The usual place for default definitions is at /usr/share/alsa/alsa.conf.
88
89 \subsection rawmidi_dev_names_default
90
91 The default device is equal to hw device. The defaults are used:
92
93 defaults.rawmidi.card 0
94 defaults.rawmidi.device 0
95 defaults.rawmidi.subdevice -1
96
97 These defaults can be freely overwritten in local configuration files.
98
99 Example:
100
101 \code
102 default
103 \endcode
104
105 \subsection rawmidi_dev_names_hw HW device
106
107 The hw device description uses the hw plugin. The three arguments (in order: CARD,DEV,SUBDEV)
108 specify card number or identifier, device number and subdevice number (-1 means any).
109
110 Example:
111
112 \code
113 hw
114 hw:0
115 hw:0,0
116 hw:supersonic,1
117 hw:soundwave,1,2
118 hw:DEV=1,CARD=soundwave,SUBDEV=2
119 \endcode
120
121 \section read_mode Read mode
122
123 Optionally, incoming rawmidi bytes can be marked with timestamps. The library hides
124 the kernel implementation (linux kernel 5.14+) and exports
125 the \link ::snd_rawmidi_tread() \endlink function which returns the
126 midi bytes marked with the identical timestamp in one iteration.
127
128 The timestamping is available only on input streams.
129
130 \section rawmidi_examples Examples
131
132 The full featured examples with cross-links:
133
134 \par Simple input/output test program
135 \ref example_test_rawmidi "example code"
136 \par
137 This example shows open and read/write rawmidi operations.
138
139 */
140
141 /**
142 * \example ../test/rawmidi.c
143 * \anchor example_test_rawmidi
144 */
145
146 #include <stdio.h>
147 #include <stdlib.h>
148 #include <stdarg.h>
149 #include <unistd.h>
150 #include <string.h>
151 #include "rawmidi_local.h"
152
153 /**
154 * \brief setup the default parameters
155 * \param rawmidi RawMidi handle
156 * \param params pointer to a snd_rawmidi_params_t structure
157 * \return 0 on success otherwise a negative error code
158 */
snd_rawmidi_params_default(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)159 static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params)
160 {
161 assert(rawmidi);
162 assert(params);
163 params->buffer_size = page_size();
164 params->avail_min = 1;
165 params->no_active_sensing = 1;
166 params->mode = 0;
167 memset(params->reserved, 0, sizeof(params->reserved));
168 return 0;
169 }
170
snd_rawmidi_open_conf(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,const char * name,snd_config_t * rawmidi_root,snd_config_t * rawmidi_conf,int mode)171 static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
172 const char *name, snd_config_t *rawmidi_root,
173 snd_config_t *rawmidi_conf, int mode)
174 {
175 const char *str;
176 char buf[256];
177 int err;
178 snd_config_t *conf, *type_conf = NULL;
179 snd_config_iterator_t i, next;
180 snd_rawmidi_params_t params;
181 const char *id;
182 const char *lib = NULL, *open_name = NULL;
183 int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **,
184 const char *, snd_config_t *, snd_config_t *, int) = NULL;
185 #ifndef PIC
186 extern void *snd_rawmidi_open_symbols(void);
187 #endif
188 if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
189 if (name)
190 SNDERR("Invalid type for RAWMIDI %s definition", name);
191 else
192 SNDERR("Invalid type for RAWMIDI definition");
193 return -EINVAL;
194 }
195 err = snd_config_search(rawmidi_conf, "type", &conf);
196 if (err < 0) {
197 SNDERR("type is not defined");
198 return err;
199 }
200 err = snd_config_get_id(conf, &id);
201 if (err < 0) {
202 SNDERR("unable to get id");
203 return err;
204 }
205 err = snd_config_get_string(conf, &str);
206 if (err < 0) {
207 SNDERR("Invalid type for %s", id);
208 return err;
209 }
210 err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf);
211 if (err >= 0) {
212 if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
213 SNDERR("Invalid type for RAWMIDI type %s definition", str);
214 err = -EINVAL;
215 goto _err;
216 }
217 snd_config_for_each(i, next, type_conf) {
218 snd_config_t *n = snd_config_iterator_entry(i);
219 const char *id;
220 if (snd_config_get_id(n, &id) < 0)
221 continue;
222 if (strcmp(id, "comment") == 0)
223 continue;
224 if (strcmp(id, "lib") == 0) {
225 err = snd_config_get_string(n, &lib);
226 if (err < 0) {
227 SNDERR("Invalid type for %s", id);
228 goto _err;
229 }
230 continue;
231 }
232 if (strcmp(id, "open") == 0) {
233 err = snd_config_get_string(n, &open_name);
234 if (err < 0) {
235 SNDERR("Invalid type for %s", id);
236 goto _err;
237 }
238 continue;
239 }
240 SNDERR("Unknown field %s", id);
241 err = -EINVAL;
242 goto _err;
243 }
244 }
245 if (!open_name) {
246 open_name = buf;
247 snprintf(buf, sizeof(buf), "_snd_rawmidi_%s_open", str);
248 }
249 #ifndef PIC
250 snd_rawmidi_open_symbols();
251 #endif
252 open_func = snd_dlobj_cache_get2(lib, open_name,
253 SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1);
254 if (!open_func) {
255 err = -ENXIO;
256 goto _err;
257 }
258 if (type_conf)
259 snd_config_delete(type_conf);
260 err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
261 if (err < 0)
262 goto _err;
263 if (inputp) {
264 (*inputp)->open_func = open_func;
265 snd_rawmidi_params_default(*inputp, ¶ms);
266 err = snd_rawmidi_params(*inputp, ¶ms);
267 assert(err >= 0);
268 }
269 if (outputp) {
270 (*outputp)->open_func = open_func;
271 snd_rawmidi_params_default(*outputp, ¶ms);
272 err = snd_rawmidi_params(*outputp, ¶ms);
273 assert(err >= 0);
274 }
275 return 0;
276
277 _err:
278 if (open_func)
279 snd_dlobj_cache_put(open_func);
280 if (type_conf)
281 snd_config_delete(type_conf);
282 return err;
283 }
284
snd_rawmidi_open_noupdate(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,snd_config_t * root,const char * name,int mode)285 static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
286 snd_config_t *root, const char *name, int mode)
287 {
288 int err;
289 snd_config_t *rawmidi_conf;
290 err = snd_config_search_definition(root, "rawmidi", name, &rawmidi_conf);
291 if (err < 0) {
292 SNDERR("Unknown RawMidi %s", name);
293 return err;
294 }
295 err = snd_rawmidi_open_conf(inputp, outputp, name, root, rawmidi_conf, mode);
296 snd_config_delete(rawmidi_conf);
297 return err;
298 }
299
300 /**
301 * \brief Opens a new connection to the RawMidi interface.
302 * \param inputp Returned input handle (NULL if not wanted)
303 * \param outputp Returned output handle (NULL if not wanted)
304 * \param name ASCII identifier of the RawMidi handle
305 * \param mode Open mode
306 * \return 0 on success otherwise a negative error code
307 *
308 * Opens a new connection to the RawMidi interface specified with
309 * an ASCII identifier and mode.
310 */
snd_rawmidi_open(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,const char * name,int mode)311 int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
312 const char *name, int mode)
313 {
314 snd_config_t *top;
315 int err;
316
317 assert((inputp || outputp) && name);
318 if (_snd_is_ucm_device(name)) {
319 name = uc_mgr_alibcfg_by_device(&top, name);
320 if (name == NULL)
321 return -ENODEV;
322 } else {
323 err = snd_config_update_ref(&top);
324 if (err < 0)
325 return err;
326 }
327 err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode);
328 snd_config_unref(top);
329 return err;
330 }
331
332 /**
333 * \brief Opens a new connection to the RawMidi interface using local configuration
334 * \param inputp Returned input handle (NULL if not wanted)
335 * \param outputp Returned output handle (NULL if not wanted)
336 * \param name ASCII identifier of the RawMidi handle
337 * \param mode Open mode
338 * \param lconf Local configuration
339 * \return 0 on success otherwise a negative error code
340 *
341 * Opens a new connection to the RawMidi interface specified with
342 * an ASCII identifier and mode.
343 */
snd_rawmidi_open_lconf(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,const char * name,int mode,snd_config_t * lconf)344 int snd_rawmidi_open_lconf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
345 const char *name, int mode, snd_config_t *lconf)
346 {
347 assert((inputp || outputp) && name && lconf);
348 return snd_rawmidi_open_noupdate(inputp, outputp, lconf, name, mode);
349 }
350
351 /**
352 * \brief close RawMidi handle
353 * \param rawmidi RawMidi handle
354 * \return 0 on success otherwise a negative error code
355 *
356 * Closes the specified RawMidi handle and frees all associated
357 * resources.
358 */
snd_rawmidi_close(snd_rawmidi_t * rawmidi)359 int snd_rawmidi_close(snd_rawmidi_t *rawmidi)
360 {
361 int err;
362 assert(rawmidi);
363 err = rawmidi->ops->close(rawmidi);
364 free(rawmidi->name);
365 if (rawmidi->open_func)
366 snd_dlobj_cache_put(rawmidi->open_func);
367 free(rawmidi);
368 return err;
369 }
370
371 /**
372 * \brief get identifier of RawMidi handle
373 * \param rawmidi a RawMidi handle
374 * \return ascii identifier of RawMidi handle
375 *
376 * Returns the ASCII identifier of given RawMidi handle. It's the same
377 * identifier specified in snd_rawmidi_open().
378 */
snd_rawmidi_name(snd_rawmidi_t * rawmidi)379 const char *snd_rawmidi_name(snd_rawmidi_t *rawmidi)
380 {
381 assert(rawmidi);
382 return rawmidi->name;
383 }
384
385 /**
386 * \brief get type of RawMidi handle
387 * \param rawmidi a RawMidi handle
388 * \return type of RawMidi handle
389 *
390 * Returns the type #snd_rawmidi_type_t of given RawMidi handle.
391 */
snd_rawmidi_type(snd_rawmidi_t * rawmidi)392 snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rawmidi)
393 {
394 assert(rawmidi);
395 return rawmidi->type;
396 }
397
398 /**
399 * \brief get stream (direction) of RawMidi handle
400 * \param rawmidi a RawMidi handle
401 * \return stream of RawMidi handle
402 *
403 * Returns the stream #snd_rawmidi_stream_t of given RawMidi handle.
404 */
snd_rawmidi_stream(snd_rawmidi_t * rawmidi)405 snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi)
406 {
407 assert(rawmidi);
408 return rawmidi->stream;
409 }
410
411 /**
412 * \brief get count of poll descriptors for RawMidi handle
413 * \param rawmidi RawMidi handle
414 * \return count of poll descriptors
415 */
snd_rawmidi_poll_descriptors_count(snd_rawmidi_t * rawmidi)416 int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rawmidi)
417 {
418 assert(rawmidi);
419 return 1;
420 }
421
422 /**
423 * \brief get poll descriptors
424 * \param rawmidi RawMidi handle
425 * \param pfds array of poll descriptors
426 * \param space space in the poll descriptor array
427 * \return count of filled descriptors
428 */
snd_rawmidi_poll_descriptors(snd_rawmidi_t * rawmidi,struct pollfd * pfds,unsigned int space)429 int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int space)
430 {
431 assert(rawmidi);
432 if (space >= 1) {
433 pfds->fd = rawmidi->poll_fd;
434 pfds->events = rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL);
435 return 1;
436 }
437 return 0;
438 }
439
440 /**
441 * \brief get returned events from poll descriptors
442 * \param rawmidi rawmidi RawMidi handle
443 * \param pfds array of poll descriptors
444 * \param nfds count of poll descriptors
445 * \param revents returned events
446 * \return zero if success, otherwise a negative error code
447 */
snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t * rawmidi,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)448 int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
449 {
450 assert(rawmidi && pfds && revents);
451 if (nfds == 1) {
452 *revents = pfds->revents;
453 return 0;
454 }
455 return -EINVAL;
456 }
457
458 /**
459 * \brief set nonblock mode
460 * \param rawmidi RawMidi handle
461 * \param nonblock 0 = block, 1 = nonblock mode
462 * \return 0 on success otherwise a negative error code
463 *
464 * The nonblock mode cannot be used when the stream is in
465 * #SND_RAWMIDI_APPEND state.
466 */
snd_rawmidi_nonblock(snd_rawmidi_t * rawmidi,int nonblock)467 int snd_rawmidi_nonblock(snd_rawmidi_t *rawmidi, int nonblock)
468 {
469 int err;
470 assert(rawmidi);
471 assert(!(rawmidi->mode & SND_RAWMIDI_APPEND));
472 if ((err = rawmidi->ops->nonblock(rawmidi, nonblock)) < 0)
473 return err;
474 if (nonblock)
475 rawmidi->mode |= SND_RAWMIDI_NONBLOCK;
476 else
477 rawmidi->mode &= ~SND_RAWMIDI_NONBLOCK;
478 return 0;
479 }
480
481 /**
482 * \brief get size of the snd_rawmidi_info_t structure in bytes
483 * \return size of the snd_rawmidi_info_t structure in bytes
484 */
snd_rawmidi_info_sizeof()485 size_t snd_rawmidi_info_sizeof()
486 {
487 return sizeof(snd_rawmidi_info_t);
488 }
489
490 /**
491 * \brief allocate a new snd_rawmidi_info_t structure
492 * \param info returned pointer
493 * \return 0 on success otherwise a negative error code if fails
494 *
495 * Allocates a new snd_rawmidi_params_t structure using the standard
496 * malloc C library function.
497 */
snd_rawmidi_info_malloc(snd_rawmidi_info_t ** info)498 int snd_rawmidi_info_malloc(snd_rawmidi_info_t **info)
499 {
500 assert(info);
501 *info = calloc(1, sizeof(snd_rawmidi_info_t));
502 if (!*info)
503 return -ENOMEM;
504 return 0;
505 }
506
507 /**
508 * \brief frees the snd_rawmidi_info_t structure
509 * \param info pointer to the snd_rawmidi_info_t structure to free
510 *
511 * Frees the given snd_rawmidi_params_t structure using the standard
512 * free C library function.
513 */
snd_rawmidi_info_free(snd_rawmidi_info_t * info)514 void snd_rawmidi_info_free(snd_rawmidi_info_t *info)
515 {
516 assert(info);
517 free(info);
518 }
519
520 /**
521 * \brief copy one snd_rawmidi_info_t structure to another
522 * \param dst destination snd_rawmidi_info_t structure
523 * \param src source snd_rawmidi_info_t structure
524 */
snd_rawmidi_info_copy(snd_rawmidi_info_t * dst,const snd_rawmidi_info_t * src)525 void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src)
526 {
527 assert(dst && src);
528 *dst = *src;
529 }
530
531 /**
532 * \brief get rawmidi device number
533 * \param info pointer to a snd_rawmidi_info_t structure
534 * \return rawmidi device number
535 */
snd_rawmidi_info_get_device(const snd_rawmidi_info_t * info)536 unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *info)
537 {
538 assert(info);
539 return info->device;
540 }
541
542 /**
543 * \brief get rawmidi subdevice number
544 * \param info pointer to a snd_rawmidi_info_t structure
545 * \return rawmidi subdevice number
546 */
snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t * info)547 unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *info)
548 {
549 assert(info);
550 return info->subdevice;
551 }
552
553 /**
554 * \brief get rawmidi stream identification
555 * \param info pointer to a snd_rawmidi_info_t structure
556 * \return rawmidi stream identification
557 */
snd_rawmidi_info_get_stream(const snd_rawmidi_info_t * info)558 snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *info)
559 {
560 assert(info);
561 return info->stream;
562 }
563
564 /**
565 * \brief get rawmidi card number
566 * \param info pointer to a snd_rawmidi_info_t structure
567 * \return rawmidi card number
568 */
snd_rawmidi_info_get_card(const snd_rawmidi_info_t * info)569 int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *info)
570 {
571 assert(info);
572 return info->card;
573 }
574
575 /**
576 * \brief get rawmidi flags
577 * \param info pointer to a snd_rawmidi_info_t structure
578 * \return rawmidi flags
579 */
snd_rawmidi_info_get_flags(const snd_rawmidi_info_t * info)580 unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *info)
581 {
582 assert(info);
583 return info->flags;
584 }
585
586 /**
587 * \brief get rawmidi hardware driver identifier
588 * \param info pointer to a snd_rawmidi_info_t structure
589 * \return rawmidi hardware driver identifier
590 */
snd_rawmidi_info_get_id(const snd_rawmidi_info_t * info)591 const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *info)
592 {
593 assert(info);
594 return (const char *)info->id;
595 }
596
597 /**
598 * \brief get rawmidi hardware driver name
599 * \param info pointer to a snd_rawmidi_info_t structure
600 * \return rawmidi hardware driver name
601 */
snd_rawmidi_info_get_name(const snd_rawmidi_info_t * info)602 const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *info)
603 {
604 assert(info);
605 return (const char *)info->name;
606 }
607
608 /**
609 * \brief get rawmidi subdevice name
610 * \param info pointer to a snd_rawmidi_info_t structure
611 * \return rawmidi subdevice name
612 */
snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t * info)613 const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *info)
614 {
615 assert(info);
616 return (const char *)info->subname;
617 }
618
619 /**
620 * \brief get rawmidi count of subdevices
621 * \param info pointer to a snd_rawmidi_info_t structure
622 * \return rawmidi count of subdevices
623 */
snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t * info)624 unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *info)
625 {
626 assert(info);
627 return info->subdevices_count;
628 }
629
630 /**
631 * \brief get rawmidi available count of subdevices
632 * \param info pointer to a snd_rawmidi_info_t structure
633 * \return rawmidi available count of subdevices
634 */
snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t * info)635 unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *info)
636 {
637 assert(info);
638 return info->subdevices_avail;
639 }
640
641 /**
642 * \brief set rawmidi device number
643 * \param info pointer to a snd_rawmidi_info_t structure
644 * \param val device number
645 */
snd_rawmidi_info_set_device(snd_rawmidi_info_t * info,unsigned int val)646 void snd_rawmidi_info_set_device(snd_rawmidi_info_t *info, unsigned int val)
647 {
648 assert(info);
649 info->device = val;
650 }
651
652 /**
653 * \brief set rawmidi subdevice number
654 * \param info pointer to a snd_rawmidi_info_t structure
655 * \param val subdevice number
656 */
snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t * info,unsigned int val)657 void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *info, unsigned int val)
658 {
659 assert(info);
660 info->subdevice = val;
661 }
662
663 /**
664 * \brief set rawmidi stream identifier
665 * \param info pointer to a snd_rawmidi_info_t structure
666 * \param val rawmidi stream identifier
667 */
snd_rawmidi_info_set_stream(snd_rawmidi_info_t * info,snd_rawmidi_stream_t val)668 void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *info, snd_rawmidi_stream_t val)
669 {
670 assert(info);
671 info->stream = val;
672 }
673
674 /**
675 * \brief get information about RawMidi handle
676 * \param rawmidi RawMidi handle
677 * \param info pointer to a snd_rawmidi_info_t structure to be filled
678 * \return 0 on success otherwise a negative error code
679 */
snd_rawmidi_info(snd_rawmidi_t * rawmidi,snd_rawmidi_info_t * info)680 int snd_rawmidi_info(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t * info)
681 {
682 assert(rawmidi);
683 assert(info);
684 return rawmidi->ops->info(rawmidi, info);
685 }
686
687 /**
688 * \brief get size of the snd_rawmidi_params_t structure in bytes
689 * \return size of the snd_rawmidi_params_t structure in bytes
690 */
snd_rawmidi_params_sizeof()691 size_t snd_rawmidi_params_sizeof()
692 {
693 return sizeof(snd_rawmidi_params_t);
694 }
695
696 /**
697 * \brief allocate the snd_rawmidi_params_t structure
698 * \param params returned pointer
699 * \return 0 on success otherwise a negative error code if fails
700 *
701 * Allocates a new snd_rawmidi_params_t structure using the standard
702 * malloc C library function.
703 */
snd_rawmidi_params_malloc(snd_rawmidi_params_t ** params)704 int snd_rawmidi_params_malloc(snd_rawmidi_params_t **params)
705 {
706 assert(params);
707 *params = calloc(1, sizeof(snd_rawmidi_params_t));
708 if (!*params)
709 return -ENOMEM;
710 return 0;
711 }
712
713 /**
714 * \brief frees the snd_rawmidi_params_t structure
715 * \param params pointer to the #snd_rawmidi_params_t structure to free
716 *
717 * Frees the given snd_rawmidi_params_t structure using the standard
718 * free C library function.
719 */
snd_rawmidi_params_free(snd_rawmidi_params_t * params)720 void snd_rawmidi_params_free(snd_rawmidi_params_t *params)
721 {
722 assert(params);
723 free(params);
724 }
725
726 /**
727 * \brief copy one snd_rawmidi_params_t structure to another
728 * \param dst destination snd_rawmidi_params_t structure
729 * \param src source snd_rawmidi_params_t structure
730 */
snd_rawmidi_params_copy(snd_rawmidi_params_t * dst,const snd_rawmidi_params_t * src)731 void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src)
732 {
733 assert(dst && src);
734 *dst = *src;
735 }
736
737 /**
738 * \brief set rawmidi I/O ring buffer size
739 * \param rawmidi RawMidi handle
740 * \param params pointer to a snd_rawmidi_params_t structure
741 * \param val size in bytes
742 * \return 0 on success otherwise a negative error code
743 */
744 #ifndef DOXYGEN
snd_rawmidi_params_set_buffer_size(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,size_t val)745 int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val)
746 #else
747 int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val)
748 #endif
749 {
750 assert(rawmidi && params);
751 assert(val > params->avail_min);
752 params->buffer_size = val;
753 return 0;
754 }
755
756 /**
757 * \brief get rawmidi I/O ring buffer size
758 * \param params pointer to a snd_rawmidi_params_t structure
759 * \return size of rawmidi I/O ring buffer in bytes
760 */
snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t * params)761 size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params)
762 {
763 assert(params);
764 return params->buffer_size;
765 }
766
767 /**
768 * \brief set minimum available bytes in rawmidi I/O ring buffer for wakeup
769 * \param rawmidi RawMidi handle
770 * \param params pointer to a snd_rawmidi_params_t structure
771 * \param val desired value
772 */
773 #ifndef DOXYGEN
snd_rawmidi_params_set_avail_min(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,size_t val)774 int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val)
775 #else
776 int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val)
777 #endif
778 {
779 assert(rawmidi && params);
780 assert(val < params->buffer_size);
781 params->avail_min = val;
782 return 0;
783 }
784
785 /**
786 * \brief get minimum available bytes in rawmidi I/O ring buffer for wakeup
787 * \param params pointer to snd_rawmidi_params_t structure
788 * \return minimum available bytes
789 */
snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t * params)790 size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params)
791 {
792 assert(params);
793 return params->avail_min;
794 }
795
796 /**
797 * \brief set no-active-sensing action on snd_rawmidi_close()
798 * \param rawmidi RawMidi handle
799 * \param params pointer to snd_rawmidi_params_t structure
800 * \param val value: 0 = enable to send the active sensing message, 1 = disable
801 * \return 0 on success otherwise a negative error code
802 */
803 #ifndef DOXYGEN
snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,int val)804 int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, int val)
805 #else
806 int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, int val)
807 #endif
808 {
809 assert(rawmidi && params);
810 params->no_active_sensing = val;
811 return 0;
812 }
813
814 /**
815 * \brief get no-active-sensing action status
816 * \param params pointer to snd_rawmidi_params_t structure
817 * \return the current status (0 = enable, 1 = disable the active sensing message)
818 */
snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t * params)819 int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params)
820 {
821 assert(params);
822 return params->no_active_sensing;
823 }
824
825 /**
826 * \brief set read mode
827 * \param rawmidi RawMidi handle
828 * \param params pointer to snd_rawmidi_params_t structure
829 * \param val type of read_mode
830 * \return 0 on success, otherwise a negative error code.
831 *
832 * Notable error codes:
833 * -EINVAL - "val" is invalid
834 * -ENOTSUP - mode is not supported
835 *
836 */
snd_rawmidi_params_set_read_mode(const snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params,snd_rawmidi_read_mode_t val)837 int snd_rawmidi_params_set_read_mode(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_read_mode_t val)
838 {
839 unsigned int framing;
840 assert(rawmidi && params);
841
842 switch (val) {
843 case SND_RAWMIDI_READ_STANDARD:
844 framing = SNDRV_RAWMIDI_MODE_FRAMING_NONE;
845 break;
846 case SND_RAWMIDI_READ_TSTAMP:
847 if (rawmidi->ops->tread == NULL)
848 return -ENOTSUP;
849 framing = SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP;
850 break;
851 default:
852 return -EINVAL;
853 }
854
855 if (framing != SNDRV_RAWMIDI_MODE_FRAMING_NONE &&
856 (rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
857 return -ENOTSUP;
858 params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_FRAMING_MASK) | framing;
859 return 0;
860 }
861
862 /**
863 * \brief get current read mode
864 * \param params pointer to snd_rawmidi_params_t structure
865 * \return the current read mode (see enum)
866 */
snd_rawmidi_params_get_read_mode(const snd_rawmidi_params_t * params)867 snd_rawmidi_read_mode_t snd_rawmidi_params_get_read_mode(const snd_rawmidi_params_t *params)
868 {
869 unsigned int framing;
870
871 assert(params);
872 framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
873 if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
874 return SND_RAWMIDI_READ_TSTAMP;
875 return SND_RAWMIDI_READ_STANDARD;
876 }
877
878 /**
879 * \brief sets clock type for tstamp type framing
880 * \param rawmidi RawMidi handle
881 * \param params pointer to snd_rawmidi_params_t structure
882 * \param val one of the SND_RAWMIDI_CLOCK_* constants
883 * \return 0 on success, otherwise a negative error code.
884 *
885 * Notable error codes:
886 * -EINVAL - "val" is invalid
887 * -ENOTSUP - Kernel is too old to support framing.
888 *
889 */
snd_rawmidi_params_set_clock_type(const snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params,snd_rawmidi_clock_t val)890 int snd_rawmidi_params_set_clock_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_clock_t val)
891 {
892 assert(rawmidi && params);
893 if (val > SNDRV_RAWMIDI_MODE_CLOCK_MASK >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT)
894 return -EINVAL;
895 if (val != SNDRV_RAWMIDI_MODE_CLOCK_NONE &&
896 (rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
897 return -ENOTSUP;
898 params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_CLOCK_MASK) + (val << SNDRV_RAWMIDI_MODE_CLOCK_SHIFT);
899 return 0;
900 }
901
902 /**
903 * \brief get current clock type (for tstamp type framing)
904 * \param params pointer to snd_rawmidi_params_t structure
905 * \return the current clock type (one of the SND_RAWMIDI_CLOCK_* constants)
906 */
snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t * params)907 snd_rawmidi_clock_t snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t *params)
908 {
909 assert(params);
910 return (params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK) >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT;
911 }
912
913
914 /**
915 * \brief set parameters about rawmidi stream
916 * \param rawmidi RawMidi handle
917 * \param params pointer to a snd_rawmidi_params_t structure to be filled
918 * \return 0 on success otherwise a negative error code
919 */
snd_rawmidi_params(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)920 int snd_rawmidi_params(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t * params)
921 {
922 int err;
923 assert(rawmidi);
924 assert(params);
925 err = rawmidi->ops->params(rawmidi, params);
926 if (err < 0)
927 return err;
928 rawmidi->buffer_size = params->buffer_size;
929 rawmidi->avail_min = params->avail_min;
930 rawmidi->no_active_sensing = params->no_active_sensing;
931 rawmidi->params_mode = rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) ? 0 : params->mode;
932 return 0;
933 }
934
935 /**
936 * \brief get current parameters about rawmidi stream
937 * \param rawmidi RawMidi handle
938 * \param params pointer to a snd_rawmidi_params_t structure to be filled
939 * \return 0 on success otherwise a negative error code
940 */
snd_rawmidi_params_current(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)941 int snd_rawmidi_params_current(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params)
942 {
943 assert(rawmidi);
944 assert(params);
945 params->buffer_size = rawmidi->buffer_size;
946 params->avail_min = rawmidi->avail_min;
947 params->no_active_sensing = rawmidi->no_active_sensing;
948 params->mode = rawmidi->params_mode;
949 return 0;
950 }
951
952 /**
953 * \brief get size of the snd_rawmidi_status_t structure in bytes
954 * \return size of the snd_rawmidi_status_t structure in bytes
955 */
snd_rawmidi_status_sizeof()956 size_t snd_rawmidi_status_sizeof()
957 {
958 return sizeof(snd_rawmidi_status_t);
959 }
960
961 /**
962 * \brief allocate the snd_rawmidi_status_t structure
963 * \param ptr returned pointer
964 * \return 0 on success otherwise a negative error code if fails
965 *
966 * Allocates a new snd_rawmidi_status_t structure using the standard
967 * malloc C library function.
968 */
snd_rawmidi_status_malloc(snd_rawmidi_status_t ** ptr)969 int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr)
970 {
971 assert(ptr);
972 *ptr = calloc(1, sizeof(snd_rawmidi_status_t));
973 if (!*ptr)
974 return -ENOMEM;
975 return 0;
976 }
977
978 /**
979 * \brief frees the snd_rawmidi_status_t structure
980 * \param status pointer to the snd_rawmidi_status_t structure to free
981 *
982 * Frees the given snd_rawmidi_status_t structure using the standard
983 * free C library function.
984 */
snd_rawmidi_status_free(snd_rawmidi_status_t * status)985 void snd_rawmidi_status_free(snd_rawmidi_status_t *status)
986 {
987 assert(status);
988 free(status);
989 }
990
991 /**
992 * \brief copy one snd_rawmidi_status_t structure to another
993 * \param dst destination snd_rawmidi_status_t structure
994 * \param src source snd_rawmidi_status_t structure
995 */
snd_rawmidi_status_copy(snd_rawmidi_status_t * dst,const snd_rawmidi_status_t * src)996 void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src)
997 {
998 assert(dst && src);
999 *dst = *src;
1000 }
1001
1002 /**
1003 * \brief get the start timestamp
1004 * \param status pointer to a snd_rawmidi_status_t structure
1005 * \param tstamp returned timestamp value
1006 */
snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t * status,snd_htimestamp_t * tstamp)1007 void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *status, snd_htimestamp_t *tstamp)
1008 {
1009 assert(status && tstamp);
1010 *tstamp = status->tstamp;
1011 }
1012
1013 /**
1014 * \brief get current available bytes in the rawmidi I/O ring buffer
1015 * \param status pointer to a snd_rawmidi_status_t structure
1016 * \return current available bytes in the rawmidi I/O ring buffer
1017 */
snd_rawmidi_status_get_avail(const snd_rawmidi_status_t * status)1018 size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *status)
1019 {
1020 assert(status);
1021 return status->avail;
1022 }
1023
1024 /**
1025 * \brief get count of xruns
1026 * \param status pointer to a snd_rawmidi_status_t structure
1027 * \return count of xruns
1028 */
snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t * status)1029 size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *status)
1030 {
1031 assert(status);
1032 return status->xruns;
1033 }
1034
1035 /**
1036 * \brief get status of rawmidi stream
1037 * \param rawmidi RawMidi handle
1038 * \param status pointer to a snd_rawmidi_status_t structure to be filled
1039 * \return 0 on success otherwise a negative error code
1040 */
snd_rawmidi_status(snd_rawmidi_t * rawmidi,snd_rawmidi_status_t * status)1041 int snd_rawmidi_status(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t * status)
1042 {
1043 assert(rawmidi);
1044 assert(status);
1045 return rawmidi->ops->status(rawmidi, status);
1046 }
1047
1048 /**
1049 * \brief drop all bytes in the rawmidi I/O ring buffer immediately
1050 * \param rawmidi RawMidi handle
1051 * \return 0 on success otherwise a negative error code
1052 */
snd_rawmidi_drop(snd_rawmidi_t * rawmidi)1053 int snd_rawmidi_drop(snd_rawmidi_t *rawmidi)
1054 {
1055 assert(rawmidi);
1056 return rawmidi->ops->drop(rawmidi);
1057 }
1058
1059 /**
1060 * \brief drain all bytes in the rawmidi I/O ring buffer
1061 * \param rawmidi RawMidi handle
1062 * \return 0 on success otherwise a negative error code
1063 *
1064 * Waits until all MIDI bytes are not drained (sent) to the
1065 * hardware device.
1066 */
snd_rawmidi_drain(snd_rawmidi_t * rawmidi)1067 int snd_rawmidi_drain(snd_rawmidi_t *rawmidi)
1068 {
1069 assert(rawmidi);
1070 return rawmidi->ops->drain(rawmidi);
1071 }
1072
1073 /**
1074 * \brief write MIDI bytes to MIDI stream
1075 * \param rawmidi RawMidi handle
1076 * \param buffer buffer containing MIDI bytes
1077 * \param size output buffer size in bytes
1078 */
snd_rawmidi_write(snd_rawmidi_t * rawmidi,const void * buffer,size_t size)1079 ssize_t snd_rawmidi_write(snd_rawmidi_t *rawmidi, const void *buffer, size_t size)
1080 {
1081 assert(rawmidi);
1082 assert(rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT);
1083 assert(buffer || size == 0);
1084 return rawmidi->ops->write(rawmidi, buffer, size);
1085 }
1086
1087 /**
1088 * \brief read MIDI bytes from MIDI stream
1089 * \param rawmidi RawMidi handle
1090 * \param buffer buffer to store the input MIDI bytes
1091 * \param size input buffer size in bytes
1092 * \retval count of MIDI bytes otherwise a negative error code
1093 */
snd_rawmidi_read(snd_rawmidi_t * rawmidi,void * buffer,size_t size)1094 ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size)
1095 {
1096 assert(rawmidi);
1097 assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT);
1098 if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
1099 size &= ~(sizeof(struct snd_rawmidi_framing_tstamp) - 1);
1100 assert(buffer || size == 0);
1101 return (rawmidi->ops->read)(rawmidi, buffer, size);
1102 }
1103
1104 /**
1105 * \brief read MIDI bytes from MIDI stream with timestamp
1106 * \param rawmidi RawMidi handle
1107 * \param[out] tstamp timestamp for the returned MIDI bytes
1108 * \param buffer buffer to store the input MIDI bytes
1109 * \param size input buffer size in bytes
1110 * \retval count of MIDI bytes otherwise a negative error code
1111 */
snd_rawmidi_tread(snd_rawmidi_t * rawmidi,struct timespec * tstamp,void * buffer,size_t size)1112 ssize_t snd_rawmidi_tread(snd_rawmidi_t *rawmidi, struct timespec *tstamp, void *buffer, size_t size)
1113 {
1114 assert(rawmidi);
1115 assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT);
1116 assert(buffer || size == 0);
1117 if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
1118 return -EINVAL;
1119 if (rawmidi->ops->tread == NULL)
1120 return -ENOTSUP;
1121 return (rawmidi->ops->tread)(rawmidi, tstamp, buffer, size);
1122 }
1123