• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 \link example_test_rawmidi example code \endlink
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  * Shows open and read/write rawmidi operations.
145  */
146 
147 #include "rawmidi_local.h"
148 #include <stdio.h>
149 #include <stdlib.h>
150 #include <stdarg.h>
151 #include <unistd.h>
152 #include <string.h>
153 
154 /**
155  * \brief setup the default parameters
156  * \param rawmidi RawMidi handle
157  * \param params pointer to a snd_rawmidi_params_t structure
158  * \return 0 on success otherwise a negative error code
159  */
snd_rawmidi_params_default(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)160 static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params)
161 {
162 	assert(rawmidi);
163 	assert(params);
164 	params->buffer_size = page_size();
165 	params->avail_min = 1;
166 	params->no_active_sensing = 1;
167 	params->mode = 0;
168 	memset(params->reserved, 0, sizeof(params->reserved));
169 	return 0;
170 }
171 
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)172 static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
173 				 const char *name, snd_config_t *rawmidi_root,
174 				 snd_config_t *rawmidi_conf, int mode)
175 {
176 	const char *str;
177 	char buf[256];
178 	int err;
179 	snd_config_t *conf, *type_conf = NULL;
180 	snd_config_iterator_t i, next;
181 	snd_rawmidi_params_t params;
182 	const char *id;
183 	const char *lib = NULL, *open_name = NULL;
184 	int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **,
185 			 const char *, snd_config_t *, snd_config_t *, int) = NULL;
186 #ifndef PIC
187 	extern void *snd_rawmidi_open_symbols(void);
188 #endif
189 	if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
190 		if (name)
191 			SNDERR("Invalid type for RAWMIDI %s definition", name);
192 		else
193 			SNDERR("Invalid type for RAWMIDI definition");
194 		return -EINVAL;
195 	}
196 	err = snd_config_search(rawmidi_conf, "type", &conf);
197 	if (err < 0) {
198 		SNDERR("type is not defined");
199 		return err;
200 	}
201 	err = snd_config_get_id(conf, &id);
202 	if (err < 0) {
203 		SNDERR("unable to get id");
204 		return err;
205 	}
206 	err = snd_config_get_string(conf, &str);
207 	if (err < 0) {
208 		SNDERR("Invalid type for %s", id);
209 		return err;
210 	}
211 	err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf);
212 	if (err >= 0) {
213 		if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
214 			SNDERR("Invalid type for RAWMIDI type %s definition", str);
215 			err = -EINVAL;
216 			goto _err;
217 		}
218 		snd_config_for_each(i, next, type_conf) {
219 			snd_config_t *n = snd_config_iterator_entry(i);
220 			const char *id;
221 			if (snd_config_get_id(n, &id) < 0)
222 				continue;
223 			if (strcmp(id, "comment") == 0)
224 				continue;
225 			if (strcmp(id, "lib") == 0) {
226 				err = snd_config_get_string(n, &lib);
227 				if (err < 0) {
228 					SNDERR("Invalid type for %s", id);
229 					goto _err;
230 				}
231 				continue;
232 			}
233 			if (strcmp(id, "open") == 0) {
234 				err = snd_config_get_string(n, &open_name);
235 				if (err < 0) {
236 					SNDERR("Invalid type for %s", id);
237 					goto _err;
238 				}
239 				continue;
240 			}
241 			SNDERR("Unknown field %s", id);
242 			err = -EINVAL;
243 			goto _err;
244 		}
245 	}
246 	if (!open_name) {
247 		open_name = buf;
248 		snprintf(buf, sizeof(buf), "_snd_rawmidi_%s_open", str);
249 	}
250 #ifndef PIC
251 	snd_rawmidi_open_symbols();
252 #endif
253 	open_func = snd_dlobj_cache_get2(lib, open_name,
254 			SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1);
255 	if (!open_func) {
256 		err = -ENXIO;
257 		goto _err;
258 	}
259 	if (type_conf)
260 		snd_config_delete(type_conf);
261 	err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
262 	if (err < 0)
263 		goto _err;
264 	if (inputp) {
265 		(*inputp)->open_func = open_func;
266 		snd_rawmidi_params_default(*inputp, &params);
267 		err = snd_rawmidi_params(*inputp, &params);
268 		assert(err >= 0);
269 	}
270 	if (outputp) {
271 		(*outputp)->open_func = open_func;
272 		snd_rawmidi_params_default(*outputp, &params);
273 		err = snd_rawmidi_params(*outputp, &params);
274 		assert(err >= 0);
275 	}
276 	return 0;
277 
278        _err:
279 	if (open_func)
280 		snd_dlobj_cache_put(open_func);
281 	if (type_conf)
282 		snd_config_delete(type_conf);
283 	return err;
284 }
285 
snd_rawmidi_open_noupdate(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,snd_config_t * root,const char * name,int mode)286 static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
287 				     snd_config_t *root, const char *name, int mode)
288 {
289 	int err;
290 	snd_config_t *rawmidi_conf;
291 	err = snd_config_search_definition(root, "rawmidi", name, &rawmidi_conf);
292 	if (err < 0) {
293 		SNDERR("Unknown RawMidi %s", name);
294 		return err;
295 	}
296 	err = snd_rawmidi_open_conf(inputp, outputp, name, root, rawmidi_conf, mode);
297 	snd_config_delete(rawmidi_conf);
298 	return err;
299 }
300 
301 /**
302  * \brief Opens a new connection to the RawMidi interface.
303  * \param inputp Returned input handle (NULL if not wanted)
304  * \param outputp Returned output handle (NULL if not wanted)
305  * \param name ASCII identifier of the RawMidi handle
306  * \param mode Open mode
307  * \return 0 on success otherwise a negative error code
308  *
309  * Opens a new connection to the RawMidi interface specified with
310  * an ASCII identifier and mode.
311  */
snd_rawmidi_open(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,const char * name,int mode)312 int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
313 		     const char *name, int mode)
314 {
315 	snd_config_t *top;
316 	int err;
317 
318 	assert((inputp || outputp) && name);
319 	if (_snd_is_ucm_device(name)) {
320 		name = uc_mgr_alibcfg_by_device(&top, name);
321 		if (name == NULL)
322 			return -ENODEV;
323 	} else {
324 		err = snd_config_update_ref(&top);
325 		if (err < 0)
326 			return err;
327 	}
328 	err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode);
329 	snd_config_unref(top);
330 	return err;
331 }
332 
333 /**
334  * \brief Opens a new connection to the RawMidi interface using local configuration
335  * \param inputp Returned input handle (NULL if not wanted)
336  * \param outputp Returned output handle (NULL if not wanted)
337  * \param name ASCII identifier of the RawMidi handle
338  * \param mode Open mode
339  * \param lconf Local configuration
340  * \return 0 on success otherwise a negative error code
341  *
342  * Opens a new connection to the RawMidi interface specified with
343  * an ASCII identifier and mode.
344  */
snd_rawmidi_open_lconf(snd_rawmidi_t ** inputp,snd_rawmidi_t ** outputp,const char * name,int mode,snd_config_t * lconf)345 int snd_rawmidi_open_lconf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
346 			   const char *name, int mode, snd_config_t *lconf)
347 {
348 	assert((inputp || outputp) && name && lconf);
349 	return snd_rawmidi_open_noupdate(inputp, outputp, lconf, name, mode);
350 }
351 
352 /**
353  * \brief close RawMidi handle
354  * \param rawmidi RawMidi handle
355  * \return 0 on success otherwise a negative error code
356  *
357  * Closes the specified RawMidi handle and frees all associated
358  * resources.
359  */
snd_rawmidi_close(snd_rawmidi_t * rawmidi)360 int snd_rawmidi_close(snd_rawmidi_t *rawmidi)
361 {
362 	int err;
363   	assert(rawmidi);
364 	err = rawmidi->ops->close(rawmidi);
365 	free(rawmidi->name);
366 	if (rawmidi->open_func)
367 		snd_dlobj_cache_put(rawmidi->open_func);
368 	free(rawmidi);
369 	return err;
370 }
371 
372 /**
373  * \brief get identifier of RawMidi handle
374  * \param rawmidi a RawMidi handle
375  * \return ascii identifier of RawMidi handle
376  *
377  * Returns the ASCII identifier of given RawMidi handle. It's the same
378  * identifier specified in snd_rawmidi_open().
379  */
snd_rawmidi_name(snd_rawmidi_t * rawmidi)380 const char *snd_rawmidi_name(snd_rawmidi_t *rawmidi)
381 {
382 	assert(rawmidi);
383 	return rawmidi->name;
384 }
385 
386 /**
387  * \brief get type of RawMidi handle
388  * \param rawmidi a RawMidi handle
389  * \return type of RawMidi handle
390  *
391  * Returns the type #snd_rawmidi_type_t of given RawMidi handle.
392  */
snd_rawmidi_type(snd_rawmidi_t * rawmidi)393 snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rawmidi)
394 {
395 	assert(rawmidi);
396 	return rawmidi->type;
397 }
398 
399 /**
400  * \brief get stream (direction) of RawMidi handle
401  * \param rawmidi a RawMidi handle
402  * \return stream of RawMidi handle
403  *
404  * Returns the stream #snd_rawmidi_stream_t of given RawMidi handle.
405  */
snd_rawmidi_stream(snd_rawmidi_t * rawmidi)406 snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi)
407 {
408 	assert(rawmidi);
409 	return rawmidi->stream;
410 }
411 
412 /**
413  * \brief get count of poll descriptors for RawMidi handle
414  * \param rawmidi RawMidi handle
415  * \return count of poll descriptors
416  */
snd_rawmidi_poll_descriptors_count(snd_rawmidi_t * rawmidi)417 int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rawmidi)
418 {
419 	assert(rawmidi);
420 	return 1;
421 }
422 
423 /**
424  * \brief get poll descriptors
425  * \param rawmidi RawMidi handle
426  * \param pfds array of poll descriptors
427  * \param space space in the poll descriptor array
428  * \return count of filled descriptors
429  */
snd_rawmidi_poll_descriptors(snd_rawmidi_t * rawmidi,struct pollfd * pfds,unsigned int space)430 int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int space)
431 {
432 	assert(rawmidi);
433 	if (space >= 1) {
434 		pfds->fd = rawmidi->poll_fd;
435 		pfds->events = rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL);
436 		return 1;
437 	}
438 	return 0;
439 }
440 
441 /**
442  * \brief get returned events from poll descriptors
443  * \param rawmidi rawmidi RawMidi handle
444  * \param pfds array of poll descriptors
445  * \param nfds count of poll descriptors
446  * \param revents returned events
447  * \return zero if success, otherwise a negative error code
448  */
snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t * rawmidi,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)449 int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
450 {
451         assert(rawmidi && pfds && revents);
452         if (nfds == 1) {
453                 *revents = pfds->revents;
454                 return 0;
455         }
456         return -EINVAL;
457 }
458 
459 /**
460  * \brief set nonblock mode
461  * \param rawmidi RawMidi handle
462  * \param nonblock 0 = block, 1 = nonblock mode
463  * \return 0 on success otherwise a negative error code
464  *
465  * The nonblock mode cannot be used when the stream is in
466  * #SND_RAWMIDI_APPEND state.
467  */
snd_rawmidi_nonblock(snd_rawmidi_t * rawmidi,int nonblock)468 int snd_rawmidi_nonblock(snd_rawmidi_t *rawmidi, int nonblock)
469 {
470 	int err;
471 	assert(rawmidi);
472 	assert(!(rawmidi->mode & SND_RAWMIDI_APPEND));
473 	if ((err = rawmidi->ops->nonblock(rawmidi, nonblock)) < 0)
474 		return err;
475 	if (nonblock)
476 		rawmidi->mode |= SND_RAWMIDI_NONBLOCK;
477 	else
478 		rawmidi->mode &= ~SND_RAWMIDI_NONBLOCK;
479 	return 0;
480 }
481 
482 /**
483  * \brief get size of the snd_rawmidi_info_t structure in bytes
484  * \return size of the snd_rawmidi_info_t structure in bytes
485  */
snd_rawmidi_info_sizeof()486 size_t snd_rawmidi_info_sizeof()
487 {
488 	return sizeof(snd_rawmidi_info_t);
489 }
490 
491 /**
492  * \brief allocate a new snd_rawmidi_info_t structure
493  * \param info returned pointer
494  * \return 0 on success otherwise a negative error code if fails
495  *
496  * Allocates a new snd_rawmidi_params_t structure using the standard
497  * malloc C library function.
498  */
snd_rawmidi_info_malloc(snd_rawmidi_info_t ** info)499 int snd_rawmidi_info_malloc(snd_rawmidi_info_t **info)
500 {
501 	assert(info);
502 	*info = calloc(1, sizeof(snd_rawmidi_info_t));
503 	if (!*info)
504 		return -ENOMEM;
505 	return 0;
506 }
507 
508 /**
509  * \brief frees the snd_rawmidi_info_t structure
510  * \param info pointer to the snd_rawmidi_info_t structure to free
511  *
512  * Frees the given snd_rawmidi_params_t structure using the standard
513  * free C library function.
514  */
snd_rawmidi_info_free(snd_rawmidi_info_t * info)515 void snd_rawmidi_info_free(snd_rawmidi_info_t *info)
516 {
517 	assert(info);
518 	free(info);
519 }
520 
521 /**
522  * \brief copy one snd_rawmidi_info_t structure to another
523  * \param dst destination snd_rawmidi_info_t structure
524  * \param src source snd_rawmidi_info_t structure
525  */
snd_rawmidi_info_copy(snd_rawmidi_info_t * dst,const snd_rawmidi_info_t * src)526 void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src)
527 {
528 	assert(dst && src);
529 	*dst = *src;
530 }
531 
532 /**
533  * \brief get rawmidi device number
534  * \param info pointer to a snd_rawmidi_info_t structure
535  * \return rawmidi device number
536  */
snd_rawmidi_info_get_device(const snd_rawmidi_info_t * info)537 unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *info)
538 {
539 	assert(info);
540 	return info->device;
541 }
542 
543 /**
544  * \brief get rawmidi subdevice number
545  * \param info pointer to a snd_rawmidi_info_t structure
546  * \return rawmidi subdevice number
547  */
snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t * info)548 unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *info)
549 {
550 	assert(info);
551 	return info->subdevice;
552 }
553 
554 /**
555  * \brief get rawmidi stream identification
556  * \param info pointer to a snd_rawmidi_info_t structure
557  * \return rawmidi stream identification
558  */
snd_rawmidi_info_get_stream(const snd_rawmidi_info_t * info)559 snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *info)
560 {
561 	assert(info);
562 	return info->stream;
563 }
564 
565 /**
566  * \brief get rawmidi card number
567  * \param info pointer to a snd_rawmidi_info_t structure
568  * \return rawmidi card number
569  */
snd_rawmidi_info_get_card(const snd_rawmidi_info_t * info)570 int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *info)
571 {
572 	assert(info);
573 	return info->card;
574 }
575 
576 /**
577  * \brief get rawmidi flags
578  * \param info pointer to a snd_rawmidi_info_t structure
579  * \return rawmidi flags
580  */
snd_rawmidi_info_get_flags(const snd_rawmidi_info_t * info)581 unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *info)
582 {
583 	assert(info);
584 	return info->flags;
585 }
586 
587 /**
588  * \brief get rawmidi hardware driver identifier
589  * \param info pointer to a snd_rawmidi_info_t structure
590  * \return rawmidi hardware driver identifier
591  */
snd_rawmidi_info_get_id(const snd_rawmidi_info_t * info)592 const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *info)
593 {
594 	assert(info);
595 	return (const char *)info->id;
596 }
597 
598 /**
599  * \brief get rawmidi hardware driver name
600  * \param info pointer to a snd_rawmidi_info_t structure
601  * \return rawmidi hardware driver name
602  */
snd_rawmidi_info_get_name(const snd_rawmidi_info_t * info)603 const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *info)
604 {
605 	assert(info);
606 	return (const char *)info->name;
607 }
608 
609 /**
610  * \brief get rawmidi subdevice name
611  * \param info pointer to a snd_rawmidi_info_t structure
612  * \return rawmidi subdevice name
613  */
snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t * info)614 const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *info)
615 {
616 	assert(info);
617 	return (const char *)info->subname;
618 }
619 
620 /**
621  * \brief get rawmidi count of subdevices
622  * \param info pointer to a snd_rawmidi_info_t structure
623  * \return rawmidi count of subdevices
624  */
snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t * info)625 unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *info)
626 {
627 	assert(info);
628 	return info->subdevices_count;
629 }
630 
631 /**
632  * \brief get rawmidi available count of subdevices
633  * \param info pointer to a snd_rawmidi_info_t structure
634  * \return rawmidi available count of subdevices
635  */
snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t * info)636 unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *info)
637 {
638 	assert(info);
639 	return info->subdevices_avail;
640 }
641 
642 /**
643  * \brief set rawmidi device number
644  * \param info pointer to a snd_rawmidi_info_t structure
645  * \param val device number
646  */
snd_rawmidi_info_set_device(snd_rawmidi_info_t * info,unsigned int val)647 void snd_rawmidi_info_set_device(snd_rawmidi_info_t *info, unsigned int val)
648 {
649 	assert(info);
650 	info->device = val;
651 }
652 
653 /**
654  * \brief set rawmidi subdevice number
655  * \param info pointer to a snd_rawmidi_info_t structure
656  * \param val subdevice number
657  */
snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t * info,unsigned int val)658 void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *info, unsigned int val)
659 {
660 	assert(info);
661 	info->subdevice = val;
662 }
663 
664 /**
665  * \brief set rawmidi stream identifier
666  * \param info pointer to a snd_rawmidi_info_t structure
667  * \param val rawmidi stream identifier
668  */
snd_rawmidi_info_set_stream(snd_rawmidi_info_t * info,snd_rawmidi_stream_t val)669 void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *info, snd_rawmidi_stream_t val)
670 {
671 	assert(info);
672 	info->stream = val;
673 }
674 
675 /**
676  * \brief get information about RawMidi handle
677  * \param rawmidi RawMidi handle
678  * \param info pointer to a snd_rawmidi_info_t structure to be filled
679  * \return 0 on success otherwise a negative error code
680  */
snd_rawmidi_info(snd_rawmidi_t * rawmidi,snd_rawmidi_info_t * info)681 int snd_rawmidi_info(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t * info)
682 {
683 	assert(rawmidi);
684 	assert(info);
685 	return rawmidi->ops->info(rawmidi, info);
686 }
687 
688 /**
689  * \brief get size of the snd_rawmidi_params_t structure in bytes
690  * \return size of the snd_rawmidi_params_t structure in bytes
691  */
snd_rawmidi_params_sizeof()692 size_t snd_rawmidi_params_sizeof()
693 {
694 	return sizeof(snd_rawmidi_params_t);
695 }
696 
697 /**
698  * \brief allocate the snd_rawmidi_params_t structure
699  * \param params returned pointer
700  * \return 0 on success otherwise a negative error code if fails
701  *
702  * Allocates a new snd_rawmidi_params_t structure using the standard
703  * malloc C library function.
704  */
snd_rawmidi_params_malloc(snd_rawmidi_params_t ** params)705 int snd_rawmidi_params_malloc(snd_rawmidi_params_t **params)
706 {
707 	assert(params);
708 	*params = calloc(1, sizeof(snd_rawmidi_params_t));
709 	if (!*params)
710 		return -ENOMEM;
711 	return 0;
712 }
713 
714 /**
715  * \brief frees the snd_rawmidi_params_t structure
716  * \param params pointer to the #snd_rawmidi_params_t structure to free
717  *
718  * Frees the given snd_rawmidi_params_t structure using the standard
719  * free C library function.
720  */
snd_rawmidi_params_free(snd_rawmidi_params_t * params)721 void snd_rawmidi_params_free(snd_rawmidi_params_t *params)
722 {
723 	assert(params);
724 	free(params);
725 }
726 
727 /**
728  * \brief copy one snd_rawmidi_params_t structure to another
729  * \param dst destination snd_rawmidi_params_t structure
730  * \param src source snd_rawmidi_params_t structure
731  */
snd_rawmidi_params_copy(snd_rawmidi_params_t * dst,const snd_rawmidi_params_t * src)732 void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src)
733 {
734 	assert(dst && src);
735 	*dst = *src;
736 }
737 
738 /**
739  * \brief set rawmidi I/O ring buffer size
740  * \param rawmidi RawMidi handle
741  * \param params pointer to a snd_rawmidi_params_t structure
742  * \param val size in bytes
743  * \return 0 on success otherwise a negative error code
744  */
745 #ifndef DOXYGEN
snd_rawmidi_params_set_buffer_size(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,size_t val)746 int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val)
747 #else
748 int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val)
749 #endif
750 {
751 	assert(rawmidi && params);
752 	assert(val > params->avail_min);
753 	params->buffer_size = val;
754 	return 0;
755 }
756 
757 /**
758  * \brief get rawmidi I/O ring buffer size
759  * \param params pointer to a snd_rawmidi_params_t structure
760  * \return size of rawmidi I/O ring buffer in bytes
761  */
snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t * params)762 size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params)
763 {
764 	assert(params);
765 	return params->buffer_size;
766 }
767 
768 /**
769  * \brief set minimum available bytes in rawmidi I/O ring buffer for wakeup
770  * \param rawmidi RawMidi handle
771  * \param params pointer to a snd_rawmidi_params_t structure
772  * \param val desired value
773  */
774 #ifndef DOXYGEN
snd_rawmidi_params_set_avail_min(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,size_t val)775 int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val)
776 #else
777 int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val)
778 #endif
779 {
780 	assert(rawmidi && params);
781 	assert(val < params->buffer_size);
782 	params->avail_min = val;
783 	return 0;
784 }
785 
786 /**
787  * \brief get minimum available bytes in rawmidi I/O ring buffer for wakeup
788  * \param params pointer to snd_rawmidi_params_t structure
789  * \return minimum available bytes
790  */
snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t * params)791 size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params)
792 {
793 	assert(params);
794 	return params->avail_min;
795 }
796 
797 /**
798  * \brief set no-active-sensing action on snd_rawmidi_close()
799  * \param rawmidi RawMidi handle
800  * \param params pointer to snd_rawmidi_params_t structure
801  * \param val value: 0 = enable to send the active sensing message, 1 = disable
802  * \return 0 on success otherwise a negative error code
803  */
804 #ifndef DOXYGEN
snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t * rawmidi ATTRIBUTE_UNUSED,snd_rawmidi_params_t * params,int val)805 int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, int val)
806 #else
807 int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, int val)
808 #endif
809 {
810 	assert(rawmidi && params);
811 	params->no_active_sensing = val;
812 	return 0;
813 }
814 
815 /**
816  * \brief get no-active-sensing action status
817  * \param params pointer to snd_rawmidi_params_t structure
818  * \return the current status (0 = enable, 1 = disable the active sensing message)
819  */
snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t * params)820 int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params)
821 {
822 	assert(params);
823 	return params->no_active_sensing;
824 }
825 
826 /**
827  * \brief set read mode
828  * \param rawmidi RawMidi handle
829  * \param params pointer to snd_rawmidi_params_t structure
830  * \param val type of read_mode
831  * \return 0 on success, otherwise a negative error code.
832  *
833  * Notable error codes:
834  * -EINVAL - "val" is invalid
835  * -ENOTSUP - mode is not supported
836  *
837  */
snd_rawmidi_params_set_read_mode(const snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params,snd_rawmidi_read_mode_t val)838 int snd_rawmidi_params_set_read_mode(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_read_mode_t val)
839 {
840 	unsigned int framing;
841 	assert(rawmidi && params);
842 
843 	switch (val) {
844 	case SND_RAWMIDI_READ_STANDARD:
845 		framing = SNDRV_RAWMIDI_MODE_FRAMING_NONE;
846 		break;
847 	case SND_RAWMIDI_READ_TSTAMP:
848 		if (rawmidi->ops->tread == NULL)
849 			return -ENOTSUP;
850 		framing = SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP;
851 		break;
852 	default:
853 		return -EINVAL;
854 	}
855 
856 	if (framing != SNDRV_RAWMIDI_MODE_FRAMING_NONE &&
857 		(rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
858 		return -ENOTSUP;
859 	params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_FRAMING_MASK) | framing;
860 	return 0;
861 }
862 
863 /**
864  * \brief get current read mode
865  * \param params pointer to snd_rawmidi_params_t structure
866  * \return the current read mode (see enum)
867  */
snd_rawmidi_params_get_read_mode(const snd_rawmidi_params_t * params)868 snd_rawmidi_read_mode_t snd_rawmidi_params_get_read_mode(const snd_rawmidi_params_t *params)
869 {
870 	unsigned int framing;
871 
872 	assert(params);
873 	framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
874 	if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
875 		return SND_RAWMIDI_READ_TSTAMP;
876 	return SND_RAWMIDI_READ_STANDARD;
877 }
878 
879 /**
880  * \brief sets clock type for tstamp type framing
881  * \param rawmidi RawMidi handle
882  * \param params pointer to snd_rawmidi_params_t structure
883  * \param val one of the SND_RAWMIDI_CLOCK_* constants
884  * \return 0 on success, otherwise a negative error code.
885  *
886  * Notable error codes:
887  * -EINVAL - "val" is invalid
888  * -ENOTSUP - Kernel is too old to support framing.
889  *
890  */
snd_rawmidi_params_set_clock_type(const snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params,snd_rawmidi_clock_t val)891 int snd_rawmidi_params_set_clock_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_clock_t val)
892 {
893 	assert(rawmidi && params);
894 	if (val > SNDRV_RAWMIDI_MODE_CLOCK_MASK >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT)
895 		return -EINVAL;
896 	if (val != SNDRV_RAWMIDI_MODE_CLOCK_NONE &&
897 		(rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
898 		return -ENOTSUP;
899 	params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_CLOCK_MASK) + (val << SNDRV_RAWMIDI_MODE_CLOCK_SHIFT);
900 	return 0;
901 }
902 
903 /**
904  * \brief get current clock type (for tstamp type framing)
905  * \param params pointer to snd_rawmidi_params_t structure
906  * \return the current clock type (one of the SND_RAWMIDI_CLOCK_* constants)
907  */
snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t * params)908 snd_rawmidi_clock_t snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t *params)
909 {
910 	assert(params);
911 	return (params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK) >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT;
912 }
913 
914 
915 /**
916  * \brief set parameters about rawmidi stream
917  * \param rawmidi RawMidi handle
918  * \param params pointer to a snd_rawmidi_params_t structure to be filled
919  * \return 0 on success otherwise a negative error code
920  */
snd_rawmidi_params(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)921 int snd_rawmidi_params(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t * params)
922 {
923 	int err;
924 	assert(rawmidi);
925 	assert(params);
926 	err = rawmidi->ops->params(rawmidi, params);
927 	if (err < 0)
928 		return err;
929 	rawmidi->buffer_size = params->buffer_size;
930 	rawmidi->avail_min = params->avail_min;
931 	rawmidi->no_active_sensing = params->no_active_sensing;
932 	rawmidi->params_mode = rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) ? 0 : params->mode;
933 	return 0;
934 }
935 
936 /**
937  * \brief get current parameters about rawmidi stream
938  * \param rawmidi RawMidi handle
939  * \param params pointer to a snd_rawmidi_params_t structure to be filled
940  * \return 0 on success otherwise a negative error code
941  */
snd_rawmidi_params_current(snd_rawmidi_t * rawmidi,snd_rawmidi_params_t * params)942 int snd_rawmidi_params_current(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params)
943 {
944 	assert(rawmidi);
945 	assert(params);
946 	params->buffer_size = rawmidi->buffer_size;
947 	params->avail_min = rawmidi->avail_min;
948 	params->no_active_sensing = rawmidi->no_active_sensing;
949 	params->mode = rawmidi->params_mode;
950 	return 0;
951 }
952 
953 /**
954  * \brief get size of the snd_rawmidi_status_t structure in bytes
955  * \return size of the snd_rawmidi_status_t structure in bytes
956  */
snd_rawmidi_status_sizeof()957 size_t snd_rawmidi_status_sizeof()
958 {
959 	return sizeof(snd_rawmidi_status_t);
960 }
961 
962 /**
963  * \brief allocate the snd_rawmidi_status_t structure
964  * \param ptr returned pointer
965  * \return 0 on success otherwise a negative error code if fails
966  *
967  * Allocates a new snd_rawmidi_status_t structure using the standard
968  * malloc C library function.
969  */
snd_rawmidi_status_malloc(snd_rawmidi_status_t ** ptr)970 int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr)
971 {
972 	assert(ptr);
973 	*ptr = calloc(1, sizeof(snd_rawmidi_status_t));
974 	if (!*ptr)
975 		return -ENOMEM;
976 	return 0;
977 }
978 
979 /**
980  * \brief frees the snd_rawmidi_status_t structure
981  * \param status pointer to the snd_rawmidi_status_t structure to free
982  *
983  * Frees the given snd_rawmidi_status_t structure using the standard
984  * free C library function.
985  */
snd_rawmidi_status_free(snd_rawmidi_status_t * status)986 void snd_rawmidi_status_free(snd_rawmidi_status_t *status)
987 {
988 	assert(status);
989 	free(status);
990 }
991 
992 /**
993  * \brief copy one snd_rawmidi_status_t structure to another
994  * \param dst destination snd_rawmidi_status_t structure
995  * \param src source snd_rawmidi_status_t structure
996  */
snd_rawmidi_status_copy(snd_rawmidi_status_t * dst,const snd_rawmidi_status_t * src)997 void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src)
998 {
999 	assert(dst && src);
1000 	*dst = *src;
1001 }
1002 
1003 /**
1004  * \brief get the start timestamp
1005  * \param status pointer to a snd_rawmidi_status_t structure
1006  * \param tstamp returned timestamp value
1007  */
snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t * status,snd_htimestamp_t * tstamp)1008 void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *status, snd_htimestamp_t *tstamp)
1009 {
1010 	assert(status && tstamp);
1011 	*tstamp = status->tstamp;
1012 }
1013 
1014 /**
1015  * \brief get current available bytes in the rawmidi I/O ring buffer
1016  * \param status pointer to a snd_rawmidi_status_t structure
1017  * \return current available bytes in the rawmidi I/O ring buffer
1018  */
snd_rawmidi_status_get_avail(const snd_rawmidi_status_t * status)1019 size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *status)
1020 {
1021 	assert(status);
1022 	return status->avail;
1023 }
1024 
1025 /**
1026  * \brief get count of xruns
1027  * \param status pointer to a snd_rawmidi_status_t structure
1028  * \return count of xruns
1029  */
snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t * status)1030 size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *status)
1031 {
1032 	assert(status);
1033 	return status->xruns;
1034 }
1035 
1036 /**
1037  * \brief get status of rawmidi stream
1038  * \param rawmidi RawMidi handle
1039  * \param status pointer to a snd_rawmidi_status_t structure to be filled
1040  * \return 0 on success otherwise a negative error code
1041  */
snd_rawmidi_status(snd_rawmidi_t * rawmidi,snd_rawmidi_status_t * status)1042 int snd_rawmidi_status(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t * status)
1043 {
1044 	assert(rawmidi);
1045 	assert(status);
1046 	return rawmidi->ops->status(rawmidi, status);
1047 }
1048 
1049 /**
1050  * \brief drop all bytes in the rawmidi I/O ring buffer immediately
1051  * \param rawmidi RawMidi handle
1052  * \return 0 on success otherwise a negative error code
1053  */
snd_rawmidi_drop(snd_rawmidi_t * rawmidi)1054 int snd_rawmidi_drop(snd_rawmidi_t *rawmidi)
1055 {
1056 	assert(rawmidi);
1057 	return rawmidi->ops->drop(rawmidi);
1058 }
1059 
1060 /**
1061  * \brief drain all bytes in the rawmidi I/O ring buffer
1062  * \param rawmidi RawMidi handle
1063  * \return 0 on success otherwise a negative error code
1064  *
1065  * Waits until all MIDI bytes are not drained (sent) to the
1066  * hardware device.
1067  */
snd_rawmidi_drain(snd_rawmidi_t * rawmidi)1068 int snd_rawmidi_drain(snd_rawmidi_t *rawmidi)
1069 {
1070 	assert(rawmidi);
1071 	return rawmidi->ops->drain(rawmidi);
1072 }
1073 
1074 /**
1075  * \brief write MIDI bytes to MIDI stream
1076  * \param rawmidi RawMidi handle
1077  * \param buffer buffer containing MIDI bytes
1078  * \param size output buffer size in bytes
1079  */
snd_rawmidi_write(snd_rawmidi_t * rawmidi,const void * buffer,size_t size)1080 ssize_t snd_rawmidi_write(snd_rawmidi_t *rawmidi, const void *buffer, size_t size)
1081 {
1082 	assert(rawmidi);
1083 	assert(rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT);
1084 	assert(buffer || size == 0);
1085 	return rawmidi->ops->write(rawmidi, buffer, size);
1086 }
1087 
1088 /**
1089  * \brief read MIDI bytes from MIDI stream
1090  * \param rawmidi RawMidi handle
1091  * \param buffer buffer to store the input MIDI bytes
1092  * \param size input buffer size in bytes
1093  * \retval count of MIDI bytes otherwise a negative error code
1094  */
snd_rawmidi_read(snd_rawmidi_t * rawmidi,void * buffer,size_t size)1095 ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size)
1096 {
1097 	assert(rawmidi);
1098 	assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT);
1099 	if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
1100 		size &= ~(sizeof(struct snd_rawmidi_framing_tstamp) - 1);
1101 	assert(buffer || size == 0);
1102 	return (rawmidi->ops->read)(rawmidi, buffer, size);
1103 }
1104 
1105 /**
1106  * \brief read MIDI bytes from MIDI stream with timestamp
1107  * \param rawmidi RawMidi handle
1108  * \param[out] tstamp timestamp for the returned MIDI bytes
1109  * \param buffer buffer to store the input MIDI bytes
1110  * \param size input buffer size in bytes
1111  * \retval count of MIDI bytes otherwise a negative error code
1112  */
snd_rawmidi_tread(snd_rawmidi_t * rawmidi,struct timespec * tstamp,void * buffer,size_t size)1113 ssize_t snd_rawmidi_tread(snd_rawmidi_t *rawmidi, struct timespec *tstamp, void *buffer, size_t size)
1114 {
1115 	assert(rawmidi);
1116 	assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT);
1117 	assert(buffer || size == 0);
1118 	if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) != SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
1119 		return -EINVAL;
1120 	if (rawmidi->ops->tread == NULL)
1121 		return -ENOTSUP;
1122 	return (rawmidi->ops->tread)(rawmidi, tstamp, buffer, size);
1123 }
1124 
1125 #ifndef DOXYGEN
1126 /*
1127  * internal API functions for obtaining UMP info from rawmidi instance
1128  */
_snd_rawmidi_ump_endpoint_info(snd_rawmidi_t * rmidi,void * info)1129 int _snd_rawmidi_ump_endpoint_info(snd_rawmidi_t *rmidi, void *info)
1130 {
1131 	if (!rmidi->ops->ump_endpoint_info)
1132 		return -ENXIO;
1133 	return rmidi->ops->ump_endpoint_info(rmidi, info);
1134 }
1135 
_snd_rawmidi_ump_block_info(snd_rawmidi_t * rmidi,void * info)1136 int _snd_rawmidi_ump_block_info(snd_rawmidi_t *rmidi, void *info)
1137 {
1138 	if (!rmidi->ops->ump_block_info)
1139 		return -ENXIO;
1140 	return rmidi->ops->ump_block_info(rmidi, info);
1141 }
1142 #endif /* DOXYGEN */
1143