| /** | |
| * \file rawmidi/rawmidi.c | |
| * \brief RawMidi Interface | |
| * \author Jaroslav Kysela <perex@perex.cz> | |
| * \author Abramo Bagnara <abramo@alsa-project.org> | |
| * \date 2000-2001 | |
| * | |
| * See the \ref rawmidi page for more details. | |
| */ | |
| /* | |
| * | |
| * This library is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as | |
| * published by the Free Software Foundation; either version 2.1 of | |
| * the License, or (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| * | |
| */ | |
| /*! \page rawmidi RawMidi interface | |
| <P>RawMidi Interface is designed to write or read raw (unchanged) MIDI | |
| data over the MIDI line without any timestamps defined in interface. MIDI | |
| stands Musical Instrument Digital Interface and more information about | |
| this standard can be found at http://www.midi.org. | |
| \section rawmidi_general_overview General overview | |
| The rawmidi implementation uses ring buffers to store outgoing and incoming | |
| MIDI stream. The buffer size is tunable and drivers report underruns for incoming | |
| stream as well. | |
| \section rawmidi_open Open handling | |
| RawMidi devices are opened exclusively for a selected direction. | |
| While more than one process may not open a given MIDI device in the same | |
| direction simultaneously, separate processes may open a single MIDI device | |
| in different directions (i.e. process one opens a MIDI device in write | |
| direction and process two opens the same device in read direction). | |
| \subsection rawmidi_open_nonblock Nonblocking open (flag) | |
| Using #SND_RAWMIDI_NONBLOCK flag for snd_rawmidi_open() or snd_rawmidi_open_lconf() | |
| instruct device driver to return the -EBUSY error when device is already occupied | |
| with another application. This flag also changes behaviour of snd_rawmidi_write() | |
| and snd_rawmidi_read() returning -EAGAIN when no more bytes can be processed. | |
| Note: In opposite (default) behaviour, application is blocked until device resources | |
| are free. | |
| \subsection rawmidi_open_append Append open (flag) | |
| Using #SND_RAWMIDI_APPEND flag (output only) instruct device driver to append | |
| contents of written buffer - passed by snd_rawmidi_write() - atomically | |
| to output ring buffer in the kernel space. This flag also means that device | |
| is not opened exclusively, so more applications can share given rawmidi device. | |
| Note that applications must send the whole MIDI message including the running status, | |
| because another writing application might break the MIDI message in the output | |
| buffer. | |
| \subsection rawmidi_open_sync Sync open (flag) | |
| Using #SND_RAWMIDI_SYNC flag (output only) assures that the contents of output | |
| buffer specified using snd_rawmidi_write() is always drained before the function | |
| exits. This behaviour is same like 'snd_rawmidi_write() followed by | |
| snd_rawmidi_drain() immediately'. | |
| \subsection rawmidi_io I/O handling | |
| There is only standard read/write access to device internal ring buffer. Use | |
| snd_rawmidi_read() and snd_rawmidi_write() functions to obtain / write MIDI bytes. | |
| \subsection rawmidi_dev_names RawMidi naming conventions | |
| The ALSA library uses a generic string representation for names of devices. | |
| The devices might be virtual, physical or a mix of both. The generic string | |
| is passed to \link ::snd_rawmidi_open() \endlink or \link ::snd_rawmidi_open_lconf() \endlink. | |
| It contains two parts: device name and arguments. Devices and arguments are described | |
| in configuration files. The usual place for default definitions is at /usr/share/alsa/alsa.conf. | |
| \subsection rawmidi_dev_names_default | |
| The default device is equal to hw device. The defaults are used: | |
| defaults.rawmidi.card 0 | |
| defaults.rawmidi.device 0 | |
| defaults.rawmidi.subdevice -1 | |
| These defaults can be freely overwritten in local configuration files. | |
| Example: | |
| \code | |
| default | |
| \endcode | |
| \subsection rawmidi_dev_names_hw HW device | |
| The hw device description uses the hw plugin. The three arguments (in order: CARD,DEV,SUBDEV) | |
| specify card number or identifier, device number and subdevice number (-1 means any). | |
| Example: | |
| \code | |
| hw | |
| hw:0 | |
| hw:0,0 | |
| hw:supersonic,1 | |
| hw:soundwave,1,2 | |
| hw:DEV=1,CARD=soundwave,SUBDEV=2 | |
| \endcode | |
| \section read_mode Read mode | |
| Optionally, incoming rawmidi bytes can be marked with timestamps. The library hides | |
| the kernel implementation (linux kernel 5.14+) and exports | |
| the \link ::snd_rawmidi_tread() \endlink function which returns the | |
| midi bytes marked with the identical timestamp in one iteration. | |
| The timestamping is available only on input streams. | |
| \section rawmidi_examples Examples | |
| The full featured examples with cross-links: | |
| \par Simple input/output test program | |
| \link example_test_rawmidi example code \endlink | |
| \par | |
| This example shows open and read/write rawmidi operations. | |
| */ | |
| /** | |
| * \example ../test/rawmidi.c | |
| * \anchor example_test_rawmidi | |
| * Shows open and read/write rawmidi operations. | |
| */ | |
| #include "rawmidi_local.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdarg.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| /** | |
| * \brief setup the default parameters | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to a snd_rawmidi_params_t structure | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params) | |
| { | |
| assert(rawmidi); | |
| assert(params); | |
| params->buffer_size = page_size(); | |
| params->avail_min = 1; | |
| params->no_active_sensing = 1; | |
| params->mode = 0; | |
| memset(params->reserved, 0, sizeof(params->reserved)); | |
| return 0; | |
| } | |
| static int 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) | |
| { | |
| const char *str; | |
| char buf[256]; | |
| int err; | |
| snd_config_t *conf, *type_conf = NULL; | |
| snd_config_iterator_t i, next; | |
| snd_rawmidi_params_t params; | |
| const char *id; | |
| const char *lib = NULL, *open_name = NULL; | |
| int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **, | |
| const char *, snd_config_t *, snd_config_t *, int) = NULL; | |
| #ifndef PIC | |
| extern void *snd_rawmidi_open_symbols(void); | |
| #endif | |
| if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) { | |
| if (name) | |
| SNDERR("Invalid type for RAWMIDI %s definition", name); | |
| else | |
| SNDERR("Invalid type for RAWMIDI definition"); | |
| return -EINVAL; | |
| } | |
| err = snd_config_search(rawmidi_conf, "type", &conf); | |
| if (err < 0) { | |
| SNDERR("type is not defined"); | |
| return err; | |
| } | |
| err = snd_config_get_id(conf, &id); | |
| if (err < 0) { | |
| SNDERR("unable to get id"); | |
| return err; | |
| } | |
| err = snd_config_get_string(conf, &str); | |
| if (err < 0) { | |
| SNDERR("Invalid type for %s", id); | |
| return err; | |
| } | |
| err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf); | |
| if (err >= 0) { | |
| if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { | |
| SNDERR("Invalid type for RAWMIDI type %s definition", str); | |
| err = -EINVAL; | |
| goto _err; | |
| } | |
| snd_config_for_each(i, next, type_conf) { | |
| snd_config_t *n = snd_config_iterator_entry(i); | |
| const char *id; | |
| if (snd_config_get_id(n, &id) < 0) | |
| continue; | |
| if (strcmp(id, "comment") == 0) | |
| continue; | |
| if (strcmp(id, "lib") == 0) { | |
| err = snd_config_get_string(n, &lib); | |
| if (err < 0) { | |
| SNDERR("Invalid type for %s", id); | |
| goto _err; | |
| } | |
| continue; | |
| } | |
| if (strcmp(id, "open") == 0) { | |
| err = snd_config_get_string(n, &open_name); | |
| if (err < 0) { | |
| SNDERR("Invalid type for %s", id); | |
| goto _err; | |
| } | |
| continue; | |
| } | |
| SNDERR("Unknown field %s", id); | |
| err = -EINVAL; | |
| goto _err; | |
| } | |
| } | |
| if (!open_name) { | |
| open_name = buf; | |
| snprintf(buf, sizeof(buf), "_snd_rawmidi_%s_open", str); | |
| } | |
| #ifndef PIC | |
| snd_rawmidi_open_symbols(); | |
| #endif | |
| open_func = snd_dlobj_cache_get2(lib, open_name, | |
| SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1); | |
| if (!open_func) { | |
| err = -ENXIO; | |
| goto _err; | |
| } | |
| if (type_conf) | |
| snd_config_delete(type_conf); | |
| err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode); | |
| if (err < 0) | |
| goto _err; | |
| if (inputp) { | |
| (*inputp)->open_func = open_func; | |
| snd_rawmidi_params_default(*inputp, ¶ms); | |
| err = snd_rawmidi_params(*inputp, ¶ms); | |
| assert(err >= 0); | |
| } | |
| if (outputp) { | |
| (*outputp)->open_func = open_func; | |
| snd_rawmidi_params_default(*outputp, ¶ms); | |
| err = snd_rawmidi_params(*outputp, ¶ms); | |
| assert(err >= 0); | |
| } | |
| return 0; | |
| _err: | |
| if (open_func) | |
| snd_dlobj_cache_put(open_func); | |
| if (type_conf) | |
| snd_config_delete(type_conf); | |
| return err; | |
| } | |
| static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, | |
| snd_config_t *root, const char *name, int mode) | |
| { | |
| int err; | |
| snd_config_t *rawmidi_conf; | |
| err = snd_config_search_definition(root, "rawmidi", name, &rawmidi_conf); | |
| if (err < 0) { | |
| SNDERR("Unknown RawMidi %s", name); | |
| return err; | |
| } | |
| err = snd_rawmidi_open_conf(inputp, outputp, name, root, rawmidi_conf, mode); | |
| snd_config_delete(rawmidi_conf); | |
| return err; | |
| } | |
| /** | |
| * \brief Opens a new connection to the RawMidi interface. | |
| * \param inputp Returned input handle (NULL if not wanted) | |
| * \param outputp Returned output handle (NULL if not wanted) | |
| * \param name ASCII identifier of the RawMidi handle | |
| * \param mode Open mode | |
| * \return 0 on success otherwise a negative error code | |
| * | |
| * Opens a new connection to the RawMidi interface specified with | |
| * an ASCII identifier and mode. | |
| */ | |
| int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, | |
| const char *name, int mode) | |
| { | |
| snd_config_t *top; | |
| int err; | |
| assert((inputp || outputp) && name); | |
| if (_snd_is_ucm_device(name)) { | |
| name = uc_mgr_alibcfg_by_device(&top, name); | |
| if (name == NULL) | |
| return -ENODEV; | |
| } else { | |
| err = snd_config_update_ref(&top); | |
| if (err < 0) | |
| return err; | |
| } | |
| err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode); | |
| snd_config_unref(top); | |
| return err; | |
| } | |
| /** | |
| * \brief Opens a new connection to the RawMidi interface using local configuration | |
| * \param inputp Returned input handle (NULL if not wanted) | |
| * \param outputp Returned output handle (NULL if not wanted) | |
| * \param name ASCII identifier of the RawMidi handle | |
| * \param mode Open mode | |
| * \param lconf Local configuration | |
| * \return 0 on success otherwise a negative error code | |
| * | |
| * Opens a new connection to the RawMidi interface specified with | |
| * an ASCII identifier and mode. | |
| */ | |
| int snd_rawmidi_open_lconf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, | |
| const char *name, int mode, snd_config_t *lconf) | |
| { | |
| assert((inputp || outputp) && name && lconf); | |
| return snd_rawmidi_open_noupdate(inputp, outputp, lconf, name, mode); | |
| } | |
| /** | |
| * \brief close RawMidi handle | |
| * \param rawmidi RawMidi handle | |
| * \return 0 on success otherwise a negative error code | |
| * | |
| * Closes the specified RawMidi handle and frees all associated | |
| * resources. | |
| */ | |
| int snd_rawmidi_close(snd_rawmidi_t *rawmidi) | |
| { | |
| int err; | |
| assert(rawmidi); | |
| err = rawmidi->ops->close(rawmidi); | |
| free(rawmidi->name); | |
| if (rawmidi->open_func) | |
| snd_dlobj_cache_put(rawmidi->open_func); | |
| free(rawmidi); | |
| return err; | |
| } | |
| /** | |
| * \brief get identifier of RawMidi handle | |
| * \param rawmidi a RawMidi handle | |
| * \return ascii identifier of RawMidi handle | |
| * | |
| * Returns the ASCII identifier of given RawMidi handle. It's the same | |
| * identifier specified in snd_rawmidi_open(). | |
| */ | |
| const char *snd_rawmidi_name(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return rawmidi->name; | |
| } | |
| /** | |
| * \brief get type of RawMidi handle | |
| * \param rawmidi a RawMidi handle | |
| * \return type of RawMidi handle | |
| * | |
| * Returns the type #snd_rawmidi_type_t of given RawMidi handle. | |
| */ | |
| snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return rawmidi->type; | |
| } | |
| /** | |
| * \brief get stream (direction) of RawMidi handle | |
| * \param rawmidi a RawMidi handle | |
| * \return stream of RawMidi handle | |
| * | |
| * Returns the stream #snd_rawmidi_stream_t of given RawMidi handle. | |
| */ | |
| snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return rawmidi->stream; | |
| } | |
| /** | |
| * \brief get count of poll descriptors for RawMidi handle | |
| * \param rawmidi RawMidi handle | |
| * \return count of poll descriptors | |
| */ | |
| int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return 1; | |
| } | |
| /** | |
| * \brief get poll descriptors | |
| * \param rawmidi RawMidi handle | |
| * \param pfds array of poll descriptors | |
| * \param space space in the poll descriptor array | |
| * \return count of filled descriptors | |
| */ | |
| int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int space) | |
| { | |
| assert(rawmidi); | |
| if (space >= 1) { | |
| pfds->fd = rawmidi->poll_fd; | |
| pfds->events = rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| /** | |
| * \brief get returned events from poll descriptors | |
| * \param rawmidi rawmidi RawMidi handle | |
| * \param pfds array of poll descriptors | |
| * \param nfds count of poll descriptors | |
| * \param revents returned events | |
| * \return zero if success, otherwise a negative error code | |
| */ | |
| int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) | |
| { | |
| assert(rawmidi && pfds && revents); | |
| if (nfds == 1) { | |
| *revents = pfds->revents; | |
| return 0; | |
| } | |
| return -EINVAL; | |
| } | |
| /** | |
| * \brief set nonblock mode | |
| * \param rawmidi RawMidi handle | |
| * \param nonblock 0 = block, 1 = nonblock mode | |
| * \return 0 on success otherwise a negative error code | |
| * | |
| * The nonblock mode cannot be used when the stream is in | |
| * #SND_RAWMIDI_APPEND state. | |
| */ | |
| int snd_rawmidi_nonblock(snd_rawmidi_t *rawmidi, int nonblock) | |
| { | |
| int err; | |
| assert(rawmidi); | |
| assert(!(rawmidi->mode & SND_RAWMIDI_APPEND)); | |
| if ((err = rawmidi->ops->nonblock(rawmidi, nonblock)) < 0) | |
| return err; | |
| if (nonblock) | |
| rawmidi->mode |= SND_RAWMIDI_NONBLOCK; | |
| else | |
| rawmidi->mode &= ~SND_RAWMIDI_NONBLOCK; | |
| return 0; | |
| } | |
| /** | |
| * \brief get size of the snd_rawmidi_info_t structure in bytes | |
| * \return size of the snd_rawmidi_info_t structure in bytes | |
| */ | |
| size_t snd_rawmidi_info_sizeof() | |
| { | |
| return sizeof(snd_rawmidi_info_t); | |
| } | |
| /** | |
| * \brief allocate a new snd_rawmidi_info_t structure | |
| * \param info returned pointer | |
| * \return 0 on success otherwise a negative error code if fails | |
| * | |
| * Allocates a new snd_rawmidi_params_t structure using the standard | |
| * malloc C library function. | |
| */ | |
| int snd_rawmidi_info_malloc(snd_rawmidi_info_t **info) | |
| { | |
| assert(info); | |
| *info = calloc(1, sizeof(snd_rawmidi_info_t)); | |
| if (!*info) | |
| return -ENOMEM; | |
| return 0; | |
| } | |
| /** | |
| * \brief frees the snd_rawmidi_info_t structure | |
| * \param info pointer to the snd_rawmidi_info_t structure to free | |
| * | |
| * Frees the given snd_rawmidi_params_t structure using the standard | |
| * free C library function. | |
| */ | |
| void snd_rawmidi_info_free(snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| free(info); | |
| } | |
| /** | |
| * \brief copy one snd_rawmidi_info_t structure to another | |
| * \param dst destination snd_rawmidi_info_t structure | |
| * \param src source snd_rawmidi_info_t structure | |
| */ | |
| void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src) | |
| { | |
| assert(dst && src); | |
| *dst = *src; | |
| } | |
| /** | |
| * \brief get rawmidi device number | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi device number | |
| */ | |
| unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->device; | |
| } | |
| /** | |
| * \brief get rawmidi subdevice number | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi subdevice number | |
| */ | |
| unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->subdevice; | |
| } | |
| /** | |
| * \brief get rawmidi stream identification | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi stream identification | |
| */ | |
| snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->stream; | |
| } | |
| /** | |
| * \brief get rawmidi card number | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi card number | |
| */ | |
| int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->card; | |
| } | |
| /** | |
| * \brief get rawmidi flags | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi flags | |
| */ | |
| unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->flags; | |
| } | |
| /** | |
| * \brief get rawmidi hardware driver identifier | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi hardware driver identifier | |
| */ | |
| const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return (const char *)info->id; | |
| } | |
| /** | |
| * \brief get rawmidi hardware driver name | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi hardware driver name | |
| */ | |
| const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return (const char *)info->name; | |
| } | |
| /** | |
| * \brief get rawmidi subdevice name | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi subdevice name | |
| */ | |
| const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return (const char *)info->subname; | |
| } | |
| /** | |
| * \brief get rawmidi count of subdevices | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi count of subdevices | |
| */ | |
| unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->subdevices_count; | |
| } | |
| /** | |
| * \brief get rawmidi available count of subdevices | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \return rawmidi available count of subdevices | |
| */ | |
| unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *info) | |
| { | |
| assert(info); | |
| return info->subdevices_avail; | |
| } | |
| /** | |
| * \brief set rawmidi device number | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \param val device number | |
| */ | |
| void snd_rawmidi_info_set_device(snd_rawmidi_info_t *info, unsigned int val) | |
| { | |
| assert(info); | |
| info->device = val; | |
| } | |
| /** | |
| * \brief set rawmidi subdevice number | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \param val subdevice number | |
| */ | |
| void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *info, unsigned int val) | |
| { | |
| assert(info); | |
| info->subdevice = val; | |
| } | |
| /** | |
| * \brief set rawmidi stream identifier | |
| * \param info pointer to a snd_rawmidi_info_t structure | |
| * \param val rawmidi stream identifier | |
| */ | |
| void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *info, snd_rawmidi_stream_t val) | |
| { | |
| assert(info); | |
| info->stream = val; | |
| } | |
| /** | |
| * \brief get information about RawMidi handle | |
| * \param rawmidi RawMidi handle | |
| * \param info pointer to a snd_rawmidi_info_t structure to be filled | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| int snd_rawmidi_info(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t * info) | |
| { | |
| assert(rawmidi); | |
| assert(info); | |
| return rawmidi->ops->info(rawmidi, info); | |
| } | |
| /** | |
| * \brief get size of the snd_rawmidi_params_t structure in bytes | |
| * \return size of the snd_rawmidi_params_t structure in bytes | |
| */ | |
| size_t snd_rawmidi_params_sizeof() | |
| { | |
| return sizeof(snd_rawmidi_params_t); | |
| } | |
| /** | |
| * \brief allocate the snd_rawmidi_params_t structure | |
| * \param params returned pointer | |
| * \return 0 on success otherwise a negative error code if fails | |
| * | |
| * Allocates a new snd_rawmidi_params_t structure using the standard | |
| * malloc C library function. | |
| */ | |
| int snd_rawmidi_params_malloc(snd_rawmidi_params_t **params) | |
| { | |
| assert(params); | |
| *params = calloc(1, sizeof(snd_rawmidi_params_t)); | |
| if (!*params) | |
| return -ENOMEM; | |
| return 0; | |
| } | |
| /** | |
| * \brief frees the snd_rawmidi_params_t structure | |
| * \param params pointer to the #snd_rawmidi_params_t structure to free | |
| * | |
| * Frees the given snd_rawmidi_params_t structure using the standard | |
| * free C library function. | |
| */ | |
| void snd_rawmidi_params_free(snd_rawmidi_params_t *params) | |
| { | |
| assert(params); | |
| free(params); | |
| } | |
| /** | |
| * \brief copy one snd_rawmidi_params_t structure to another | |
| * \param dst destination snd_rawmidi_params_t structure | |
| * \param src source snd_rawmidi_params_t structure | |
| */ | |
| void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src) | |
| { | |
| assert(dst && src); | |
| *dst = *src; | |
| } | |
| /** | |
| * \brief set rawmidi I/O ring buffer size | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to a snd_rawmidi_params_t structure | |
| * \param val size in bytes | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| #ifndef DOXYGEN | |
| int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val) | |
| #else | |
| int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val) | |
| #endif | |
| { | |
| assert(rawmidi && params); | |
| assert(val > params->avail_min); | |
| params->buffer_size = val; | |
| return 0; | |
| } | |
| /** | |
| * \brief get rawmidi I/O ring buffer size | |
| * \param params pointer to a snd_rawmidi_params_t structure | |
| * \return size of rawmidi I/O ring buffer in bytes | |
| */ | |
| size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params) | |
| { | |
| assert(params); | |
| return params->buffer_size; | |
| } | |
| /** | |
| * \brief set minimum available bytes in rawmidi I/O ring buffer for wakeup | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to a snd_rawmidi_params_t structure | |
| * \param val desired value | |
| */ | |
| #ifndef DOXYGEN | |
| int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val) | |
| #else | |
| int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val) | |
| #endif | |
| { | |
| assert(rawmidi && params); | |
| assert(val < params->buffer_size); | |
| params->avail_min = val; | |
| return 0; | |
| } | |
| /** | |
| * \brief get minimum available bytes in rawmidi I/O ring buffer for wakeup | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \return minimum available bytes | |
| */ | |
| size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params) | |
| { | |
| assert(params); | |
| return params->avail_min; | |
| } | |
| /** | |
| * \brief set no-active-sensing action on snd_rawmidi_close() | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \param val value: 0 = enable to send the active sensing message, 1 = disable | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| #ifndef DOXYGEN | |
| int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, int val) | |
| #else | |
| int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, int val) | |
| #endif | |
| { | |
| assert(rawmidi && params); | |
| params->no_active_sensing = val; | |
| return 0; | |
| } | |
| /** | |
| * \brief get no-active-sensing action status | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \return the current status (0 = enable, 1 = disable the active sensing message) | |
| */ | |
| int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params) | |
| { | |
| assert(params); | |
| return params->no_active_sensing; | |
| } | |
| /** | |
| * \brief set read mode | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \param val type of read_mode | |
| * \return 0 on success, otherwise a negative error code. | |
| * | |
| * Notable error codes: | |
| * -EINVAL - "val" is invalid | |
| * -ENOTSUP - mode is not supported | |
| * | |
| */ | |
| int snd_rawmidi_params_set_read_mode(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_read_mode_t val) | |
| { | |
| unsigned int framing; | |
| assert(rawmidi && params); | |
| switch (val) { | |
| case SND_RAWMIDI_READ_STANDARD: | |
| framing = SNDRV_RAWMIDI_MODE_FRAMING_NONE; | |
| break; | |
| case SND_RAWMIDI_READ_TSTAMP: | |
| if (rawmidi->ops->tread == NULL) | |
| return -ENOTSUP; | |
| framing = SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP; | |
| break; | |
| default: | |
| return -EINVAL; | |
| } | |
| if (framing != SNDRV_RAWMIDI_MODE_FRAMING_NONE && | |
| (rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT)) | |
| return -ENOTSUP; | |
| params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_FRAMING_MASK) | framing; | |
| return 0; | |
| } | |
| /** | |
| * \brief get current read mode | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \return the current read mode (see enum) | |
| */ | |
| snd_rawmidi_read_mode_t snd_rawmidi_params_get_read_mode(const snd_rawmidi_params_t *params) | |
| { | |
| unsigned int framing; | |
| assert(params); | |
| framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; | |
| if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) | |
| return SND_RAWMIDI_READ_TSTAMP; | |
| return SND_RAWMIDI_READ_STANDARD; | |
| } | |
| /** | |
| * \brief sets clock type for tstamp type framing | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \param val one of the SND_RAWMIDI_CLOCK_* constants | |
| * \return 0 on success, otherwise a negative error code. | |
| * | |
| * Notable error codes: | |
| * -EINVAL - "val" is invalid | |
| * -ENOTSUP - Kernel is too old to support framing. | |
| * | |
| */ | |
| int snd_rawmidi_params_set_clock_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_clock_t val) | |
| { | |
| assert(rawmidi && params); | |
| if (val > SNDRV_RAWMIDI_MODE_CLOCK_MASK >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT) | |
| return -EINVAL; | |
| if (val != SNDRV_RAWMIDI_MODE_CLOCK_NONE && | |
| (rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT)) | |
| return -ENOTSUP; | |
| params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_CLOCK_MASK) + (val << SNDRV_RAWMIDI_MODE_CLOCK_SHIFT); | |
| return 0; | |
| } | |
| /** | |
| * \brief get current clock type (for tstamp type framing) | |
| * \param params pointer to snd_rawmidi_params_t structure | |
| * \return the current clock type (one of the SND_RAWMIDI_CLOCK_* constants) | |
| */ | |
| snd_rawmidi_clock_t snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t *params) | |
| { | |
| assert(params); | |
| return (params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK) >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT; | |
| } | |
| /** | |
| * \brief set parameters about rawmidi stream | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to a snd_rawmidi_params_t structure to be filled | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| int snd_rawmidi_params(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t * params) | |
| { | |
| int err; | |
| assert(rawmidi); | |
| assert(params); | |
| err = rawmidi->ops->params(rawmidi, params); | |
| if (err < 0) | |
| return err; | |
| rawmidi->buffer_size = params->buffer_size; | |
| rawmidi->avail_min = params->avail_min; | |
| rawmidi->no_active_sensing = params->no_active_sensing; | |
| rawmidi->params_mode = rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) ? 0 : params->mode; | |
| return 0; | |
| } | |
| /** | |
| * \brief get current parameters about rawmidi stream | |
| * \param rawmidi RawMidi handle | |
| * \param params pointer to a snd_rawmidi_params_t structure to be filled | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| int snd_rawmidi_params_current(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params) | |
| { | |
| assert(rawmidi); | |
| assert(params); | |
| params->buffer_size = rawmidi->buffer_size; | |
| params->avail_min = rawmidi->avail_min; | |
| params->no_active_sensing = rawmidi->no_active_sensing; | |
| params->mode = rawmidi->params_mode; | |
| return 0; | |
| } | |
| /** | |
| * \brief get size of the snd_rawmidi_status_t structure in bytes | |
| * \return size of the snd_rawmidi_status_t structure in bytes | |
| */ | |
| size_t snd_rawmidi_status_sizeof() | |
| { | |
| return sizeof(snd_rawmidi_status_t); | |
| } | |
| /** | |
| * \brief allocate the snd_rawmidi_status_t structure | |
| * \param ptr returned pointer | |
| * \return 0 on success otherwise a negative error code if fails | |
| * | |
| * Allocates a new snd_rawmidi_status_t structure using the standard | |
| * malloc C library function. | |
| */ | |
| int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr) | |
| { | |
| assert(ptr); | |
| *ptr = calloc(1, sizeof(snd_rawmidi_status_t)); | |
| if (!*ptr) | |
| return -ENOMEM; | |
| return 0; | |
| } | |
| /** | |
| * \brief frees the snd_rawmidi_status_t structure | |
| * \param status pointer to the snd_rawmidi_status_t structure to free | |
| * | |
| * Frees the given snd_rawmidi_status_t structure using the standard | |
| * free C library function. | |
| */ | |
| void snd_rawmidi_status_free(snd_rawmidi_status_t *status) | |
| { | |
| assert(status); | |
| free(status); | |
| } | |
| /** | |
| * \brief copy one snd_rawmidi_status_t structure to another | |
| * \param dst destination snd_rawmidi_status_t structure | |
| * \param src source snd_rawmidi_status_t structure | |
| */ | |
| void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src) | |
| { | |
| assert(dst && src); | |
| *dst = *src; | |
| } | |
| /** | |
| * \brief get the start timestamp | |
| * \param status pointer to a snd_rawmidi_status_t structure | |
| * \param tstamp returned timestamp value | |
| */ | |
| void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *status, snd_htimestamp_t *tstamp) | |
| { | |
| assert(status && tstamp); | |
| *tstamp = status->tstamp; | |
| } | |
| /** | |
| * \brief get current available bytes in the rawmidi I/O ring buffer | |
| * \param status pointer to a snd_rawmidi_status_t structure | |
| * \return current available bytes in the rawmidi I/O ring buffer | |
| */ | |
| size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *status) | |
| { | |
| assert(status); | |
| return status->avail; | |
| } | |
| /** | |
| * \brief get count of xruns | |
| * \param status pointer to a snd_rawmidi_status_t structure | |
| * \return count of xruns | |
| */ | |
| size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *status) | |
| { | |
| assert(status); | |
| return status->xruns; | |
| } | |
| /** | |
| * \brief get status of rawmidi stream | |
| * \param rawmidi RawMidi handle | |
| * \param status pointer to a snd_rawmidi_status_t structure to be filled | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| int snd_rawmidi_status(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t * status) | |
| { | |
| assert(rawmidi); | |
| assert(status); | |
| return rawmidi->ops->status(rawmidi, status); | |
| } | |
| /** | |
| * \brief drop all bytes in the rawmidi I/O ring buffer immediately | |
| * \param rawmidi RawMidi handle | |
| * \return 0 on success otherwise a negative error code | |
| */ | |
| int snd_rawmidi_drop(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return rawmidi->ops->drop(rawmidi); | |
| } | |
| /** | |
| * \brief drain all bytes in the rawmidi I/O ring buffer | |
| * \param rawmidi RawMidi handle | |
| * \return 0 on success otherwise a negative error code | |
| * | |
| * Waits until all MIDI bytes are not drained (sent) to the | |
| * hardware device. | |
| */ | |
| int snd_rawmidi_drain(snd_rawmidi_t *rawmidi) | |
| { | |
| assert(rawmidi); | |
| return rawmidi->ops->drain(rawmidi); | |
| } | |
| /** | |
| * \brief write MIDI bytes to MIDI stream | |
| * \param rawmidi RawMidi handle | |
| * \param buffer buffer containing MIDI bytes | |
| * \param size output buffer size in bytes | |
| */ | |
| ssize_t snd_rawmidi_write(snd_rawmidi_t *rawmidi, const void *buffer, size_t size) | |
| { | |
| assert(rawmidi); | |
| assert(rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT); | |
| assert(buffer || size == 0); | |
| return rawmidi->ops->write(rawmidi, buffer, size); | |
| } | |
| /** | |
| * \brief read MIDI bytes from MIDI stream | |
| * \param rawmidi RawMidi handle | |
| * \param buffer buffer to store the input MIDI bytes | |
| * \param size input buffer size in bytes | |
| * \retval count of MIDI bytes otherwise a negative error code | |
| */ | |
| ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size) | |
| { | |
| assert(rawmidi); | |
| assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); | |
| if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) | |
| size &= ~(sizeof(struct snd_rawmidi_framing_tstamp) - 1); | |
| assert(buffer || size == 0); | |
| return (rawmidi->ops->read)(rawmidi, buffer, size); | |
| } | |
| /** | |
| * \brief read MIDI bytes from MIDI stream with timestamp | |
| * \param rawmidi RawMidi handle | |
| * \param[out] tstamp timestamp for the returned MIDI bytes | |
| * \param buffer buffer to store the input MIDI bytes | |
| * \param size input buffer size in bytes | |
| * \retval count of MIDI bytes otherwise a negative error code | |
| */ | |
| ssize_t snd_rawmidi_tread(snd_rawmidi_t *rawmidi, struct timespec *tstamp, void *buffer, size_t size) | |
| { | |
| assert(rawmidi); | |
| assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); | |
| assert(buffer || size == 0); | |
| if ((rawmidi->params_mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) != SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) | |
| return -EINVAL; | |
| if (rawmidi->ops->tread == NULL) | |
| return -ENOTSUP; | |
| return (rawmidi->ops->tread)(rawmidi, tstamp, buffer, size); | |
| } | |
| #ifndef DOXYGEN | |
| /* | |
| * internal API functions for obtaining UMP info from rawmidi instance | |
| */ | |
| int _snd_rawmidi_ump_endpoint_info(snd_rawmidi_t *rmidi, void *info) | |
| { | |
| if (!rmidi->ops->ump_endpoint_info) | |
| return -ENXIO; | |
| return rmidi->ops->ump_endpoint_info(rmidi, info); | |
| } | |
| int _snd_rawmidi_ump_block_info(snd_rawmidi_t *rmidi, void *info) | |
| { | |
| if (!rmidi->ops->ump_block_info) | |
| return -ENXIO; | |
| return rmidi->ops->ump_block_info(rmidi, info); | |
| } | |
| #endif /* DOXYGEN */ |