• 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 \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, &params);
266 		err = snd_rawmidi_params(*inputp, &params);
267 		assert(err >= 0);
268 	}
269 	if (outputp) {
270 		(*outputp)->open_func = open_func;
271 		snd_rawmidi_params_default(*outputp, &params);
272 		err = snd_rawmidi_params(*outputp, &params);
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