summaryrefslogtreecommitdiff
path: root/lib/libsalsa
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libsalsa')
-rw-r--r--lib/libsalsa/.config2
-rw-r--r--lib/libsalsa/.nativemake0
-rw-r--r--lib/libsalsa/Makefile60
-rw-r--r--lib/libsalsa/README34
-rw-r--r--lib/libsalsa/Versions162
-rw-r--r--lib/libsalsa/alsa-symbols.h66
-rw-r--r--lib/libsalsa/alsakernel.h108
-rw-r--r--lib/libsalsa/local.h98
-rw-r--r--lib/libsalsa/main.c498
-rw-r--r--lib/libsalsa/misc.c107
-rw-r--r--lib/libsalsa/mix.c1125
-rw-r--r--lib/libsalsa/output.c411
-rw-r--r--lib/libsalsa/pcm.c3114
-rw-r--r--lib/libsalsa/rawmidi.c236
-rw-r--r--lib/libsalsa/seq.c2230
-rw-r--r--lib/libsalsa/seq_input.c136
-rw-r--r--lib/libsalsa/seq_output.c315
-rw-r--r--lib/libsalsa/seqmid.c205
-rw-r--r--lib/libsalsa/stubs.c59
-rw-r--r--lib/libsalsa/timer.c361
20 files changed, 9327 insertions, 0 deletions
diff --git a/lib/libsalsa/.config b/lib/libsalsa/.config
new file mode 100644
index 0000000..4094239
--- /dev/null
+++ b/lib/libsalsa/.config
@@ -0,0 +1,2 @@
+targetos=Linux
+depends=ALSA
diff --git a/lib/libsalsa/.nativemake b/lib/libsalsa/.nativemake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/libsalsa/.nativemake
diff --git a/lib/libsalsa/Makefile b/lib/libsalsa/Makefile
new file mode 100644
index 0000000..5f8216b
--- /dev/null
+++ b/lib/libsalsa/Makefile
@@ -0,0 +1,60 @@
+LOBJECTS=main.lo output.lo misc.lo pcm.lo mix.lo seq.lo seqmid.lo rawmidi.lo seq_output.lo timer.lo stubs.lo seq_input.lo
+
+OSSLIBDIR=/usr/lib/oss
+
+CFLAGS=-O -I../../include -I../libOSSlib
+LIBTOOL=libtool --tag=CC
+
+all: libsalsa.la
+
+*.lo: local.h
+
+main.lo: main.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c main.c
+
+pcm.lo: pcm.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c pcm.c
+
+misc.lo: misc.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c misc.c
+
+stubs.lo: stubs.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c stubs.c
+
+mix.lo: mix.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c mix.c
+
+output.lo: output.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c output.c
+
+seq.lo: seq.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq.c
+
+timer.lo: timer.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c timer.c
+
+seqmid.lo: seqmid.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seqmid.c
+
+seq_input.lo: seq_input.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq_input.c
+
+seq_output.lo: seq_output.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq_output.c
+
+rawmidi.lo: rawmidi.c
+ $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c rawmidi.c
+
+libsalsa.la: $(LOBJECTS)
+ $(LIBTOOL) --mode=link ${CC} -rpath /usr/lib -Wl,--version-script=Versions -version-info 2:0:0 -o libsalsa.la $(LOBJECTS) -L../libOSSlib -lOSSlib
+
+install: libsalsa.la
+ $(LIBTOOL) cp libsalsa.la /usr/lib
+ (cd /usr/lib;ln -sf libsalsa.so.2.0.0 libasound.so)
+ (cd /usr/lib;ln -sf libsalsa.so.2.0.0 libasound.so.2)
+
+dep:
+
+clean:
+ rm -f core core.* *.o *.a *.lo *.so *.loT *.la x y z *.s
+ rm -rf .libs
diff --git a/lib/libsalsa/README b/lib/libsalsa/README
new file mode 100644
index 0000000..e201b5c
--- /dev/null
+++ b/lib/libsalsa/README
@@ -0,0 +1,34 @@
+SALSA - Simple ALSA emulation library for OSS
+=============================================
+
+The sole purpose of this library is to make certain key ALSA applications
+to work with OSS. This is necessary just because some Linux distributions
+don't ship utilities like esd or xmss with OSS support compiled in.
+
+This library has been programmed using brute force methods and it's
+not designed to be any programming example. We didn't make any attempt to get
+all ALSA applications to work with it. Most applications support the OSS
+API directly so there is no need for doing this.
+
+We do not have any specific plans to develop this library any further. However
+some changes will be made occasionally.
+
+Copying
+-------
+
+The seqmid.c, alsakernel.h, alsa-symbols.h and output.c files have been
+copied more or less from stock alsa-lib and they have been copyrighted by the
+ALSA team members. All parts of this package are distributed under GNU GPL
+version 2.1.
+
+Installing and compiling the library
+------------------------------------
+
+The precompiled library is already shipped as a part of the OSS package
+for Linux 2.6.x and later kernels so there should be no reason to recompile
+it. This library is not applicable under any other operating systems or Linux
+versions.
+
+To compile the library you can execute "make". "make install" will install
+the library (libsalsa.so.2.0.0) to /usr/lib and then change the required
+libasound.so.* symbolic links to point to it.
diff --git a/lib/libsalsa/Versions b/lib/libsalsa/Versions
new file mode 100644
index 0000000..c4d3065
--- /dev/null
+++ b/lib/libsalsa/Versions
@@ -0,0 +1,162 @@
+ALSA_0.9 {
+ global:
+ __snd_*;
+ _snd_*;
+ snd_*;
+ local:
+ *;
+};
+
+ALSA_0.9.0rc4 {
+ global:
+
+ snd_pcm_hw_params_get_access;
+ snd_pcm_hw_params_set_access_first;
+ snd_pcm_hw_params_set_access_last;
+
+ snd_pcm_hw_params_get_format;
+ snd_pcm_hw_params_set_format_first;
+ snd_pcm_hw_params_set_format_last;
+
+ snd_pcm_hw_params_get_subformat;
+ snd_pcm_hw_params_set_subformat_first;
+ snd_pcm_hw_params_set_subformat_last;
+
+ snd_pcm_hw_params_get_channels;
+ snd_pcm_hw_params_get_channels_min;
+ snd_pcm_hw_params_get_channels_max;
+ snd_pcm_hw_params_set_channels_near;
+ snd_pcm_hw_params_set_channels_first;
+ snd_pcm_hw_params_set_channels_last;
+
+ snd_pcm_hw_params_get_rate;
+ snd_pcm_hw_params_get_rate_min;
+ snd_pcm_hw_params_get_rate_max;
+ snd_pcm_hw_params_set_rate_near;
+ snd_pcm_hw_params_set_rate_first;
+ snd_pcm_hw_params_set_rate_last;
+
+ snd_pcm_hw_params_get_period_time;
+ snd_pcm_hw_params_get_period_time_min;
+ snd_pcm_hw_params_get_period_time_max;
+ snd_pcm_hw_params_set_period_time_near;
+ snd_pcm_hw_params_set_period_time_first;
+ snd_pcm_hw_params_set_period_time_last;
+
+ snd_pcm_hw_params_get_period_size;
+ snd_pcm_hw_params_get_period_size_min;
+ snd_pcm_hw_params_get_period_size_max;
+ snd_pcm_hw_params_set_period_size_near;
+ snd_pcm_hw_params_set_period_size_first;
+ snd_pcm_hw_params_set_period_size_last;
+
+ snd_pcm_hw_params_get_periods;
+ snd_pcm_hw_params_get_periods_min;
+ snd_pcm_hw_params_get_periods_max;
+ snd_pcm_hw_params_set_periods_near;
+ snd_pcm_hw_params_set_periods_first;
+ snd_pcm_hw_params_set_periods_last;
+
+ snd_pcm_hw_params_get_buffer_time;
+ snd_pcm_hw_params_get_buffer_time_min;
+ snd_pcm_hw_params_get_buffer_time_max;
+ snd_pcm_hw_params_set_buffer_time_near;
+ snd_pcm_hw_params_set_buffer_time_first;
+ snd_pcm_hw_params_set_buffer_time_last;
+
+ snd_pcm_hw_params_get_buffer_size;
+ snd_pcm_hw_params_get_buffer_size_min;
+ snd_pcm_hw_params_get_buffer_size_max;
+ snd_pcm_hw_params_set_buffer_size_near;
+ snd_pcm_hw_params_set_buffer_size_first;
+ snd_pcm_hw_params_set_buffer_size_last;
+
+ snd_pcm_hw_params_get_tick_time;
+ snd_pcm_hw_params_get_tick_time_min;
+ snd_pcm_hw_params_get_tick_time_max;
+ snd_pcm_hw_params_set_tick_time_near;
+ snd_pcm_hw_params_set_tick_time_first;
+ snd_pcm_hw_params_set_tick_time_last;
+
+} ALSA_0.9;
+
+ALSA_0.9.0rc8 {
+ global:
+
+ snd_pcm_forward;
+ snd_pcm_status_get_trigger_htstamp;
+ snd_pcm_status_get_htstamp;
+
+} ALSA_0.9.0rc4;
+
+ALSA_0.9.0 {
+ global:
+
+ snd_pcm_type_name;
+ snd_timer_query_info;
+ snd_timer_query_params;
+ snd_timer_query_status;
+ snd_timer_params_set_exclusive;
+ snd_timer_params_get_exclusive;
+ snd_timer_params_set_filter;
+ snd_timer_params_get_filter;
+} ALSA_0.9.0rc8;
+
+ALSA_0.9.3 {
+ global:
+
+ snd_ctl_elem_info_get_dimensions;
+ snd_ctl_elem_info_get_dimension;
+} ALSA_0.9.0;
+
+ALSA_0.9.5 {
+ global:
+
+ alsa_lisp;
+} ALSA_0.9.3;
+
+ALSA_0.9.6 {
+ global:
+
+ snd_hctl_open_ctl;
+ snd_seq_port_info_get_timestamping;
+ snd_seq_port_info_get_timestamp_real;
+ snd_seq_port_info_get_timestamp_queue;
+ snd_seq_port_info_set_timestamping;
+ snd_seq_port_info_set_timestamp_real;
+ snd_seq_port_info_set_timestamp_queue;
+} ALSA_0.9.5;
+
+ALSA_0.9.7 {
+ global:
+
+ snd_user_file;
+ snd_hctl_ctl;
+ sndo_*;
+ alsa_lisp_*;
+} ALSA_0.9.6;
+
+ALSA_0.9.8 {
+ global:
+
+ snd_ctl_elem_add;
+ snd_ctl_elem_replace;
+ snd_ctl_elem_remove;
+ snd_hctl_poll_descriptors_revents;
+} ALSA_0.9.7;
+
+ALSA_1.0.4 {
+ global:
+
+ snd_spcm_init;
+ snd_spcm_init_duplex;
+ snd_spcm_init_get_params;
+} ALSA_0.9.8;
+
+ALSA_1.0.5 {
+ global:
+
+ snd_asoundlib_version;
+ snd_timer_params_set_early_event;
+ snd_timer_params_get_early_event;
+} ALSA_1.0.4;
diff --git a/lib/libsalsa/alsa-symbols.h b/lib/libsalsa/alsa-symbols.h
new file mode 100644
index 0000000..692846c
--- /dev/null
+++ b/lib/libsalsa/alsa-symbols.h
@@ -0,0 +1,66 @@
+/*
+ * ALSA lib - dynamic symbol versions
+ * Copyright (c) 2002 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ALSA_SYMBOLS_H
+#define __ALSA_SYMBOLS_H
+
+#if defined(PIC) && defined(VERSIONED_SYMBOLS) /* might be also configurable */
+#define USE_VERSIONED_SYMBOLS
+#endif
+
+#define INTERNAL_CONCAT2_2(Pre, Post) Pre##Post
+#define INTERNAL(Name) INTERNAL_CONCAT2_2(__, Name)
+
+#ifdef __powerpc64__
+# define symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@" #version); \
+ __asm__ (".symver ." #real ",." #name "@" #version)
+# define default_symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@@" #version); \
+ __asm__ (".symver ." #real ",." #name "@@" #version)
+#else
+# define symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@" #version)
+# define default_symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@@" #version)
+#endif
+
+#ifdef USE_VERSIONED_SYMBOLS
+#define use_symbol_version(real, name, version) \
+ symbol_version(real, name, version)
+#define use_default_symbol_version(real, name, version) \
+ default_symbol_version(real, name, version)
+#else
+#define use_symbol_version(real, name, version) /* nothing */
+#ifdef __powerpc64__
+#define use_default_symbol_version(real, name, version) \
+ __asm__ (".weak " #name); \
+ __asm__ (".weak ." #name); \
+ __asm__ (".set " #name "," #real); \
+ __asm__ (".set ." #name ",." #real)
+#else
+#define use_default_symbol_version(real, name, version) \
+ __asm__ (".weak " #name); \
+ __asm__ (".set " #name "," #real)
+#endif
+#endif
+
+#endif /* __ALSA_SYMBOLS_H */
diff --git a/lib/libsalsa/alsakernel.h b/lib/libsalsa/alsakernel.h
new file mode 100644
index 0000000..1e1fb52
--- /dev/null
+++ b/lib/libsalsa/alsakernel.h
@@ -0,0 +1,108 @@
+
+enum sndrv_pcm_format
+{
+ SNDRV_PCM_FORMAT_S8 = 0,
+ SNDRV_PCM_FORMAT_U8,
+ SNDRV_PCM_FORMAT_S16_LE,
+ SNDRV_PCM_FORMAT_S16_BE,
+ SNDRV_PCM_FORMAT_U16_LE,
+ SNDRV_PCM_FORMAT_U16_BE,
+ SNDRV_PCM_FORMAT_S24_LE, /* low three bytes */
+ SNDRV_PCM_FORMAT_S24_BE, /* low three bytes */
+ SNDRV_PCM_FORMAT_U24_LE, /* low three bytes */
+ SNDRV_PCM_FORMAT_U24_BE, /* low three bytes */
+ SNDRV_PCM_FORMAT_S32_LE,
+ SNDRV_PCM_FORMAT_S32_BE,
+ SNDRV_PCM_FORMAT_U32_LE,
+ SNDRV_PCM_FORMAT_U32_BE,
+ SNDRV_PCM_FORMAT_FLOAT_LE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+ SNDRV_PCM_FORMAT_FLOAT_BE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+ SNDRV_PCM_FORMAT_FLOAT64_LE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+ SNDRV_PCM_FORMAT_FLOAT64_BE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+ SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, /* IEC-958 subframe, Little Endian */
+ SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, /* IEC-958 subframe, Big Endian */
+ SNDRV_PCM_FORMAT_MU_LAW,
+ SNDRV_PCM_FORMAT_A_LAW,
+ SNDRV_PCM_FORMAT_IMA_ADPCM,
+ SNDRV_PCM_FORMAT_MPEG,
+ SNDRV_PCM_FORMAT_GSM,
+ SNDRV_PCM_FORMAT_SPECIAL = 31,
+ SNDRV_PCM_FORMAT_S24_3LE = 32, /* in three bytes */
+ SNDRV_PCM_FORMAT_S24_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U24_3LE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U24_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_S20_3LE, /* in three bytes */
+ SNDRV_PCM_FORMAT_S20_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U20_3LE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U20_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_S18_3LE, /* in three bytes */
+ SNDRV_PCM_FORMAT_S18_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U18_3LE, /* in three bytes */
+ SNDRV_PCM_FORMAT_U18_3BE, /* in three bytes */
+ SNDRV_PCM_FORMAT_LAST = SNDRV_PCM_FORMAT_U18_3BE,
+
+#ifdef SNDRV_LITTLE_ENDIAN
+ SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_LE,
+ SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_LE,
+ SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_LE,
+ SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_LE,
+ SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_LE,
+ SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_LE,
+ SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_LE,
+ SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_LE,
+ SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE,
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+ SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_BE,
+ SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_BE,
+ SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_BE,
+ SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_BE,
+ SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_BE,
+ SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_BE,
+ SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_BE,
+ SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_BE,
+ SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE,
+#endif
+};
+
+#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
+static const char *snd_pcm_format_names[] = {
+ FORMAT (S8),
+ FORMAT (U8),
+ FORMAT (S16_LE),
+ FORMAT (S16_BE),
+ FORMAT (U16_LE),
+ FORMAT (U16_BE),
+ FORMAT (S24_LE),
+ FORMAT (S24_BE),
+ FORMAT (U24_LE),
+ FORMAT (U24_BE),
+ FORMAT (S32_LE),
+ FORMAT (S32_BE),
+ FORMAT (U32_LE),
+ FORMAT (U32_BE),
+ FORMAT (FLOAT_LE),
+ FORMAT (FLOAT_BE),
+ FORMAT (FLOAT64_LE),
+ FORMAT (FLOAT64_BE),
+ FORMAT (IEC958_SUBFRAME_LE),
+ FORMAT (IEC958_SUBFRAME_BE),
+ FORMAT (MU_LAW),
+ FORMAT (A_LAW),
+ FORMAT (IMA_ADPCM),
+ FORMAT (MPEG),
+ FORMAT (GSM),
+ FORMAT (SPECIAL),
+ FORMAT (S24_3LE),
+ FORMAT (S24_3BE),
+ FORMAT (U24_3LE),
+ FORMAT (U24_3BE),
+ FORMAT (S20_3LE),
+ FORMAT (S20_3BE),
+ FORMAT (U20_3LE),
+ FORMAT (U20_3BE),
+ FORMAT (S18_3LE),
+ FORMAT (S18_3BE),
+ FORMAT (U18_3LE),
+ FORMAT (U18_3BE),
+};
diff --git a/lib/libsalsa/local.h b/lib/libsalsa/local.h
new file mode 100644
index 0000000..5c87ebc
--- /dev/null
+++ b/lib/libsalsa/local.h
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "alsa-symbols.h"
+#include <alsa/asoundlib.h>
+#include "../../include/soundcard.h"
+#include "alsakernel.h"
+#include <sys/poll.h>
+#include "../../kernel/framework/include/midiparser.h"
+
+extern int alib_verbose;
+extern int mixer_fd;
+
+extern char alib_appname[64];
+
+extern oss_sysinfo sysinfo;
+
+#define dbg_printf if (alib_verbose>0)printf
+#define dbg_printf0 if (alib_verbose>=0)printf
+#define dbg_printf1 if (alib_verbose>=1)printf
+#define dbg_printf2 if (alib_verbose>=2)printf
+#define dbg_printf3 if (alib_verbose>=3)printf
+
+extern int alib_initialized;
+
+extern int init_alib (void);
+
+#define ALIB_INIT() \
+{ \
+ int init_err; \
+ if (!alib_initialized) \
+ if ((init_err=alib_init())<0) \
+ return init_err; \
+}
+
+struct _snd_pcm_info
+{
+ oss_audioinfo *ainfo;
+};
+
+
+extern int alib_appcheck (void);
+
+struct _snd_seq_port_info
+{
+ oss_longname_t name;
+ int port;
+ int capability;
+ int midi_channels;
+ int synth_voices;
+ int midi_voices;
+ int type;
+};
+
+struct _snd_seq_client_info
+{
+ oss_longname_t name;
+ int client;
+};
+
+/* Size of the local event buffer */
+#define MAX_EVENTS 128
+
+struct _snd_seq
+{
+ int fd;
+ int streams;
+ int nonblock;
+ int oss_mode;
+ oss_longname_t name;
+ midiparser_common_t *parser;
+
+ snd_seq_event_t events[MAX_EVENTS];
+ int nevents, nextevent;
+};
+
+struct _snd_rawmidi_info
+{
+ int dummy;
+};
+
+struct _snd_seq_queue_status
+{
+ int dummy;
+};
+
+struct _snd_seq_queue_timer
+{
+ int dummy;
+};
+
+extern int convert_event (snd_seq_t * seq, snd_seq_event_t * ev);
+extern void midiparser_callback (void *context, int category,
+ unsigned char msg, unsigned char ch,
+ unsigned char *parms, int len);
diff --git a/lib/libsalsa/main.c b/lib/libsalsa/main.c
new file mode 100644
index 0000000..34c8c22
--- /dev/null
+++ b/lib/libsalsa/main.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * Parts of the code is derived from the alsa-lib package that is
+ * copyrighted by Jaroslav Kysela and the other ALSA team members.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "local.h"
+
+int mixer_fd = -1;
+int alib_initialized = 0;
+
+oss_sysinfo sysinfo = { 0 };
+struct _snd_ctl
+{
+ oss_card_info info;
+ oss_audioinfo ainfo;
+};
+
+int alib_verbose = 0;
+
+int
+alib_init (void)
+{
+ char *p;
+ char *devmixer;
+
+ if ((devmixer=getenv("OSS_MIXERDEV"))==NULL)
+ devmixer = "/dev/mixer";
+
+ if ((p = getenv ("ALIB_DEBUG")) != NULL)
+ alib_verbose = atoi (p);
+
+ if (mixer_fd == -1)
+ {
+ if ((mixer_fd = open (devmixer, O_RDONLY, 0)) == -1)
+ return -errno;
+ }
+
+ if (ioctl (mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1)
+ {
+ perror ("SNDCTL_SYSINFO");
+ return -errno;
+ }
+
+ return 0;
+}
+
+char alib_appname[64] = "salsa";
+
+int
+alib_appcheck (void)
+{
+ /*
+ * Some programs are known to support OSS at the same time with ALSA.
+ * Prevent them from using this library accidently.
+ */
+
+ static int done = 0;
+
+ if (done)
+ return 1;
+
+ done = 1;
+
+ typedef struct
+ {
+ char *name, *msg, *action;
+ } prog_t;
+
+ static const prog_t banned_programs[] = {
+ {"artsd", "Please use 'artsd -a oss' instead.", NULL},
+ {"kcontrol", NULL, NULL},
+ {"kmid", NULL, NULL},
+ {"krec", NULL, NULL},
+ {"kplay", NULL, NULL},
+ {"kamix", "Please use ossxmix instead", NULL},
+ {"qamix", "Please use ossxmix instead", NULL},
+ NULL
+ };
+
+ static const char *whitelist[] = {
+ "esd",
+ "kmix",
+ "gnome-volume-control",
+ "artsd",
+ "xmms",
+ "alsaplayer",
+ "aplay",
+ "alsamixer",
+ "vkeybd",
+ NULL
+ };
+
+ FILE *f;
+ char tmp[64], *p, *cmd = tmp;
+ int i;
+ static int warned = 0;
+
+ if ((f = fopen ("/proc/self/cmdline", "r")) == NULL)
+ return 1;
+
+ if (fgets (tmp, sizeof (tmp) - 1, f) == NULL)
+ {
+ fclose (f);
+ return 1;
+ }
+
+ fclose (f);
+
+ p = cmd;
+
+ while (*p && (*p != ' ' && *p != '\n'))
+ p++;
+ *p = 0;
+
+ p = cmd = tmp;
+ while (*p)
+ {
+ if (*p == '/')
+ cmd = p + 1;
+ p++;
+ }
+
+ strcpy (alib_appname, cmd);
+
+ for (i = 0; i < strlen (alib_appname); i++)
+ if (alib_appname[i] < 'a' || alib_appname[i] > 'z')
+ if (alib_appname[i] < 'A' || alib_appname[i] > 'Z')
+ if (alib_appname[i] < '0' || alib_appname[i] > '9')
+ alib_appname[i] = '_';
+
+ for (i = 0; banned_programs[i].name != NULL; i++)
+ if (strcmp (banned_programs[i].name, cmd) == 0)
+ {
+ if (alib_verbose != 0)
+ {
+ return 1;
+ }
+ fprintf (stderr,
+ "\n\n************** WARNING ***********************\n");
+ fprintf (stderr, "This program (%s) should not use ALSA emulation\n",
+ cmd);
+ if (banned_programs[i].msg != NULL)
+ fprintf (stderr, "%s\n", banned_programs[i].msg);
+ fprintf (stderr,
+ "**************************************************\n\n");
+
+ if (banned_programs[i].action != NULL)
+ {
+ if (fork () == 0)
+ {
+ exit (system (banned_programs[i].action));
+ }
+ while (wait () != -1);
+ exit (1);
+ }
+ return 0;
+ }
+
+ if (alib_verbose == 0)
+ {
+ int ok = 0;
+
+ for (i = 0; !ok && whitelist[i] != NULL; i++)
+ if (strcmp (cmd, whitelist[i]) == 0)
+ ok = 1;
+
+
+ if (!ok)
+ return 0;
+ }
+
+ if (!warned)
+ {
+ fprintf (stderr,
+ "\n\n******************** WARNING *******************************\n");
+ fprintf (stderr,
+ "Warning! %s uses ALSA emulation instead of the native OSS API\n",
+ cmd);
+ fprintf (stderr,
+ "****************************************************************\n\n");
+ }
+ warned = 1;
+ return 1;
+}
+
+typedef struct _snd_ctl_card_info
+{
+ oss_card_info *info;
+} snd_ctl_card_info_t;
+
+/**
+ * \brief Try to determine the next card.
+ * \param rcard pointer to card number
+ * \result zero if success, otherwise a negative error code
+ *
+ * Tries to determine the next card from given card number.
+ * If card number is -1, then the first available card is
+ * returned. If the result card number is -1, no more cards
+ * are available.
+ */
+int
+snd_card_next (int *rcard)
+{
+ ALIB_INIT ();
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ if (*rcard == -1)
+ *rcard = 0;
+ else
+ *rcard = *rcard + 1;
+
+ if (*rcard >= sysinfo.numcards)
+ {
+ *rcard = -1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Convert card string to an integer value.
+ * \param string String containing card identifier
+ * \return zero if success, otherwise a negative error code
+ *
+ * The accepted format is an integer value in ASCII representation
+ * or the card identifier (the id parameter for sound-card drivers).
+ */
+int
+snd_card_get_index (const char *string)
+{
+ dbg_printf ("snd_card_get_index(%s)\n", string);
+ return -EINVAL;
+}
+
+/**
+ * \brief Get card name from a CTL card info
+ * \param obj CTL card info
+ * \return card name
+ */
+const char *
+snd_ctl_card_info_get_name (const snd_ctl_card_info_t * obj)
+{
+ return obj->info->longname;
+}
+
+/**
+ * \brief get size of #snd_ctl_card_info_t
+ * \return size in bytes
+ */
+size_t
+snd_ctl_card_info_sizeof ()
+{
+ return sizeof (snd_ctl_card_info_t);
+}
+
+/**
+ * \brief Opens a CTL
+ * \param ctlp Returned CTL handle
+ * \param name ASCII identifier of the CTL handle
+ * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_open (snd_ctl_t ** ctlp, const char *name, int mode)
+{
+ int num;
+ snd_ctl_t *ctl;
+
+ ALIB_INIT ();
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ *ctlp = NULL;
+
+ if (strcmp (name, "default") == 0)
+ num = 0;
+ else
+ {
+ if (name[0] != 'h' && name[1] != 'w' && name[2] != ':')
+ return -ENOENT;
+
+ if (sscanf (name + 3, "%d", &num) != 1)
+ return -ENOENT;
+ }
+
+ if (num < 0 || num >= sysinfo.numcards)
+ return -ENXIO;
+
+
+ if ((ctl = malloc (sizeof (*ctl))) == NULL)
+ return -ENOMEM;
+
+ memset (ctl, 0, sizeof (*ctl));
+ ctl->info.card = num;
+ if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ctl->info) == -1)
+ {
+ perror ("SNDCTL_CARDINFO");
+ fprintf (stderr, "Mixer fd was %d\n", mixer_fd);
+ return -errno;
+ }
+
+ *ctlp = ctl;
+ return 0;
+}
+
+/**
+ * \brief close CTL handle
+ * \param ctl CTL handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified CTL handle and frees all associated
+ * resources.
+ */
+int
+snd_ctl_close (snd_ctl_t * ctl)
+{
+ free (ctl);
+ return 0;
+}
+
+/**
+ * \brief Get card related information
+ * \param ctl CTL handle
+ * \param info Card info pointer
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_card_info (snd_ctl_t * ctl, snd_ctl_card_info_t * info)
+{
+
+ memset (info, 0, sizeof (*info));
+ info->info = &ctl->info;
+
+ return 0;
+}
+
+/**
+ * \brief Obtain the card name.
+ * \param card Card number
+ * \param name Result - card name corresponding to card number
+ * \result zero if success, otherwise a negative error code
+ */
+int
+snd_card_get_name (int card, char **name)
+{
+ char tmp[256];
+
+ sprintf (tmp, "OSS%d", card);
+
+ *name = strdup (tmp);
+ return 0;
+}
+
+int
+snd_card_get_longname (int card, char **name)
+{
+ oss_card_info ci;
+
+ ci.card = card;
+ if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ci) == -1)
+ return -errno;
+
+ *name = strdup (ci.longname);
+ return 0;
+}
+
+/**
+ * \brief Get next PCM device number
+ * \param ctl CTL handle
+ * \param device current device on entry and next device on return
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_pcm_next_device (snd_ctl_t * ctl, int *device)
+{
+ ALIB_INIT ();
+
+ dbg_printf ("snd_ctl_pcm_next_device(%d)\n", *device);
+
+ if (*device < 0)
+ *device = 0;
+ else
+ {
+ *device = *device + 1;
+ }
+
+ while (1)
+ {
+ if (*device < 0 || *device >= sysinfo.numaudios)
+ {
+ *device = -1;
+ return 0;
+ }
+
+ ctl->ainfo.dev = *device;
+ if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ctl->ainfo) < 0)
+ return -errno;
+
+ if (ctl->ainfo.card_number == ctl->info.card)
+ {
+ return 0;
+ }
+
+ *device = *device + 1;
+ }
+
+ *device = -1;
+ return 0;
+}
+
+/**
+ * \brief Get info about a PCM device
+ * \param ctl CTL handle
+ * \param info PCM device id/info pointer
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_pcm_info (snd_ctl_t * ctl, snd_pcm_info_t * info)
+{
+ dbg_printf ("snd_ctl_pcm_info()\n");
+ memset (info, 0, sizeof (*info));
+ info->ainfo = &ctl->ainfo;
+ return 0;
+}
+
+/**
+ * \brief Get card mixer name from a CTL card info
+ * \param obj CTL card info
+ * \return card mixer name
+ */
+const char *
+snd_ctl_card_info_get_mixername (const snd_ctl_card_info_t * obj)
+{
+ return obj->info->longname;
+}
+
+/**
+ * \brief Get info about a RawMidi device
+ * \param ctl CTL handle
+ * \param info RawMidi device id/info pointer
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_rawmidi_info (snd_ctl_t * ctl, snd_rawmidi_info_t * info)
+{
+ dbg_printf ("snd_ctl_rawmidi_info()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get next RawMidi device number
+ * \param ctl CTL handle
+ * \param device current device on entry and next device on return
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_ctl_rawmidi_next_device (snd_ctl_t * ctl, int *device)
+{
+ dbg_printf ("snd_ctl_rawmidi_next_device()\n");
+
+ if (*device < 0)
+ *device = 0;
+ else
+ *device = -1;
+
+ return 0;
+}
+
+/**
+ * \brief Get card identifier from a CTL card info
+ * \param obj CTL card info
+ * \return card identifier
+ */
+const char *
+snd_ctl_card_info_get_id (const snd_ctl_card_info_t * obj)
+{
+ dbg_printf ("snd_ctl_card_info_get_id()\n");
+
+ return "snd_ctl_card_info_get_id";
+}
diff --git a/lib/libsalsa/misc.c b/lib/libsalsa/misc.c
new file mode 100644
index 0000000..9af2408
--- /dev/null
+++ b/lib/libsalsa/misc.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+snd_config_t *snd_config = NULL;
+
+const char *
+snd_strerror (int errnum)
+{
+ if (errnum < 0)
+ errnum = -errnum;
+
+ return strerror (errnum);;
+}
+
+/**
+ * \brief Dumps the contents of a configuration node or tree.
+ * \param config Handle to the (root) configuration node.
+ * \param out Output handle.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_config_save (snd_config_t * config, snd_output_t * out)
+{
+ dbg_printf ("snd_config_save()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Searches for a node in a configuration tree.
+ * \param config Handle to the root of the configuration (sub)tree to search.
+ * \param key Search key: one or more node keys, separated with dots.
+ * \param result The function puts the handle to the node found at the address
+ * specified by \p result.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_config_search (snd_config_t * config, const char *key,
+ snd_config_t ** result)
+{
+ dbg_printf ("snd_config_search()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Updates #snd_config by rereading the global configuration files (if needed).
+ * \return A non-negative value if successful, otherwise a negative error code. * \retval 0 No action is needed.
+ * \retval 1 The configuration tree has been rebuilt.
+ *
+ * The global configuration files are specified in the environment variable
+ * \c ALSA_CONFIG_PATH. If this is not set, the default value is
+ * "/usr/share/alsa/alsa.conf".
+ *
+ * \warning If the configuration tree is reread, all string pointers and
+ * configuration node handles previously obtained from this tree become invalid.
+ */
+int
+snd_config_update (void)
+{
+ dbg_printf ("snd_config_update()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Frees the global configuration tree in #snd_config.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_config_update_free_global (void)
+{
+ dbg_printf ("snd_config_update_free_global()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Sets the error handler.
+ * \param handler The pointer to the new error handler function.
+ *
+ * This function sets a new error handler, or (if \c handler is \c NULL)
+ * the default one which prints the error messages to \c stderr.
+ */
+int
+snd_lib_error_set_handler (snd_lib_error_handler_t handler)
+{
+ dbg_printf ("snd_lib_error_set_handler()\n");
+ return 0;
+}
diff --git a/lib/libsalsa/mix.c b/lib/libsalsa/mix.c
new file mode 100644
index 0000000..5131518
--- /dev/null
+++ b/lib/libsalsa/mix.c
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * Parts of the code is derived from the alsa-lib package that is
+ * copyrighted by Jaroslav Kysela and the other ALSA team members.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+#define SND_VERS(a, b, c) (a<<16|b<<8|c)
+
+typedef struct _snd_mixer
+{
+ int mixdev;
+ int nrext;
+
+ oss_mixerinfo info;
+
+ snd_mixer_elem_t *elems;
+} snd_mixer_t;
+
+#define MAX_MIXERS 32
+static snd_mixer_t *mixers[MAX_MIXERS];
+static int nmixers = 0;
+
+typedef struct _snd_mixer_selem_id
+{
+ int number;
+ char name[32];
+} snd_mixer_selem_id_t;
+
+typedef struct _snd_mixer_class
+{
+ int dummy;
+} snd_mixer_class_t;
+
+typedef struct _snd_mixer_elem
+{
+ snd_mixer_t *mixer;
+ int ctrl;
+ oss_mixext ext;
+
+ snd_mixer_elem_t *next;
+
+ int low, high;
+} snd_mixer_elem_t;
+
+/**
+ * \brief Opens an empty mixer
+ * \param mixerp Returned mixer handle
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_open (snd_mixer_t ** mixerp, int mode)
+{
+ snd_mixer_t *mixer;
+ dbg_printf2 ("snd_mixer_open()\n");
+
+ ALIB_INIT ();
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ if ((mixer = malloc (sizeof (*mixer))) == NULL)
+ return -ENOMEM;
+
+ memset (mixer, 0, sizeof (*mixer));
+ *mixerp = mixer;
+
+ return 0;
+}
+
+/**
+ * \brief Attach an HCTL to an opened mixer
+ * \param mixer Mixer handle
+ * \param name HCTL name (see #snd_hctl_open)
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_attach (snd_mixer_t * mixer, const char *name)
+{
+ int dev = 0;
+
+ ALIB_INIT ();
+ dbg_printf2 ("snd_mixer_attach(%s)\n", name);
+
+
+ if (strcmp (name, "default") == 0)
+ dev = 0;
+ else if (name[0] == 'h' && name[1] == 'w' && name[2] == ':')
+ {
+ if (sscanf (name + 3, "%d", &dev) != 1)
+ return -ENOENT;
+
+ if (dev < 0 || dev >= sysinfo.nummixers)
+ return -ENXIO;
+ }
+ else
+ return -ENOENT;
+
+ mixer->mixdev = dev;
+
+ mixer->info.dev = dev;
+ if (ioctl (mixer_fd, SNDCTL_MIXERINFO, &mixer->info) == -1)
+ return -errno;
+
+ mixer->nrext = mixer->info.nrext;
+
+ if (nmixers < MAX_MIXERS)
+ mixers[nmixers++] = mixer;
+
+ return 0;
+}
+
+
+/**
+ * \brief Close a mixer and free all related resources
+ * \param mixer Mixer handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_close (snd_mixer_t * mixer)
+{
+ dbg_printf2 ("snd_mixer_close()\n");
+
+ free (mixer);
+ return 0;
+}
+
+/**
+ * \brief Register mixer simple element class
+ * \param mixer Mixer handle
+ * \param options Options container (not used now)
+ * \param classp Pointer to returned mixer simple element class handle (or NULL) * \return 0 on success otherwise a negative error code
+ */
+#if 1
+int
+snd_mixer_selem_register (snd_mixer_t * mixer,
+ struct snd_mixer_selem_regopt *arg,
+ snd_mixer_class_t ** classp)
+#else
+int
+snd_mixer_selem_register (snd_mixer_t * mixer, void *arg,
+ snd_mixer_class_t ** classp)
+#endif
+{
+ snd_mixer_class_t *class;
+
+ dbg_printf2 ("snd_mixer_selem_register()\n");
+
+ if (classp == NULL) /* Why this call was ever made ? */
+ return 0;
+
+ if ((class = malloc (sizeof (*class))) == NULL)
+ return -ENOMEM;
+
+ memset (class, 0, sizeof (*class));
+ *classp = class;
+
+ return 0;
+}
+
+/**
+ * \brief Return info about playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int
+snd_mixer_selem_has_playback_volume (snd_mixer_elem_t * elem)
+{
+ dbg_printf2 ("snd_mixer_selem_has_playback_volume(%x)\n", elem);
+ fflush (stdout);
+
+ if (elem->ext.type == MIXT_STEREOSLIDER)
+ return 1;
+ if (elem->ext.type == MIXT_MONOSLIDER)
+ return 1;
+ if (elem->ext.type == MIXT_SLIDER)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * \brief Return info about playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int
+snd_mixer_selem_has_playback_volume_joined (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_playback_volume_joined()\n");
+
+ return elem->ext.type != MIXT_STEREOSLIDER;
+}
+
+/**
+ * \brief Return info about capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int
+snd_mixer_selem_has_capture_volume (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_capture_volume()\n");
+
+ return 0;
+}
+
+
+/**
+ * \brief Return info about playback switch control existence of a mixer simple
+element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int
+snd_mixer_selem_has_playback_switch (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_playback_switch()\n");
+
+ if (elem->ext.type == MIXT_ONOFF || elem->ext.type == MIXT_MUTE)
+ return 1;
+ return 0;
+}
+
+/**
+ * \brief Set value of playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_playback_volume (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ long value)
+{
+ int vol, range;
+ oss_mixer_value rec;
+
+ dbg_printf2 ("snd_mixer_selem_set_playback_volume(%ld)\n", value);
+
+ if (value < elem->low)
+ value = elem->low;
+ if (value > elem->high)
+ value = elem->high;
+
+ range = elem->high - elem->low;
+ if (range == 0)
+ range = 100;
+ value -= elem->low;
+ vol = (value * elem->ext.maxvalue) / range;
+
+ rec.dev = elem->ext.dev;
+ rec.ctrl = elem->ext.ctrl;
+ rec.ctrl = elem->ext.ctrl;
+ rec.timestamp = elem->ext.timestamp;
+ rec.value = vol | (vol << 8);
+
+ if (ioctl (mixer_fd, SNDCTL_MIX_WRITE, &rec) == -1)
+ return -errno;
+
+ return 0;
+}
+
+/**
+ * \brief Set range for capture volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min minimum volume value
+ * \param max maximum volume value
+ */
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+int
+#else
+void
+#endif
+snd_mixer_selem_set_capture_volume_range (snd_mixer_elem_t * elem,
+ long min, long max)
+{
+ dbg_printf ("snd_mixer_selem_set_capture_volume_range()\n");
+
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+ return 0;
+#endif
+}
+
+/**
+ * \brief Set value of capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_capture_volume (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ long value)
+{
+ dbg_printf ("snd_mixer_selem_set_capture_volume()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set range for playback volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min minimum volume value
+ * \param max maximum volume value
+ */
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+int
+#else
+void
+#endif
+snd_mixer_selem_set_playback_volume_range (snd_mixer_elem_t * elem,
+ long min, long max)
+{
+ dbg_printf2 ("snd_mixer_selem_set_playback_volume_range(%s, %d, %d)\n",
+ elem->ext.extname, min, max);
+
+ elem->low = min;
+ elem->high = max;
+
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+ return 0;
+#endif
+}
+
+/**
+ * \brief Return value of playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_playback_volume (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ long *value)
+{
+ int vol, range, left, right;
+ oss_mixer_value rec;
+
+ dbg_printf2 ("snd_mixer_selem_get_playback_volume()\n");
+
+ rec.dev = elem->ext.dev;
+ rec.ctrl = elem->ext.ctrl;
+ rec.timestamp = elem->ext.timestamp;
+
+ if (ioctl (mixer_fd, SNDCTL_MIX_READ, &rec) == -1)
+ return -errno;
+
+ left = rec.value & 0xff;
+ right = (rec.value >> 8) & 0xff;
+
+ if (left > right)
+ vol = left;
+ else
+ vol = right;
+ range = elem->high - elem->low;
+
+ vol = (vol * range) / elem->ext.maxvalue;
+ vol += elem->low;
+ *value = vol;
+
+ return 0;
+}
+
+/**
+ * \brief Get range for playback volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum
+ * \param max Pointer to returned maximum
+ */
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+int
+#else
+void
+#endif
+snd_mixer_selem_get_playback_volume_range (snd_mixer_elem_t * elem,
+ long *min, long *max)
+{
+ dbg_printf2 ("snd_mixer_selem_get_playback_volume_range()\n");
+#if 1
+ *min = elem->low;
+ *max = elem->high;
+#endif
+
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+ return 0;
+#endif
+}
+
+/**
+ * \brief get first element for a mixer
+ * \param mixer Mixer handle
+ * \return pointer to first element
+ */
+snd_mixer_elem_t *
+snd_mixer_first_elem (snd_mixer_t * mixer)
+{
+ dbg_printf2 ("snd_mixer_first_elem()\n");
+
+ return mixer->elems;
+}
+
+/**
+ * \brief get next mixer element
+ * \param elem mixer element
+ * \return pointer to next element
+ */
+snd_mixer_elem_t *
+snd_mixer_elem_next (snd_mixer_elem_t * elem)
+{
+ dbg_printf2 ("snd_mixer_elem_next(%x/%d)\n", elem, elem);
+
+ if (elem == NULL || (long) elem < 4096)
+ {
+ dbg_printf2 ("Returning NULL\n");
+ return NULL;
+ }
+
+ if (elem->next == NULL)
+ dbg_printf ("No more elemsnts\n");
+ else
+ dbg_printf2 ("Returning %d/%s\n", elem->next->ctrl,
+ elem->next->ext.extname);
+ return elem->next;
+}
+
+/**
+ * \brief Find a mixer simple element
+ * \param mixer Mixer handle
+ * \param id Mixer simple element identifier
+ * \return mixer simple element handle or NULL if not found
+ *
+ * Wuld somebody kindly explain me what in hell is the logic
+ * behind this idiotic "simple" mixer stuff.
+ */
+snd_mixer_elem_t *
+snd_mixer_find_selem (snd_mixer_t * mixer, const snd_mixer_selem_id_t * id)
+{
+ int i;
+
+ dbg_printf2 ("snd_mixer_find_selem(%d/%s)\n", id->number, id->name);
+
+ if (*id->name == 0 && id->number == 0)
+ return NULL;
+
+ for (i = 0; i < mixer->nrext; i++)
+ {
+ oss_mixext *ext = &mixer->elems[i].ext;
+
+ if (ext->type == MIXT_GROUP ||
+ ext->type == MIXT_DEVROOT || ext->type == MIXT_MARKER)
+ continue;
+
+ if (strcasecmp (ext->extname, id->name) == 0)
+ {
+ return &mixer->elems[i];
+ }
+
+ if (ext->ctrl == id->number)
+ {
+ return &mixer->elems[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * \brief Handle pending mixer events invoking callbacks
+ * \param mixer Mixer handle
+ * \return 0 otherwise a negative error code on failure
+ */
+int
+snd_mixer_handle_events (snd_mixer_t * mixer)
+{
+ dbg_printf2 ("snd_mixer_handle_events()\n");
+ // NOP
+}
+
+/**
+ * \brief Load a mixer elements
+ * \param mixer Mixer handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_load (snd_mixer_t * mixer)
+{
+ snd_mixer_elem_t *elems;
+ int i, n = 0;
+
+ dbg_printf2 ("snd_mixer_load()\n");
+
+ if (mixer->elems != NULL)
+ free (mixer->elems);
+
+ if ((elems = malloc (sizeof (*elems) * mixer->nrext)) == NULL)
+ return -ENOMEM;
+
+ memset (elems, 0, sizeof (*elems) * mixer->nrext);
+
+ for (i = 0; i < mixer->nrext; i++)
+ {
+ oss_mixext *ext = &elems[n].ext;
+ snd_mixer_elem_t *elem;
+
+ elem = &elems[n];
+
+ ext->dev = mixer->mixdev;
+ ext->ctrl = i;
+
+ if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, ext) < 0)
+ {
+ int e = errno;
+ perror ("SNDCTL_MIX_EXTINFO");
+ return -e;
+ }
+
+ if (ext->type == MIXT_DEVROOT)
+ continue;
+ if (ext->type == MIXT_GROUP)
+ continue;
+ if (ext->type == MIXT_MARKER)
+ continue;
+
+ elem->low = 0;
+ elem->high = ext->maxvalue;
+ elem->ctrl = elem->ext.ctrl;
+
+ if (n > 0)
+ elems[n - 1].next = &elems[n];
+
+ n++;
+ }
+
+ mixer->nrext = n;
+ mixer->elems = elems;
+ return 0;
+}
+
+/**
+ * \brief Get name part of mixer simple element identifier
+ * \param elem Mixer simple element handle
+ * \return name part of simple element identifier
+ */
+const char *
+snd_mixer_selem_get_name (snd_mixer_elem_t * elem)
+{
+ dbg_printf2 ("snd_mixer_selem_get_name()\n");
+
+ return elem->ext.extname;
+}
+
+/**
+ * \brief Set index part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \param val index part
+ */
+void
+snd_mixer_selem_id_set_index (snd_mixer_selem_id_t * obj, unsigned int val)
+{
+ dbg_printf2 ("snd_mixer_selem_id_set_index(%u)\n", val);
+
+ obj->number = val;
+}
+
+/**
+ * \brief Set name part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \param val name part
+ */
+void
+snd_mixer_selem_id_set_name (snd_mixer_selem_id_t * obj, const char *val)
+{
+ dbg_printf2 ("snd_mixer_selem_id_set_name(%s)\n", val);
+
+ strcpy (obj->name, val);
+}
+
+/**
+ * \brief get size of #snd_mixer_selem_id_t
+ * \return size in bytes
+ */
+size_t
+snd_mixer_selem_id_sizeof ()
+{
+ return sizeof (snd_mixer_selem_id_t);
+}
+
+
+/**
+ * \brief Get info about the active state of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not active, 1 if active
+ */
+int
+snd_mixer_selem_is_active (snd_mixer_elem_t * elem)
+{
+ dbg_printf2 ("snd_mixer_selem_is_active()\n");
+ return 1;
+}
+
+/**
+ * \brief Return value of capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_capture_switch (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ int *value)
+{
+ dbg_printf ("snd_mixer_selem_get_capture_switch()\n");
+
+ *value = 0;
+ return 0;
+}
+
+/**
+ * \brief Return value of playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_playback_switch (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ int *value)
+{
+ oss_mixer_value rec;
+
+ dbg_printf ("snd_mixer_selem_get_playback_switch()\n");
+
+ *value = 0;
+
+ rec.dev = elem->ext.dev;
+ rec.ctrl = elem->ext.ctrl;
+ rec.ctrl = elem->ext.ctrl;
+ rec.timestamp = elem->ext.timestamp;
+
+ if (ioctl (mixer_fd, SNDCTL_MIX_READ, &rec) == -1)
+ return -errno;
+
+ *value = !!rec.value;
+ return 0;
+}
+
+/**
+ * \brief Get info about channels of capture stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel Mixer simple element channel identifier
+ * \return 0 if channel is not present, 1 if present
+ */
+int
+snd_mixer_selem_has_capture_channel (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel)
+{
+ dbg_printf ("snd_mixer_selem_has_capture_channel()\n");
+
+ return (channel < 2);
+}
+
+/**
+ * \brief Return info about capture switch control existence of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int
+snd_mixer_selem_has_capture_switch (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_capture_switch()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Return info about capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int
+snd_mixer_selem_has_capture_switch_joined (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_capture_switch_joined()\n");
+
+ return 1;
+}
+
+/**
+ * \brief Get info about channels of capture stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not mono, 1 if mono
+ */
+int
+snd_mixer_selem_is_capture_mono (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_is_capture_mono()\n");
+ return 0;
+}
+
+/**
+ * \brief Get info about channels of playback stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not mono, 1 if mono
+ */
+int
+snd_mixer_selem_is_playback_mono (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_is_playback_mono()\n");
+ return 0;
+}
+
+/**
+ * \brief Set value of capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_capture_switch (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ int value)
+{
+ dbg_printf ("snd_mixer_selem_set_capture_switch()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set value of capture switch control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_capture_switch_all (snd_mixer_elem_t * elem, int value)
+{
+ dbg_printf ("snd_mixer_selem_set_capture_switch_all()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set value of playback switch control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_playback_switch_all (snd_mixer_elem_t * elem, int value)
+{
+ oss_mixer_value rec;
+
+ dbg_printf ("snd_mixer_selem_set_playback_switch_all()\n");
+
+ rec.dev = elem->ext.dev;
+ rec.ctrl = elem->ext.ctrl;
+ rec.ctrl = elem->ext.ctrl;
+ rec.timestamp = elem->ext.timestamp;
+ rec.value = !!value;
+
+ if (ioctl (mixer_fd, SNDCTL_MIX_WRITE, &rec) == -1)
+ return -errno;
+
+ return 0;
+}
+
+/**
+ * \brief Return value of capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_capture_volume (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ long *value)
+{
+ dbg_printf ("snd_mixer_selem_get_capture_volume()\n");
+
+ *value = 0;
+ return 0;
+}
+
+/**
+ * \brief Get mixer simple element identifier
+ * \param elem Mixer simple element handle
+ * \param id returned mixer simple element identifier
+ */
+void
+snd_mixer_selem_get_id (snd_mixer_elem_t * elem, snd_mixer_selem_id_t * id)
+{
+ dbg_printf ("snd_mixer_selem_get_id()\n");
+ // What in hell is this?
+
+ id->number = elem->ctrl;
+ strcpy (id->name, elem->ext.extname);
+ dbg_printf ("ID=%d / %s\n", id->number, id->name);
+}
+
+/**
+ * \brief Get name part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \return name part
+ */
+const char *
+snd_mixer_selem_id_get_name (const snd_mixer_selem_id_t * obj)
+{
+ dbg_printf ("snd_mixer_selem_id_get_name()=%s\n", obj->name);
+//return "Objname";
+ return obj->name;
+}
+
+/**
+ * \brief Get index part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \return index part
+ */
+unsigned int
+snd_mixer_selem_id_get_index (const snd_mixer_selem_id_t * obj)
+{
+ dbg_printf ("snd_mixer_selem_id_get_index()\n");
+
+ return 0;
+}
+
+
+/**
+ * \brief Get elements count for a mixer
+ * \param mixer mixer handle
+ * \return elements count
+ */
+unsigned int
+snd_mixer_get_count (const snd_mixer_t * obj)
+{
+ dbg_printf ("snd_mixer_get_count()\n");
+
+ return obj->nrext;
+}
+
+/**
+ * \brief get poll descriptors
+ * \param mixer Mixer handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \return count of filled descriptors
+ */
+int
+snd_mixer_poll_descriptors (snd_mixer_t * mixer, struct pollfd *pfds,
+ unsigned int space)
+{
+ dbg_printf ("snd_mixer_poll_descriptors()\n");
+
+ return 0;
+}
+
+/**
+ * \brief get count of poll descriptors for mixer handle
+ * \param mixer Mixer handle
+ * \return count of poll descriptors
+ */
+int
+snd_mixer_poll_descriptors_count (snd_mixer_t * mixer)
+{
+ dbg_printf ("snd_mixer_poll_descriptors_count()\n");
+
+ return 0;
+}
+
+/**
+ * \brief get returned events from poll descriptors
+ * \param mixer Mixer 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_mixer_poll_descriptors_revents (snd_mixer_t * mixer, struct pollfd *pfds,
+ unsigned int nfds,
+ unsigned short *revents)
+{
+ dbg_printf ("snd_mixer_poll_descriptors_revents()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set callback function for a mixer
+ * \param mixer mixer handle
+ * \param callback callback function
+ */
+void
+snd_mixer_set_callback (snd_mixer_t * obj, snd_mixer_callback_t val)
+{
+ dbg_printf0 ("snd_mixer_set_callback()\n");
+
+}
+
+/**
+ * \brief Get range for capture volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum
+ * \param max Pointer to returned maximum
+ */
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+int
+#else
+void
+#endif
+snd_mixer_selem_get_capture_volume_range (snd_mixer_elem_t * elem,
+ long *min, long *max)
+{
+ dbg_printf ("snd_mixer_selem_get_capture_volume_range()\n");
+
+ *min = 0;
+ *max = 100;
+
+#if SND_LIB_VERSION > SND_VERS(1,0,9)
+ return 0;
+#endif
+}
+
+/**
+ * \brief Return true if mixer simple element is an enumerated control
+ * \param elem Mixer simple element handle
+ * \return 0 normal volume/switch control, 1 enumerated control
+ */
+int
+snd_mixer_selem_is_enumerated (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_is_enumerated()\n");
+
+ return 0;
+}
+
+/**
+ * \brief get the current selected enumerated item for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param itemp the pointer to store the index of the enumerated item
+ * \return 0 if successful, otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_enum_item (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ unsigned int *itemp)
+{
+ dbg_printf ("snd_mixer_selem_get_enum_item()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Return the number of enumerated items of the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \return the number of enumerated items, otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_enum_items (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_get_enum_items()\n");
+ return 0;
+}
+
+/**
+ * \brief get the enumerated item string for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param item the index of the enumerated item to query
+ * \param maxlen the maximal length to be stored
+ * \param buf the buffer to store the name string
+ * \return 0 if successful, otherwise a negative error code
+ */
+int
+snd_mixer_selem_get_enum_item_name (snd_mixer_elem_t * elem,
+ unsigned int item,
+ size_t maxlen, char *buf)
+{
+ dbg_printf ("snd_mixer_selem_get_enum_item_name()\n");
+ strncpy (buf, "Enum", maxlen);
+ buf[maxlen - 1] = 0;
+
+ return 0;
+}
+
+/**
+ * \brief Return info about capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int
+snd_mixer_selem_has_capture_volume_joined (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_capture_volume_joined()\n");
+ return elem->ext.type != MIXT_STEREOSLIDER;
+}
+
+/**
+ * \brief Get info about channels of playback stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel Mixer simple element channel identifier
+ * \return 0 if channel is not present, 1 if present
+ */
+int
+snd_mixer_selem_has_playback_channel (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel)
+{
+ dbg_printf ("snd_mixer_selem_has_playback_channel(%s, %d)\n",
+ elem->ext.extname, channel);
+
+ if (elem->ext.type == MIXT_SLIDER && channel == 0)
+ return 1;
+ if (elem->ext.type == MIXT_MONOSLIDER && channel == 0)
+ return 1;
+ if (elem->ext.type == MIXT_STEREOSLIDER && channel < 2)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * \brief Return info about playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int
+snd_mixer_selem_has_playback_switch_joined (snd_mixer_elem_t * elem)
+{
+ dbg_printf ("snd_mixer_selem_has_playback_switch_joined()\n");
+
+ return 0;
+}
+
+/**
+ * \brief copy one #snd_mixer_selem_id_t to another
+ * \param dst pointer to destination
+ * \param src pointer to source
+ */
+void
+snd_mixer_selem_id_copy (snd_mixer_selem_id_t * dst,
+ const snd_mixer_selem_id_t * src)
+{
+ dbg_printf ("snd_mixer_selem_id_copy()\n");
+ memcpy (dst, src, sizeof (*dst));
+}
+
+
+/**
+ * \brief set the current selected enumerated item for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param item the enumerated item index
+ * \return 0 if successful, otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_enum_item (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ unsigned int item)
+{
+ dbg_printf ("snd_mixer_selem_set_enum_item()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set value of playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_mixer_selem_set_playback_switch (snd_mixer_elem_t * elem,
+ snd_mixer_selem_channel_id_t channel,
+ int value)
+{
+ dbg_printf ("snd_mixer_selem_set_playback_switch()\n");
+
+ return 0;
+}
+
+/**
+ * * \brief Return true if mixer simple element has only one volume control for both playback and capture
+ * * \param elem Mixer simple element handle
+ * * \return 0 separated control, 1 common control
+ * */
+int
+snd_mixer_selem_has_common_volume (snd_mixer_elem_t * elem)
+{
+ return 0; // TODO
+}
+
+/**
+ * * \brief Return true if mixer simple element has only one switch control for both playback and capture
+ * * \param elem Mixer simple element handle
+ * * \return 0 separated control, 1 common control
+ * */
+int
+snd_mixer_selem_has_common_switch (snd_mixer_elem_t * elem)
+{
+ return 0; // TODO
+}
diff --git a/lib/libsalsa/output.c b/lib/libsalsa/output.c
new file mode 100644
index 0000000..0369a81
--- /dev/null
+++ b/lib/libsalsa/output.c
@@ -0,0 +1,411 @@
+/**
+ * \file output.c
+ * \brief Generic stdio-like output interface
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \date 2000
+ *
+ * Generic stdio-like output interface
+ */
+/*
+ * Output object
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "local.h"
+
+#ifndef DOC_HIDDEN
+typedef struct _snd_output_ops
+{
+ int (*close) (snd_output_t * output);
+ int (*print) (snd_output_t * output, const char *format, va_list args);
+ int (*puts) (snd_output_t * output, const char *str);
+ int (*putch) (snd_output_t * output, int c);
+ int (*flush) (snd_output_t * output);
+} snd_output_ops_t;
+
+struct _snd_output
+{
+ snd_output_type_t type;
+ snd_output_ops_t *ops;
+ void *private_data;
+};
+#endif
+
+/**
+ * \brief Closes an output handle.
+ * \param output The output handle to be closed.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_close (snd_output_t * output)
+{
+ int err = output->ops->close (output);
+ free (output);
+ return err;
+}
+
+/**
+ * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
+ * \param output The output handle.
+ * \param format Format string in \c fprintf format.
+ * \param ... Other \c fprintf arguments.
+ * \return The number of characters written, or a negative error code.
+ */
+int
+snd_output_printf (snd_output_t * output, const char *format, ...)
+{
+ int result;
+ va_list args;
+ va_start (args, format);
+ result = output->ops->print (output, format, args);
+ va_end (args);
+ return result;
+}
+
+/**
+ * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
+ * \param output The output handle.
+ * \param format Format string in \c fprintf format.
+ * \param args Other \c fprintf arguments.
+ * \return The number of characters written, or a negative error code.
+ */
+int
+snd_output_vprintf (snd_output_t * output, const char *format, va_list args)
+{
+ return output->ops->print (output, format, args);
+}
+
+/**
+ * \brief Writes a string to an output handle (like \c fputs(3)).
+ * \param output The output handle.
+ * \param str Pointer to the string.
+ * \return Zero if successful, otherwise a negative error code or \c EOF.
+ */
+int
+snd_output_puts (snd_output_t * output, const char *str)
+{
+ return output->ops->puts (output, str);
+}
+
+/**
+ * \brief Writes a character to an output handle (like \c putc(3)).
+ * \param output The output handle.
+ * \param c The character.
+ * \return Zero if successful, otherwise a negative error code or \c EOF.
+ */
+int
+snd_output_putc (snd_output_t * output, int c)
+{
+ return output->ops->putch (output, c);
+}
+
+/**
+ * \brief Flushes an output handle (like fflush(3)).
+ * \param output The output handle.
+ * \return Zero if successful, otherwise \c EOF.
+ *
+ * If the underlying destination is a stdio stream, this function calls
+ * \c fflush. If the underlying destination is a memory buffer, the write
+ * position is reset to the beginning of the buffer. \c =:-o
+ */
+int
+snd_output_flush (snd_output_t * output)
+{
+ return output->ops->flush (output);
+}
+
+#ifndef DOC_HIDDEN
+typedef struct _snd_output_stdio
+{
+ int close;
+ FILE *fp;
+} snd_output_stdio_t;
+
+static int
+snd_output_stdio_close (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ if (stdio->close)
+ fclose (stdio->fp);
+ free (stdio);
+ return 0;
+}
+
+static int
+snd_output_stdio_print (snd_output_t * output, const char *format,
+ va_list args)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return vfprintf (stdio->fp, format, args);
+}
+
+static int
+snd_output_stdio_puts (snd_output_t * output, const char *str)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return fputs (str, stdio->fp);
+}
+
+static int
+snd_output_stdio_putc (snd_output_t * output, int c)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return putc (c, stdio->fp);
+}
+
+static int
+snd_output_stdio_flush (snd_output_t * output)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return fflush (stdio->fp);
+}
+
+static snd_output_ops_t snd_output_stdio_ops = {
+ .close = snd_output_stdio_close,
+ .print = snd_output_stdio_print,
+ .puts = snd_output_stdio_puts,
+ .putch = snd_output_stdio_putc,
+ .flush = snd_output_stdio_flush,
+};
+
+#endif
+
+/**
+ * \brief Creates a new output object using an existing stdio \c FILE pointer.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \param fp The \c FILE pointer to write to. Characters are written
+ * to the file starting at the current file position.
+ * \param close Close flag. Set this to 1 if #snd_output_close should close
+ * \p fp by calling \c fclose.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_stdio_attach (snd_output_t ** outputp, FILE * fp, int _close)
+{
+ snd_output_t *output;
+ snd_output_stdio_t *stdio;
+ assert (outputp && fp);
+ stdio = calloc (1, sizeof (*stdio));
+ if (!stdio)
+ return -ENOMEM;
+ output = calloc (1, sizeof (*output));
+ if (!output)
+ {
+ free (stdio);
+ return -ENOMEM;
+ }
+ stdio->fp = fp;
+ stdio->close = _close;
+ output->type = SND_OUTPUT_STDIO;
+ output->ops = &snd_output_stdio_ops;
+ output->private_data = stdio;
+ *outputp = output;
+ return 0;
+}
+
+/**
+ * \brief Creates a new output object writing to a file.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \param file The name of the file to open.
+ * \param mode The open mode, like \c fopen(3).
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_stdio_open (snd_output_t ** outputp, const char *file,
+ const char *mode)
+{
+ int err;
+ FILE *fp = fopen (file, mode);
+ if (!fp)
+ {
+ //SYSERR("fopen");
+ return -errno;
+ }
+ err = snd_output_stdio_attach (outputp, fp, 1);
+ if (err < 0)
+ fclose (fp);
+ return err;
+}
+
+#ifndef DOC_HIDDEN
+
+typedef struct _snd_output_buffer
+{
+ unsigned char *buf;
+ size_t alloc;
+ size_t size;
+} snd_output_buffer_t;
+
+static int
+snd_output_buffer_close (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ free (buffer->buf);
+ free (buffer);
+ return 0;
+}
+
+static int
+snd_output_buffer_need (snd_output_t * output, size_t size)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t _free = buffer->alloc - buffer->size;
+ size_t alloc;
+ unsigned char *buf;
+
+ if (_free >= size)
+ return _free;
+ if (buffer->alloc == 0)
+ alloc = 256;
+ else
+ alloc = buffer->alloc;
+ while (alloc < size)
+ alloc *= 2;
+ buf = realloc (buffer->buf, alloc);
+ if (!buf)
+ return -ENOMEM;
+ buffer->buf = buf;
+ buffer->alloc = alloc;
+ return buffer->alloc - buffer->size;
+}
+
+static int
+snd_output_buffer_print (snd_output_t * output, const char *format,
+ va_list args)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t size = 256;
+ int result;
+ result = snd_output_buffer_need (output, size);
+ if (result < 0)
+ return result;
+ result = vsnprintf (buffer->buf + buffer->size, size, format, args);
+ assert (result >= 0);
+ if ((size_t) result <= size)
+ {
+ buffer->size += result;
+ return result;
+ }
+ size = result;
+ result = snd_output_buffer_need (output, size);
+ if (result < 0)
+ return result;
+ result = vsnprintf (buffer->buf + buffer->size, result, format, args);
+ assert (result == (int) size);
+ buffer->size += result;
+ return result;
+}
+
+static int
+snd_output_buffer_puts (snd_output_t * output, const char *str)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t size = strlen (str);
+ int err;
+ err = snd_output_buffer_need (output, size);
+ if (err < 0)
+ return err;
+ memcpy (buffer->buf + buffer->size, str, size);
+ buffer->size += size;
+ return size;
+}
+
+static int
+snd_output_buffer_putc (snd_output_t * output, int c)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ int err;
+ err = snd_output_buffer_need (output, 1);
+ if (err < 0)
+ return err;
+ buffer->buf[buffer->size++] = c;
+ return 0;
+}
+
+static int
+snd_output_buffer_flush (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ buffer->size = 0;
+ return 0;
+}
+
+static snd_output_ops_t snd_output_buffer_ops = {
+ .close = snd_output_buffer_close,
+ .print = snd_output_buffer_print,
+ .puts = snd_output_buffer_puts,
+ .putch = snd_output_buffer_putc,
+ .flush = snd_output_buffer_flush,
+};
+#endif
+
+/**
+ * \brief Returns the address of the buffer of a #SND_OUTPUT_TYPE_BUFFER output handle.
+ * \param output The output handle.
+ * \param buf The functions puts the current address of the buffer at the
+ * address specified by \p buf.
+ * \return The current size of valid data in the buffer.
+ *
+ * The address of the buffer may become invalid when output functions or
+ * #snd_output_close are called.
+ */
+size_t
+snd_output_buffer_string (snd_output_t * output, char **buf)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ *buf = buffer->buf;
+ return buffer->size;
+}
+
+/**
+ * \brief Creates a new output object with an auto-extending memory buffer.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_buffer_open (snd_output_t ** outputp)
+{
+ snd_output_t *output;
+ snd_output_buffer_t *buffer;
+ assert (outputp);
+ buffer = calloc (1, sizeof (*buffer));
+ if (!buffer)
+ return -ENOMEM;
+ output = calloc (1, sizeof (*output));
+ if (!output)
+ {
+ free (buffer);
+ return -ENOMEM;
+ }
+ buffer->buf = NULL;
+ buffer->alloc = 0;
+ buffer->size = 0;
+ output->type = SND_OUTPUT_BUFFER;
+ output->ops = &snd_output_buffer_ops;
+ output->private_data = buffer;
+ *outputp = output;
+ return 0;
+}
diff --git a/lib/libsalsa/pcm.c b/lib/libsalsa/pcm.c
new file mode 100644
index 0000000..a305e54
--- /dev/null
+++ b/lib/libsalsa/pcm.c
@@ -0,0 +1,3114 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * Parts of the code is derived from the alsa-lib package that is
+ * copyrighted by Jaroslav Kysela and the other ALSA team members.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define USE_VERSIONED_SYMBOLS
+#define DO_VERSIONING
+#define HAVE_ELF
+#define PERIOD_SIZE 128
+
+#include "local.h"
+
+#define PCMTYPE(v) [SND_PCM_TYPE_##v] = #v
+#define STATE(v) [SND_PCM_STATE_##v] = #v
+#define STREAM(v) [SND_PCM_STREAM_##v] = #v
+#define READY(v) [SND_PCM_READY_##v] = #v
+#define XRUN(v) [SND_PCM_XRUN_##v] = #v
+#define SILENCE(v) [SND_PCM_SILENCE_##v] = #v
+#define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v
+#define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
+#define START(v) [SND_PCM_START_##v] = #v
+#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
+#define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v
+#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
+#define SUBFORMAT(v) [SND_PCM_SUBFORMAT_##v] = #v
+
+#define FORMATD(v, d) [SND_PCM_FORMAT_##v] = d
+#define SUBFORMATD(v, d) [SND_PCM_SUBFORMAT_##v] = d
+
+static const char *snd_pcm_stream_names[] = {
+ STREAM (PLAYBACK),
+ STREAM (CAPTURE),
+};
+
+static const char *snd_pcm_state_names[] = {
+ STATE (OPEN),
+ STATE (SETUP),
+ STATE (PREPARED),
+ STATE (RUNNING),
+ STATE (XRUN),
+ STATE (DRAINING),
+ STATE (PAUSED),
+ STATE (SUSPENDED),
+ STATE (DISCONNECTED),
+};
+
+static const char *snd_pcm_access_names[] = {
+ ACCESS (MMAP_INTERLEAVED),
+ ACCESS (MMAP_NONINTERLEAVED),
+ ACCESS (MMAP_COMPLEX),
+ ACCESS (RW_INTERLEAVED),
+ ACCESS (RW_NONINTERLEAVED),
+};
+
+static const char *snd_pcm_format_descriptions[] = {
+ FORMATD (S8, "Signed 8 bit"),
+ FORMATD (U8, "Unsigned 8 bit"),
+ FORMATD (S16_LE, "Signed 16 bit Little Endian"),
+ FORMATD (S16_BE, "Signed 16 bit Big Endian"),
+ FORMATD (U16_LE, "Unsigned 16 bit Little Endian"),
+ FORMATD (U16_BE, "Unsigned 16 bit Big Endian"),
+ FORMATD (S24_LE, "Signed 24 bit Little Endian"),
+ FORMATD (S24_BE, "Signed 24 bit Big Endian"),
+ FORMATD (U24_LE, "Unsigned 24 bit Little Endian"),
+ FORMATD (U24_BE, "Unsigned 24 bit Big Endian"),
+ FORMATD (S32_LE, "Signed 32 bit Little Endian"),
+ FORMATD (S32_BE, "Signed 32 bit Big Endian"),
+ FORMATD (U32_LE, "Unsigned 32 bit Little Endian"),
+ FORMATD (U32_BE, "Unsigned 32 bit Big Endian"),
+ FORMATD (FLOAT_LE, "Float 32 bit Little Endian"),
+ FORMATD (FLOAT_BE, "Float 32 bit Big Endian"),
+ FORMATD (FLOAT64_LE, "Float 64 bit Little Endian"),
+ FORMATD (FLOAT64_BE, "Float 64 bit Big Endian"),
+ FORMATD (IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
+ FORMATD (IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
+ FORMATD (MU_LAW, "Mu-Law"),
+ FORMATD (A_LAW, "A-Law"),
+ FORMATD (IMA_ADPCM, "Ima-ADPCM"),
+ FORMATD (MPEG, "MPEG"),
+ FORMATD (GSM, "GSM"),
+ FORMATD (SPECIAL, "Special"),
+ FORMATD (S24_3LE, "Signed 24 bit Little Endian in 3bytes"),
+ FORMATD (S24_3BE, "Signed 24 bit Big Endian in 3bytes"),
+ FORMATD (U24_3LE, "Unsigned 24 bit Little Endian in 3bytes"),
+ FORMATD (U24_3BE, "Unsigned 24 bit Big Endian in 3bytes"),
+ FORMATD (S20_3LE, "Signed 20 bit Little Endian in 3bytes"),
+ FORMATD (S20_3BE, "Signed 20 bit Big Endian in 3bytes"),
+ FORMATD (U20_3LE, "Unsigned 20 bit Little Endian in 3bytes"),
+ FORMATD (U20_3BE, "Unsigned 20 bit Big Endian in 3bytes"),
+ FORMATD (S18_3LE, "Signed 18 bit Little Endian in 3bytes"),
+ FORMATD (S18_3BE, "Signed 18 bit Big Endian in 3bytes"),
+ FORMATD (U18_3LE, "Unsigned 18 bit Little Endian in 3bytes"),
+ FORMATD (U18_3BE, "Unsigned 18 bit Big Endian in 3bytes"),
+};
+
+struct _snd_pcm
+{
+ int fd;
+ int state;
+ oss_audioinfo info;
+ int stream, oss_mode;
+ int frame_size, sample_size, period_size;
+ int channels;
+ int periods;
+ snd_pcm_channel_area_t *area;
+};
+
+struct _snd_pcm_format_mask
+{
+ unsigned int mask;
+};
+
+struct _snd_pcm_status
+{
+ int dummy;
+};
+
+struct _snd_pcm_sw_params
+{
+ int dummy;
+};
+
+struct _snd_pcm_hw_params
+{
+ int speed;
+ int fmt, channels;
+ int oss_fmt;
+
+ oss_audioinfo *info;
+ snd_pcm_t *pcm;
+
+ int frame_size;
+ int sample_bits;
+ int access;
+};
+
+static int
+parse_device (const char *nme, char *dspname)
+{
+ char *s;
+ oss_audioinfo ai;
+ int card = 0, port = 0, i;
+ char tmp[256], *name = tmp;
+
+ strcpy (name, nme);
+
+ if (name[0] != 'h')
+ return 0;
+ if (name[1] != 'w')
+ return 0;
+ if (name[2] != ':')
+ return 0;
+
+ name += 3;
+ s = name;
+
+ while (*s && *s != ',')
+ s++;
+
+ if (*s == ',')
+ {
+ int n = 0;
+
+ *s++ = 0;
+ if (sscanf (name, "%d", &card) != 1)
+ return 0;
+ if (sscanf (s, "%d", &port) != 1)
+ return 0;
+
+ n = -1;
+ for (i = 0; i < sysinfo.numaudios; i++)
+ {
+ ai.dev = i;
+ if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ai) == -1)
+ continue;
+
+ if (ai.card_number != card)
+ continue;
+
+ n++;
+ if (port < n)
+ continue;
+
+ sprintf (dspname, "/dev/dsp%d", i);
+ return 1;
+ }
+ return 0;
+ }
+ if (sscanf (name, "%d", &card) != 1)
+ return 0;
+
+ for (i = 0; i < sysinfo.numaudios; i++)
+ {
+ ai.dev = i;
+ if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ai) == -1)
+ continue;
+
+ if (ai.card_number == card)
+ {
+ port = i;
+ sprintf (dspname, "/dev/dsp%d", port);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Opens a PCM
+ * \param pcmp Returned PCM handle
+ * \param name ASCII identifier of the PCM handle
+ * \param stream Wanted stream
+ * \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_open (snd_pcm_t ** pcmp, const char *name,
+ snd_pcm_stream_t stream, int mode)
+{
+ snd_pcm_t *pcm;
+ int oss_mode = O_WRONLY;
+ char dspname[32];
+ const char *devdsp;
+
+ if ((devdsp = getenv("OSS_AUDIODEV")) == NULL)
+ devdsp = "/dev/dsp";
+
+ ALIB_INIT ();
+
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ *pcmp = NULL;
+
+ dbg_printf ("snd_pcm_open(%s, %x)\n", name, stream);
+
+ if (mode != 0)
+ dbg_printf2 ("snd_pcm_open: mode=0x%x - not emulated.\n", mode);
+
+ if (strcmp (name, "default") == 0)
+ name = devdsp;
+ else
+ {
+ if (!parse_device (name, dspname))
+ {
+#if 0
+ fprintf (stderr, "OSS asound - Bad PCM device '%s'\n", name);
+ return -ENOENT;
+#else
+ strcpy (dspname, devdsp);
+#endif
+ }
+
+ name = dspname;
+ }
+
+ if ((pcm = malloc (sizeof (*pcm))) == NULL)
+ return -ENOMEM;
+
+ switch (stream)
+ {
+ case SND_PCM_STREAM_CAPTURE:
+ oss_mode = O_RDONLY;
+ break;
+ case SND_PCM_STREAM_PLAYBACK:
+ oss_mode = O_WRONLY;
+ break;
+ default:
+ fprintf (stderr, "snd_pcm_open: Bad stream %d\n", stream);
+ return -EINVAL;
+ }
+
+ memset (pcm, 0, sizeof (*pcm));
+ pcm->stream = stream;
+ pcm->frame_size = 2;
+ pcm->sample_size = 1;
+ pcm->channels = 2;
+ pcm->oss_mode = oss_mode;
+ pcm->state = SND_PCM_STATE_OPEN;
+ pcm->period_size = PERIOD_SIZE;
+ pcm->periods = 4;
+
+ if ((pcm->fd = open (name, oss_mode, 0)) == -1)
+ {
+ int err = errno;
+ free (pcm);
+ return -err;
+ }
+
+ pcm->info.dev = -1;
+ if (ioctl (pcm->fd, SNDCTL_ENGINEINFO, &pcm->info) == -1)
+ {
+ int err = errno;
+ close (pcm->fd);
+ free (pcm);
+ return -err;
+ }
+
+ dbg_printf ("Opened %s='%s' = %d\n", name, pcm->info.name, pcm->fd);
+ *pcmp = pcm;
+ return 0;
+}
+
+/**
+ * \brief close PCM handle
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified PCM handle and frees all associated
+ * resources.
+ */
+int
+snd_pcm_close (snd_pcm_t * pcm)
+{
+ if (pcm == NULL)
+ return -1;
+ close (pcm->fd);
+ if (pcm->area != NULL)
+ free (pcm->area);
+ free (pcm);
+ return 0;
+}
+
+/**
+ * \brief Convert frames in bytes for a PCM
+ * \param pcm PCM handle
+ * \param frames quantity in frames
+ * \return quantity expressed in bytes
+ */
+ssize_t
+snd_pcm_frames_to_bytes (snd_pcm_t * pcm, snd_pcm_sframes_t frames)
+{
+// printf("snd_pcm_frames_to_bytes(%d)\n", frames);
+ return frames * pcm->frame_size;
+}
+
+/**
+ * \brief Convert bytes in frames for a PCM
+ * \param pcm PCM handle
+ * \param bytes quantity in bytes
+ * \return quantity expressed in frames
+ */
+snd_pcm_sframes_t
+snd_pcm_bytes_to_frames (snd_pcm_t * pcm, ssize_t bytes)
+{
+ dbg_printf3 ("snd_pcm_bytes_to_frames(%d)=%d\n", bytes,
+ bytes / pcm->frame_size);
+ return bytes / pcm->frame_size;
+}
+
+/**
+ * \brief Stop a PCM preserving pending frames
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ * \retval -ESTRPIPE a suspend event occurred
+ *
+ * For playback wait for all pending frames to be played and then stop
+ * the PCM.
+ * For capture stop PCM permitting to retrieve residual frames.
+ *
+ * For stopping the PCM stream immediately, use \link ::snd_pcm_drop() \endlink
+ * instead.
+ */
+int
+snd_pcm_drain (snd_pcm_t * pcm)
+{
+ dbg_printf2 ("snd_pcm_drain()\n");
+ ioctl (pcm->fd, SNDCTL_DSP_SYNC, NULL);
+ return 0;
+}
+
+/**
+ * \brief Stop a PCM dropping pending frames
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * This function stops the PCM <i>immediately</i>.
+ * The pending samples on the buffer are ignored.
+ *
+ * For processing all pending samples, use \link ::snd_pcm_drain() \endlink
+ * instead.
+ */
+int
+snd_pcm_drop (snd_pcm_t * pcm)
+{
+ dbg_printf2 ("snd_pcm_drop()\n");
+ ioctl (pcm->fd, SNDCTL_DSP_HALT, NULL);
+ return 0;
+}
+
+/** \brief Install one PCM hardware configuration chosen from a configuration sp
+ace and #snd_pcm_prepare it
+ * \param pcm PCM handle
+ * \param params Configuration space definition container
+ * \return 0 on success otherwise a negative error code
+ *
+ * The configuration is chosen fixing single parameters in this order:
+ * first access, first format, first subformat, min channels, min rate,
+ * min period time, max buffer size, min tick time
+ *
+ * After this call, #snd_pcm_prepare() is called automatically and
+ * the stream is brought to \c #SND_PCM_STATE_PREPARED state.
+ */
+int
+snd_pcm_hw_params (snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+{
+ int tmp;
+
+ dbg_printf ("snd_pcm_hw_params(%d, %d ch, %x)\n",
+ params->speed, params->channels, params->oss_fmt);
+
+ tmp = params->oss_fmt;
+ if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, &tmp) == -1)
+ return -errno;
+ if (tmp != params->oss_fmt)
+ return -EINVAL;
+
+ tmp = params->channels;
+ if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1)
+ return -errno;
+ if (tmp != params->channels)
+ return -EINVAL;
+ pcm->channels = tmp;
+
+ tmp = params->speed;
+ if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, &tmp) == -1)
+ return -errno;
+ if (tmp != params->speed)
+ return -EINVAL;
+
+ tmp = params->channels * params->sample_bits;
+ pcm->frame_size = params->frame_size = tmp / 8;
+ pcm->sample_size = pcm->frame_size / pcm->channels;
+ dbg_printf ("Frame size = %d\n", params->frame_size);
+ return 0;
+}
+
+
+/**
+ * \brief Fill params with a full configuration space for a PCM
+ * \param pcm PCM handle
+ * \param params Configuration space
+ */
+int
+snd_pcm_hw_params_any (snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+{
+ dbg_printf ("snd_pcm_hw_params_any()\n");
+
+ memset (params, 0, sizeof (params));
+ if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, &params->channels) == -1)
+ return -errno;
+ pcm->channels = params->channels;
+ if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, &params->oss_fmt) == -1)
+ return -errno;
+ if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, &params->speed) == -1)
+ return -errno;
+ dbg_printf ("Rate %d, channels %d, fmt %x\n", params->speed,
+ params->channels, params->oss_fmt);
+
+// TODO
+ params->frame_size = 2 * params->channels;
+ params->sample_bits = 16;
+
+ params->info = &pcm->info;
+ params->pcm = pcm;
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one access type
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param access access type
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ */
+int
+snd_pcm_hw_params_set_access (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ snd_pcm_access_t access)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_access(%x/%s)\n", access,
+ snd_pcm_access_names[access]);
+ params->access = access;
+ if (access == SND_PCM_ACCESS_RW_INTERLEAVED)
+ return 0;
+ if (access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
+ return 0;
+ return -EINVAL;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one buffer size
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val buffer size in frames
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ *
+ * Wanted exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+snd_pcm_hw_params_set_buffer_size (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_hw_params_set_buffer_size()\n");
+
+ return 0;
+}
+
+int
+snd_pcm_hw_params_set_buffer_size_min (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val)
+{
+ dbg_printf ("snd_pcm_hw_params_set_buffer_size_min()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to have buffer size nearest to a target
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target buffer size in frames / returned chosen approxi
+mate target buffer size in frames
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+__snd_pcm_hw_params_set_buffer_size_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val)
+{
+ dbg_printf ("snd_pcm_hw_params_set_buffer_size_near(%d)\n", *val);
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one channels count
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val channels count
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ */
+int
+snd_pcm_hw_params_set_channels (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ unsigned int val)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_channels(%d)\n", val);
+
+ params->channels = val;
+
+ if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, &params->channels) < 0)
+ return -errno;
+
+ if (params->channels != val)
+ return -EINVAL;
+ pcm->channels = params->channels;
+ return 0;
+}
+
+int
+__snd_pcm_hw_params_set_channels_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_channels_near(%d)\n", *val);
+
+ params->channels = *val;
+
+ if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, &params->channels) < 0)
+ return -errno;
+
+ *val = params->channels;
+ pcm->channels = params->channels;
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one format
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param format format
+ * \return 0 otherwise a negative error code
+ */
+int
+snd_pcm_hw_params_set_format (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ snd_pcm_format_t format)
+{
+ int err = -EINVAL;
+ int tmp;
+
+ dbg_printf2 ("snd_pcm_hw_params_set_format(%d)\n", format);
+ if (format == SND_PCM_FORMAT_U8)
+ {
+ params->fmt = format;
+ params->oss_fmt = AFMT_U8;
+ params->sample_bits = 8;
+ err = 0;
+ }
+
+ if (format == SND_PCM_FORMAT_S16_LE)
+ {
+ params->fmt = format;
+ params->oss_fmt = AFMT_S16_LE;
+ params->sample_bits = 16;
+ err = 0;
+ }
+
+ if (err < 0)
+ return err;
+
+ tmp = params->oss_fmt;
+ if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, &tmp) < 0)
+ return -errno;
+
+ if (tmp != params->oss_fmt)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * \brief Extract format from a configuration space
+ * \param params Configuration space
+ * \param format returned format
+ * \return format otherwise a negative error code if not exactly one is present
+ */
+int INTERNAL (snd_pcm_hw_params_get_format) (const snd_pcm_hw_params_t *
+ params,
+ snd_pcm_format_t * format)
+{
+ dbg_printf ("snd_pcm_hw_params_get_format(params=%x)\n", params);
+
+ *format = params->fmt;
+}
+
+/**
+ * \brief Verify if a format is available inside a configuration space for a PCM * \param pcm PCM handle
+ * \param params Configuration space
+ * \param format format
+ * \return 0 if available a negative error code otherwise
+ */
+int
+snd_pcm_hw_params_test_format (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ snd_pcm_format_t format)
+{
+ dbg_printf2 ("snd_pcm_hw_params_test_format()\n");
+
+ if (format == SND_PCM_FORMAT_U8)
+ return 0;
+ if (format == SND_PCM_FORMAT_S16_LE)
+ return 0;
+
+ return -EINVAL;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one periods count
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate periods per buffer
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ *
+ * Wanted exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+snd_pcm_hw_params_set_periods (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ unsigned int val, int dir)
+{
+ dbg_printf
+ ("snd_pcm_hw_params_set_periods(pcm=%x, params=%x, val=%d, dir=%d)\n",
+ pcm, params, val, dir);
+ pcm->periods = val;
+
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only integer periods counts
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ */
+int
+snd_pcm_hw_params_set_periods_integer (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params)
+{
+ dbg_printf ("snd_pcm_hw_params_set_periods_integer()\n");
+ return 0;
+}
+
+/** * \brief Restrict a configuration space with a minimum periods count
+ * \param pcm PCM handle * \param params Configuration space
+ * \param val approximate minimum periods per buffer (on return filled with actual minimum)
+ * \param dir Sub unit direction (on return filled with actual direction) * \return 0 otherwise a negative error code if configuration space would become
+ empty *
+ * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) */
+int
+snd_pcm_hw_params_set_periods_min (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_set_periods_min(%x, %x)\n", val, dir);
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space with a maximum periods count
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate maximum periods per buffer (on return filled with actual maximum)
+ * \param dir Sub unit direction (on return filled with actual direction)
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ *
+ * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
+ */
+int
+snd_pcm_hw_params_set_periods_max (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_set_periods_max(%x, %x)\n", val, dir);
+ return 0;
+ return -EINVAL;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one rate
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate rate
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ *
+ * Wanted exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+snd_pcm_hw_params_set_rate (snd_pcm_t * pcm, snd_pcm_hw_params_t * params,
+ unsigned int val, int dir)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_rate(%d, %d)\n", val, dir);
+
+ params->speed = val;
+
+ if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, &params->speed) < 0)
+ return -errno;
+
+ if (val != params->speed)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * \brief Extract rate from a configuration space
+ * \param params Configuration space
+ * \param val Returned approximate rate
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if not exactly one is present
+ *
+ * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
+ */
+int INTERNAL (snd_pcm_hw_params_get_rate) (const snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_rate(params=%x)=%d\n",
+ params, params->speed);
+
+ *val = params->speed;
+ *dir = 0;
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to have rate nearest to a target
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target rate / returned approximate set rate
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+__snd_pcm_hw_params_set_rate_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_rate_near(%d)\n", *val);
+
+ params->speed = *val;
+
+ if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, &params->speed) < 0)
+ return -errno;
+
+ *val = params->speed;
+ return 0;
+}
+
+/**
+ * \brief get size of #snd_pcm_hw_params_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_hw_params_sizeof ()
+{
+ return sizeof (snd_pcm_hw_params_t);
+}
+
+/**
+ * \brief set nonblock mode
+ * \param pcm PCM handle
+ * \param nonblock 0 = block, 1 = nonblock mode
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_nonblock (snd_pcm_t * pcm, int nonblock)
+{
+ dbg_printf2 ("snd_pcm_nonblock(%d)\n", nonblock);
+
+ if (nonblock == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+/**
+ * \brief Prepare PCM for use
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_prepare (snd_pcm_t * pcm)
+{
+ dbg_printf2 ("snd_pcm_prepare()\n");
+ return 0;
+}
+
+/**
+ * \brief Read interleaved frames from a PCM
+ * \param pcm PCM handle
+ * \param buffer frames containing buffer
+ * \param size frames to be written
+ * \return a positive number of frames actually read otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SN
+D_PCM_STATE_RUNNING)
+ * \retval -EPIPE an overrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting f
+or an application recovery)
+ *
+ * If the blocking behaviour was selected, then routine waits until
+ * all requested bytes are filled. The count of bytes can be less only
+ * if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_readi (snd_pcm_t * pcm, void *buffer, snd_pcm_uframes_t size)
+{
+ int l;
+
+ dbg_printf3 ("snd_pcm_readi(%d)\n", pcm->fd);
+
+ pcm->state = SND_PCM_STATE_RUNNING;
+
+ l = size * pcm->frame_size;
+
+ if ((l = read (pcm->fd, buffer, l)) == -1)
+ return -errno;
+ return l / pcm->frame_size;
+}
+
+/** \brief Remove PCM hardware configuration and free associated resources
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_hw_free (snd_pcm_t * pcm)
+{
+ dbg_printf ("snd_pcm_hw_free()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Remove a PCM from a linked group
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_unlink (snd_pcm_t * pcm)
+{
+ dbg_printf ("snd_pcm_unlink()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Extract tick time from a configuration space
+ * \param params Configuration space
+ * \param val Returned approximate tick duration in us
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if not exactly one is present
+ *
+ * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
+ */
+int INTERNAL (snd_pcm_hw_params_get_tick_time) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_tick_time()\n");
+
+ *val = 1;
+ *dir = 0;
+ return 0;
+}
+
+/**
+ * \brief Write interleaved frames to a PCM
+ * \param pcm PCM handle
+ * \param buffer frames containing buffer
+ * \param size frames to be written
+ * \return a positive number of frames actually written otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SN
+D_PCM_STATE_RUNNING)
+ * \retval -EPIPE an underrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting f
+or an application recovery)
+ *
+ * If the blocking behaviour is selected, then routine waits until
+ * all requested bytes are played or put to the playback ring buffer.
+ * The count of bytes can be less only if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_writei (snd_pcm_t * pcm, const void *buffer, snd_pcm_uframes_t size)
+{
+ int l;
+
+ dbg_printf3 ("snd_pcm_writei(%d)\n", size);
+
+ pcm->state = SND_PCM_STATE_RUNNING;
+
+ l = size * pcm->frame_size;
+
+ if ((l = write (pcm->fd, buffer, l)) == -1)
+ return -errno;
+ return l / pcm->frame_size;
+}
+
+/**
+ * \brief Resume from suspend, no samples are lost
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ * \retval -EAGAIN resume can't be proceed immediately (audio hardware is probab
+ly still suspended)
+ * \retval -ENOSYS hardware doesn't support this feature
+ *
+ * This function can be used when the stream is in the suspend state
+ * to do the fine resume from this state. Not all hardware supports
+ * this feature, when an -ENOSYS error is returned, use the \link ::snd_pcm_prep
+are() \endlink
+ * function to recovery.
+ */
+int
+snd_pcm_resume (snd_pcm_t * pcm)
+{
+ dbg_printf ("snd_pcm_resume()\n");
+ return -EINVAL;
+}
+
+/**
+ * \brief allocate an invalid #snd_pcm_status_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_pcm_status_malloc (snd_pcm_status_t ** ptr)
+{
+ assert (ptr);
+ *ptr = calloc (1, sizeof (snd_pcm_status_t));
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_pcm_status_t
+ * \param pointer to object to free
+ */
+void
+snd_pcm_status_free (snd_pcm_status_t * obj)
+{
+ free (obj);
+}
+
+
+/**
+ * \brief Obtain status (runtime) information for PCM handle
+ * \param pcm PCM handle
+ * \param status Status container
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_status (snd_pcm_t * pcm, snd_pcm_status_t * status)
+{
+ dbg_printf ("snd_pcm_status()\n");
+ return -EINVAL;
+}
+
+/**
+ * \brief Get state from a PCM status container (see #snd_pcm_state)
+ * \return PCM state
+ */
+snd_pcm_state_t
+snd_pcm_status_get_state (const snd_pcm_status_t * obj)
+{
+ dbg_printf ("snd_pcm_status_get_state()\n");
+ return -EINVAL;
+}
+
+/**
+ * \brief Get number of frames available from a PCM status container (see #snd_pcm_avail_update)
+ * \return Number of frames ready to be read/written
+ */
+snd_pcm_uframes_t
+snd_pcm_status_get_avail (const snd_pcm_status_t * obj)
+{
+ dbg_printf ("snd_pcm_status_get_avail()\n");
+
+ return 1;
+}
+
+/**
+ * \brief get size of #snd_pcm_status_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_status_sizeof ()
+{
+ return sizeof (snd_pcm_status_t);
+}
+
+/**
+ * \brief Dump PCM info
+ * \param pcm PCM handle
+ * \param out Output handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_dump (snd_pcm_t * pcm, snd_output_t * out)
+{
+ dbg_printf ("snd_pcm_dump()\n");
+ return 0;
+}
+
+void
+snd_pcm_hw_params_copy (snd_pcm_hw_params_t * dst,
+ const snd_pcm_hw_params_t * src)
+{
+ memcpy (dst, src, sizeof (*dst));
+}
+
+void
+snd_pcm_hw_params_free (snd_pcm_hw_params_t * p)
+{
+ free (p);
+}
+
+int
+snd_pcm_hw_params_can_mmap_sample_resolution (const snd_pcm_hw_params_t *
+ params)
+{
+ return 0;
+}
+
+int
+snd_pcm_hw_params_can_overrange (const snd_pcm_hw_params_t * params)
+{
+ return 0;
+}
+
+int
+snd_pcm_hw_params_can_pause (const snd_pcm_hw_params_t * params)
+{
+ return 0;
+}
+
+int
+snd_pcm_hw_params_can_resume (const snd_pcm_hw_params_t * params)
+{
+ return 0;
+}
+
+int
+snd_pcm_hw_params_can_sync_start (const snd_pcm_hw_params_t * params)
+{
+ return 1;
+}
+
+int
+snd_pcm_hw_params_get_channels (const snd_pcm_hw_params_t * params,
+ unsigned int *val)
+{
+ *val = params->channels;
+ return 0;
+}
+
+int INTERNAL (snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *
+ params, unsigned int *val)
+{
+ *val = params->info->min_channels;
+ return 0;
+}
+
+int INTERNAL (snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *
+ params, unsigned int *val)
+{
+ *val = params->info->max_channels;
+ return 0;
+}
+
+int INTERNAL (snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ *val = params->info->min_rate;
+ return 0;
+}
+
+int INTERNAL (snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ *val = params->info->max_rate;
+ return 0;
+}
+
+// int snd_pcm_hw_params_get_(const snd_pcm_hw_params_t *params, unsigned int *val) { return 0;}
+
+/**
+ * \brief get name of PCM sample format
+ * \param format PCM sample format
+ * \return ascii name of PCM sample format
+ */
+const char *
+snd_pcm_format_name (snd_pcm_format_t format)
+{
+ if (format > SND_PCM_FORMAT_LAST)
+ return NULL;
+ return snd_pcm_format_names[format];
+}
+
+/**
+ * \brief Return PCM state
+ * \param pcm PCM handle
+ * \return PCM state #snd_pcm_state_t of given PCM handle
+ *
+ * This is a faster way to obtain only the PCM state without calling
+ * \link ::snd_pcm_status() \endlink.
+ */
+snd_pcm_state_t
+snd_pcm_state (snd_pcm_t * pcm)
+{
+ dbg_printf3 ("snd_pcm_state()\n");
+ return pcm->state;
+}
+
+/**
+ * \brief allocate an invalid #snd_pcm_info_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_pcm_info_malloc (snd_pcm_info_t ** ptr)
+{
+ assert (ptr);
+ *ptr = calloc (1, sizeof (snd_pcm_info_t));
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_pcm_info_t
+ * \param pointer to object to free
+ */
+void
+snd_pcm_info_free (snd_pcm_info_t * obj)
+{
+ free (obj);
+}
+
+
+/**
+ * \brief Obtain general (static) information for PCM handle
+ * \param pcm PCM handle
+ * \param info Information container
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_info (snd_pcm_t * pcm, snd_pcm_info_t * info)
+{
+ dbg_printf ("snd_pcm_info()\n");
+ memset (info, 0, sizeof (*info));
+ info->ainfo = &pcm->info;
+
+ return 0;
+}
+
+/**
+ * \brief Get card from a PCM info container
+ * \param obj PCM info container
+ * \return card number otherwise a negative error code if not associable to a card
+ */
+int
+snd_pcm_info_get_card (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_card()\n");
+ return obj->ainfo->card_number;
+}
+
+/**
+ * \brief Get device from a PCM info container
+ * \param obj PCM info container
+ * \return device number
+ */
+unsigned int
+snd_pcm_info_get_device (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_device()\n");
+ return obj->ainfo->dev;
+}
+
+/**
+ * \brief Get name from a PCM info container
+ * \param obj PCM info container
+ * \return name of PCM
+ */
+const char *
+snd_pcm_info_get_name (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_name()\n");
+
+ return obj->ainfo->name;
+}
+
+/**
+ * \brief Get subdevice from a PCM info container
+ * \param obj PCM info container
+ * \return subdevice number
+ */
+unsigned int
+snd_pcm_info_get_subdevice (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_subdevice()\n");
+ return 0;
+}
+
+/**
+ * \brief Set wanted device inside a PCM info container (see #snd_ctl_pcm_info)
+ * \param obj PCM info container
+ * \param val Device number
+ */
+void
+snd_pcm_info_set_device (snd_pcm_info_t * obj, unsigned int val)
+{
+ dbg_printf ("snd_pcm_info_set_device()\n");
+}
+
+/**
+ * \brief Set wanted subdevice inside a PCM info container (see #snd_ctl_pcm_info)
+ * \param obj PCM info container
+ * \param val Subdevice number
+ */
+void
+snd_pcm_info_set_subdevice (snd_pcm_info_t * obj, unsigned int val)
+{
+ dbg_printf ("snd_pcm_info_set_subdevice()\n");
+}
+
+void
+snd_pcm_info_set_stream (snd_pcm_info_t * obj, snd_pcm_stream_t val)
+{
+ dbg_printf ("snd_pcm_info_set_stream()\n");
+}
+
+/**
+ * \brief get size of #snd_pcm_info_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_info_sizeof ()
+{
+ return sizeof (snd_pcm_info_t);
+}
+
+
+/**
+ * \brief Return number of frames ready to be read/written
+ * \param pcm PCM handle
+ * \return a positive number of frames ready otherwise a negative
+ * error code
+ *
+ * On capture does all the actions needed to transport to application
+ * level all the ready frames across underlying layers.
+ *
+ * Using of this function is useless for the standard read/write
+ * operations. Use it only for mmap access. See to #snd_pcm_delay.
+ */
+snd_pcm_sframes_t
+snd_pcm_avail_update (snd_pcm_t * pcm)
+{
+ audio_buf_info bi;
+
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ if (ioctl (pcm->fd, SNDCTL_DSP_GETOSPACE, &bi) == -1)
+ return -errno;
+ }
+ else
+ {
+ if (ioctl (pcm->fd, SNDCTL_DSP_GETISPACE, &bi) == -1)
+ return -errno;
+ }
+
+ dbg_printf3 ("snd_pcm_avail_update(pcm=%x)=%d\n", pcm,
+ bi.bytes / pcm->frame_size);
+ return bi.bytes / pcm->frame_size;
+}
+
+/**
+ * \brief Obtain delay for a running PCM handle
+ * \param pcm PCM handle
+ * \param delayp Returned delay in frames
+ * \return 0 on success otherwise a negative error code
+ *
+ * Delay is distance between current application frame position and
+ * sound frame position.
+ * It's positive and less than buffer size in normal situation,
+ * negative on playback underrun and greater than buffer size on
+ * capture overrun.
+ *
+ * Note this function does not update the actual r/w pointer
+ * for applications. The function #snd_pcm_avail_update()
+ * have to be called before any begin+commit operation.
+ */
+int
+snd_pcm_delay (snd_pcm_t * pcm, snd_pcm_sframes_t * delayp)
+{
+ int tmp;
+
+ if (ioctl (pcm->fd, SNDCTL_DSP_GETODELAY, &tmp) < 0)
+ return -errno;
+
+ *delayp = tmp / pcm->frame_size;
+ return 0;
+}
+
+/**
+ * \brief Return bits needed to store a PCM sample
+ * \param format Sample format
+ * \return bits per sample, a negative error code if not applicable
+ */
+int
+snd_pcm_format_physical_width (snd_pcm_format_t format)
+{
+ switch (format)
+ {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_U8:
+ return 8;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ return 16;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ case SNDRV_PCM_FORMAT_S18_3BE:
+ case SNDRV_PCM_FORMAT_U18_3LE:
+ case SNDRV_PCM_FORMAT_U18_3BE:
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ case SNDRV_PCM_FORMAT_U20_3LE:
+ case SNDRV_PCM_FORMAT_U20_3BE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_3BE:
+ case SNDRV_PCM_FORMAT_U24_3LE:
+ case SNDRV_PCM_FORMAT_U24_3BE:
+ return 24;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ case SNDRV_PCM_FORMAT_U24_BE:
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S32_BE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ case SNDRV_PCM_FORMAT_U32_BE:
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ case SNDRV_PCM_FORMAT_FLOAT_BE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+ return 32;
+ case SNDRV_PCM_FORMAT_FLOAT64_LE:
+ case SNDRV_PCM_FORMAT_FLOAT64_BE:
+ return 64;
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ case SNDRV_PCM_FORMAT_A_LAW:
+ return 8;
+ case SNDRV_PCM_FORMAT_IMA_ADPCM:
+ return 4;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * \brief Return bytes needed to store a quantity of PCM sample
+ * \param format Sample format
+ * \param samples Samples count
+ * \return bytes needed, a negative error code if not integer or unknown
+ */
+ssize_t
+snd_pcm_format_size (snd_pcm_format_t format, size_t samples)
+{
+ switch (format)
+ {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_U8:
+ return samples;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ return samples * 2;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ case SNDRV_PCM_FORMAT_S18_3BE:
+ case SNDRV_PCM_FORMAT_U18_3LE:
+ case SNDRV_PCM_FORMAT_U18_3BE:
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ case SNDRV_PCM_FORMAT_U20_3LE:
+ case SNDRV_PCM_FORMAT_U20_3BE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_3BE:
+ case SNDRV_PCM_FORMAT_U24_3LE:
+ case SNDRV_PCM_FORMAT_U24_3BE:
+ return samples * 3;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ case SNDRV_PCM_FORMAT_U24_BE:
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S32_BE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ case SNDRV_PCM_FORMAT_U32_BE:
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ case SNDRV_PCM_FORMAT_FLOAT_BE:
+ return samples * 4;
+ case SNDRV_PCM_FORMAT_FLOAT64_LE:
+ case SNDRV_PCM_FORMAT_FLOAT64_BE:
+ return samples * 8;
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+ return samples * 4;
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ case SNDRV_PCM_FORMAT_A_LAW:
+ return samples;
+ case SNDRV_PCM_FORMAT_IMA_ADPCM:
+ if (samples & 1)
+ return -EINVAL;
+ return samples / 2;
+ default:
+ assert (0);
+ return -EINVAL;
+ }
+}
+
+/**
+ * \brief Dump a PCM hardware configuration space
+ * \param params Configuration space
+ * \param out Output handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_hw_params_dump (snd_pcm_hw_params_t * params, snd_output_t * out)
+{
+ return 0;
+}
+
+/**
+ * \brief Extract buffer size from a configuration space
+ * \param params Configuration space
+ * \param val Returned buffer size in frames
+ * \return 0 otherwise a negative error code if not exactly one is present
+ */
+int
+__snd_pcm_hw_params_get_buffer_size (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val)
+{
+ *val = 65536;
+
+ return 0;
+}
+
+int
+snd_pcm_hw_params_get_buffer_size_min (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val)
+{
+ *val = 65536;
+
+ return 0;
+}
+
+int
+snd_pcm_hw_params_get_buffer_size_max (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val)
+{
+ *val = 65536;
+
+ return 0;
+}
+
+/**
+ * \brief Extract access type from a configuration space
+ * \param params Configuration space
+ * \param access Returned value
+ * \return access type otherwise a negative error code if not exactly one is present
+ */
+int INTERNAL (snd_pcm_hw_params_get_access) (const snd_pcm_hw_params_t *
+ params,
+ snd_pcm_access_t * access)
+{
+ dbg_printf ("snd_pcm_hw_params_get_access()\n"), *access = params->access;
+
+ return 0;
+}
+
+/**
+ * \brief Extract period size from a configuration space
+ * \param params Configuration space
+ * \param val Returned approximate period size in frames
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if not exactly one is present
+ *
+ * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
+ */
+int
+__snd_pcm_hw_params_get_period_size (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_period_size(params=%x)=%d\n",
+ params, params->pcm->period_size);
+ *val = params->pcm->period_size;
+ if (dir) *dir = 0;
+ return 0;
+}
+
+int
+snd_pcm_hw_params_get_period_size_min (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_period_size_min(params=%x)=%d\n",
+ params, params->pcm->period_size);
+ *val = params->pcm->period_size;
+ if (dir) *dir = 0;
+ return 0;
+}
+
+int
+snd_pcm_hw_params_get_period_size_max (const snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val, int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_period_size_min(params=%x)=%d\n",
+ params, params->pcm->period_size);
+ *val = params->pcm->period_size;
+ if (dir) *dir = 0;
+ return 0;
+}
+
+/**
+ * \brief Extract periods from a configuration space
+ * \param params Configuration space
+ * \param val approximate periods per buffer
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if not exactly one is present
+ *
+ * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
+ */
+int INTERNAL (snd_pcm_hw_params_get_periods) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_periods(params=%x)=%d\n",
+ params, params->pcm->periods);
+
+ *val = params->pcm->periods;
+
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to have period size nearest to a target * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target period size in frames / returned chosen approximate target period size
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+__snd_pcm_hw_params_set_period_size_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t * val, int *dir)
+{
+ dbg_printf
+ ("snd_pcm_hw_params_set_period_size_near(pcm=%x, params=%x, val=%d, dir=%d)\n",
+ pcm, params, *val, dir?*dir:-1);
+ pcm->period_size = *val;
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to have buffer time nearest to a target * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+__snd_pcm_hw_params_set_period_time_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ dbg_printf2 ("snd_pcm_hw_params_set_period_time_near()\n");
+ return 0;
+}
+
+/**
+ * \brief Application request to access a portion of direct (mmap) area
+ * \param pcm PCM handle
+ * \param areas Returned mmap channel areas
+ * \param offset Returned mmap area offset in area steps (== frames)
+ * \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit)
+ * \return 0 on success otherwise a negative error code
+ *
+ * It is necessary to call the snd_pcm_avail_update() function directly before
+ * this call. Otherwise, this function can return a wrong count of available frames.
+ *
+ * The function should be called before a sample-direct area can be accessed.
+ * The resulting size parameter is always less or equal to the input count of frames
+ * and can be zero, if no frames can be processed (the ring buffer is full).
+ *
+ * See the snd_pcm_mmap_commit() function to finish the frame processing in
+ * the direct areas.
+ */
+int
+snd_pcm_mmap_begin (snd_pcm_t * pcm,
+ const snd_pcm_channel_area_t ** areas,
+ snd_pcm_uframes_t * offset, snd_pcm_uframes_t * frames)
+{
+ dbg_printf2 ("snd_pcm_mmap_begin(frames=%d)\n", *frames);
+ if (pcm->area == NULL)
+ {
+ pcm->area = malloc (sizeof (*pcm->area) * pcm->channels);
+ pcm->area[0].addr = malloc (65536);
+ pcm->area[0].first = 0;
+ pcm->area[0].step = pcm->frame_size * 8;
+ pcm->area[1].addr = pcm->area[0].addr + pcm->sample_size;
+ pcm->area[1].first = 0;
+ pcm->area[1].step = pcm->frame_size * 8;
+ }
+
+ *areas = pcm->area;
+ *offset = 0;
+ if (*frames * pcm->frame_size > 65536)
+ *frames = 65536 / pcm->frame_size;
+ return 0;
+}
+
+/**
+ * \brief Application has completed the access to area requested with #snd_pcm_mmap_begin
+ * \param pcm PCM handle
+ * \param offset area offset in area steps (== frames)
+ * \param size area portion size in frames
+ * \return count of transferred frames otherwise a negative error code
+ *
+ * You should pass this function the offset value that
+ * snd_pcm_mmap_begin() returned. The frames parameter should hold the
+ * number of frames you have written or read to/from the audio
+ * buffer. The frames parameter must never exceed the contiguous frames
+ * count that snd_pcm_mmap_begin() returned. Each call to snd_pcm_mmap_begin()
+ * must be followed by a call to snd_pcm_mmap_commit().
+ *
+ * Example:
+\code
+ double phase = 0;
+ const snd_pcm_area_t *areas;
+ snd_pcm_sframes_t avail, size, commitres;
+ snd_pcm_uframes_t offset, frames;
+ int err;
+
+ avail = snd_pcm_avail_update(pcm);
+ if (avail < 0)
+ error(avail);
+ // at this point, we can transfer at least 'avail' frames
+
+ // we want to process frames in chunks (period_size)
+ if (avail < period_size)
+ goto _skip;
+ size = period_size;
+ // it is possible that contiguous areas are smaller, thus we use a loop
+ while (size > 0) {
+ frames = size;
+
+ err = snd_pcm_mmap_begin(pcm_handle, &areas, &offset, &frames);
+ if (err < 0)
+ error(err);
+ // this function fills the areas from offset with count of frames
+ generate_sine(areas, offset, frames, &phase);
+ commitres = snd_pcm_mmap_commit(pcm_handle, offset, frames);
+ if (commitres < 0 || commitres != frames)
+ error(commitres >= 0 ? -EPIPE : commitres);
+
+ size -= frames;
+ }
+ _skip:
+\endcode
+ *
+ * Look to the \ref example_test_pcm "Sine-wave generator" example
+ * for more details about the generate_sine function.
+ */
+snd_pcm_sframes_t
+snd_pcm_mmap_commit (snd_pcm_t * pcm,
+ snd_pcm_uframes_t offset, snd_pcm_uframes_t frames)
+{
+ dbg_printf2 ("snd_pcm_mmap_commit(frames=%d, offs=%d)\n", frames, offset);
+
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ return snd_pcm_writei (pcm, pcm->area[0].addr, frames);
+
+ if (pcm->stream == SND_PCM_STREAM_CAPTURE)
+ return snd_pcm_readi (pcm, pcm->area[0].addr, frames);
+
+ return -EFAULT;
+}
+
+/**
+ * \brief Restrict a configuration space to have buffer time nearest to a target * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+__snd_pcm_hw_params_set_buffer_time_near (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ unsigned int *val, int *dir)
+{
+ *val = 10;
+ dbg_printf2 ("snd_pcm_hw_params_set_buffer_time_near()\n");
+ return 0;
+}
+
+/**
+ * \brief Pause/resume PCM
+ * \param pcm PCM handle
+ * \param pause 0 = resume, 1 = pause
+ * \return 0 on success otherwise a negative error code
+ *
+ * Note that this function works only on the hardware which supports
+ * pause feature. You can check it via \link ::snd_pcm_hw_params_can_pause() \endlink
+ * function.
+ */
+int
+snd_pcm_pause (snd_pcm_t * pcm, int enable)
+{
+ dbg_printf ("snd_pcm_pause()\n");
+ return -EINVAL;
+}
+
+/**
+ * \brief Start a PCM
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_start (snd_pcm_t * pcm)
+{
+ dbg_printf ("snd_pcm_start()\n");
+ return 0;
+}
+
+/**
+ * \brief Convert samples in bytes for a PCM
+ * \param pcm PCM handle
+ * \param samples quantity in samples
+ * \return quantity expressed in bytes
+ */
+ssize_t
+snd_pcm_samples_to_bytes (snd_pcm_t * pcm, long samples)
+{
+ dbg_printf2 ("snd_pcm_samples_to_bytes(%d)=%d\n", samples,
+ samples * pcm->sample_size);
+ return samples * pcm->sample_size;
+}
+
+
+/**
+ * \brief Dump status
+ * \param status Status container
+ * \param out Output handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_status_dump (snd_pcm_status_t * status, snd_output_t * out)
+{
+ return 0;
+}
+
+/** \brief Install PCM software configuration defined by params
+ * \param pcm PCM handle
+ * \param params Configuration container
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_sw_params (snd_pcm_t * pcm, snd_pcm_sw_params_t * params)
+{
+ dbg_printf2 ("snd_pcm_sw_params()\n");
+ // NOP
+ return 0;
+}
+
+/**
+ * \brief Return current software configuration for a PCM
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_sw_params_current (snd_pcm_t * pcm, snd_pcm_sw_params_t * params)
+{
+ dbg_printf2 ("snd_pcm_sw_params_current()\n");
+ // NOP
+ return 0;
+}
+
+/**
+ * \brief Dump a software configuration
+ * \param params Software configuration container
+ * \param out Output handle
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_sw_params_dump (snd_pcm_sw_params_t * params, snd_output_t * out)
+{
+ return 0;
+}
+
+/**
+ * \brief Set start threshold inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Start threshold in frames
+ * \return 0 otherwise a negative error code
+ *
+ * PCM is automatically started when playback frames available to PCM
+ * are >= threshold or when requested capture frames are >= threshold
+ */
+int
+snd_pcm_sw_params_set_start_threshold (snd_pcm_t * pcm,
+ snd_pcm_sw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf2 ("snd_pcm_sw_params_set_start_threshold(%d)\n", val);
+ // NOP
+ return 0;
+}
+
+/**
+ * \brief get size of #snd_pcm_sw_params_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_sw_params_sizeof ()
+{
+ return sizeof (snd_pcm_sw_params_t);
+}
+
+/**
+ * \brief Restrict a configuration space to have periods count nearest to a target
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate target periods per buffer / returned chosen approximate target periods per buffer
+ * \return 0 otherwise a negative error code if configuration space is empty
+ *
+ * target/chosen exact value is <,=,> val following dir (-1,0,1)
+ */
+int INTERNAL (snd_pcm_hw_params_set_periods_near) (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ dbg_printf
+ ("snd_pcm_hw_params_set_periods_near(pcm=%x, params=%x, val=%d, dir=%d)\n");
+ pcm->periods = *val;
+ return 0;
+}
+
+/**
+ * \brief get poll descriptors
+ * \param pcm PCM handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \return count of filled descriptors
+ *
+ * This function fills the given poll descriptor structs for the specified
+ * PCM handle. The poll desctiptor array should have the size returned by
+ * \link ::snd_pcm_poll_descriptors_count() \endlink function.
+ *
+ * The result is intended for direct use with the poll() syscall.
+ *
+ * For reading the returned events of poll descriptor after poll() system
+ * call, use \link ::snd_pcm_poll_descriptors_revents() \endlink function.
+ * The field values in pollfd structs may be bogus regarding the stream
+ * direction from the application perspective (POLLIN might not imply read
+ * direction and POLLOUT might not imply write), but
+ * the \link ::snd_pcm_poll_descriptors_revents() \endlink function
+ * does the right "demangling".
+ *
+ * You can use output from this function as arguments for the select()
+ * syscall, too.
+ */
+int
+snd_pcm_poll_descriptors (snd_pcm_t * pcm, struct pollfd *pfds,
+ unsigned int space)
+{
+ dbg_printf2 ("snd_pcm_poll_descriptors(pcm=%x)\n", pcm);
+
+ pfds->fd = pcm->fd;
+ pfds->events = 0;
+ pfds->revents = 0;
+
+ if (pcm->oss_mode == O_WRONLY || pcm->oss_mode == O_RDWR)
+ pfds->events = POLLOUT;
+ if (pcm->oss_mode == O_RDONLY || pcm->oss_mode == O_RDWR)
+ pfds->events = POLLIN;
+
+ return 1;
+}
+
+/**
+ * \brief get count of poll descriptors for PCM handle
+ * \param pcm PCM handle
+ * \return count of poll descriptors
+ */
+int
+snd_pcm_poll_descriptors_count (snd_pcm_t * pcm)
+{
+ dbg_printf ("snd_pcm_poll_descriptors_count()\n");
+
+ return 1;
+}
+
+/**
+ * \brief get returned events from poll descriptors
+ * \param pcm PCM 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
+ *
+ * This function does "demangling" of the revents mask returned from
+ * the poll() syscall to correct semantics (POLLIN = read, POLLOUT = write).
+ *
+ * Note: The null event also exists. Even if poll() or select()
+ * syscall returned that some events are waiting, this function might
+ * return empty set of events. In this case, application should
+ * do next event waiting using poll() or select().
+ */
+int
+snd_pcm_poll_descriptors_revents (snd_pcm_t * pcm, struct pollfd *pfds,
+ unsigned int nfds, unsigned short *revents)
+{
+ dbg_printf3 ("snd_pcm_poll_descriptors_revents()\n");
+
+ *revents = pfds->revents;
+ return 0;
+}
+
+/**
+ * \brief allocate an invalid #snd_pcm_hw_params_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_pcm_hw_params_malloc (snd_pcm_hw_params_t ** ptr)
+{
+ *ptr = calloc (1, sizeof (snd_pcm_hw_params_t));
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_pcm_sw_params_t
+ * \param pointer to object to free
+ */
+void
+snd_pcm_sw_params_free (snd_pcm_sw_params_t * obj)
+{
+ free (obj);
+}
+
+/**
+ * \brief Write non interleaved frames to a PCM
+ * \param pcm PCM handle
+ * \param bufs frames containing buffers (one for each channel)
+ * \param size frames to be written
+ * \return a positive number of frames actually written otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an underrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour is selected, then routine waits until
+ * all requested bytes are played or put to the playback ring buffer.
+ * The count of bytes can be less only if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_writen (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_writen()\n");
+ // Not supported
+ return -EINVAL;
+}
+
+/**
+ * \brief Read non interleaved frames to a PCM
+ * \param pcm PCM handle
+ * \param bufs frames containing buffers (one for each channel)
+ * \param size frames to be written
+ * \return a positive number of frames actually read otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an overrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour was selected, then routine waits until
+ * all requested bytes are filled. The count of bytes can be less only
+ * if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_readn (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_readn()\n");
+ // Not supported
+ return -EINVAL;
+}
+
+/**
+ * \brief Get trigger timestamp from a PCM status container
+ * \param ptr Pointer to returned timestamp
+ */
+void
+snd_pcm_status_get_trigger_tstamp (const snd_pcm_status_t * obj,
+ snd_timestamp_t * ptr)
+{
+ dbg_printf ("snd_pcm_status_get_trigger_tstamp()\n");
+ ptr->tv_sec = 0;
+ ptr->tv_usec = 0;
+}
+
+/**
+ * \brief Set xfer align inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Chunk size (frames are attempted to be transferred in chunks)
+ * \return 0 otherwise a negative error code
+ */
+int
+snd_pcm_sw_params_set_xfer_align (snd_pcm_t * pcm,
+ snd_pcm_sw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_xfer_align(%d)\n", val);
+ // TODO
+ return 0;
+}
+
+/**
+ * \brief Get xfer align from a software configuration container
+ * \param params Software configuration container
+ * \param val returned chunk size (frames are attempted to be transferred in chunks)
+ * \param 0 otherwise a negative error code
+ */
+int INTERNAL (snd_pcm_sw_params_get_xfer_align) (const snd_pcm_sw_params_t *
+ params,
+ snd_pcm_uframes_t * val)
+{
+ dbg_printf ("snd_pcm_sw_params_get_xfer_align()\n");
+
+ return 8;
+}
+
+/**
+ * \brief Set avail min inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Minimum avail frames to consider PCM ready
+ * \return 0 otherwise a negative error code
+ *
+ * Note: This is similar to setting an OSS wakeup point. The valid
+ * values for 'val' are determined by the specific hardware. Most PC
+ * sound cards can only accept power of 2 frame counts (i.e. 512,
+ * 1024, 2048). You cannot use this as a high resolution timer - it
+ * is limited to how often the sound card hardware raises an
+ * interrupt. Note that you can greatly improve the reponses using
+ * \ref snd_pcm_sw_params_set_sleep_min where another timing source
+ * is used.
+ */
+int
+snd_pcm_sw_params_set_avail_min (snd_pcm_t * pcm ATTRIBUTE_UNUSED,
+ snd_pcm_sw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_avail_min()\n");
+ // NOP
+ return 0;
+}
+
+/**
+ * \brief Set minimum number of ticks to sleep inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Minimum ticks to sleep or 0 to disable the use of tick timer
+ * \return 0 otherwise a negative error code
+ */
+int
+snd_pcm_sw_params_set_sleep_min (snd_pcm_t * pcm ATTRIBUTE_UNUSED,
+ snd_pcm_sw_params_t * params,
+ unsigned int val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_sleep_min()\n");
+ // NOP
+
+ return 0;
+}
+
+/**
+ * \brief Wait for a PCM to become ready
+ * \param pcm PCM handle
+ * \param timeout maximum time in milliseconds to wait
+ * \return a positive value on success otherwise a negative error code
+ * (-EPIPE for the xrun and -ESTRPIPE for the suspended status,
+ * others for general errors)
+ * \retval 0 timeout occurred
+ * \retval 1 PCM stream is ready for I/O
+ */
+int
+snd_pcm_wait (snd_pcm_t * pcm, int timeout)
+{
+ fd_set fds, *readfds = NULL, *writefds = NULL;
+ struct timeval wait, *w = NULL;
+
+ dbg_printf ("snd_pcm_wait(%d)\n", timeout);
+
+ FD_ZERO (&fds);
+ FD_SET (pcm->fd, &fds);
+
+ if (timeout > 0)
+ {
+ wait.tv_sec = timeout / 1000;
+ wait.tv_usec = (timeout % 1000) * 1000;
+ w = &wait;
+ }
+
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ writefds = &fds;
+ else
+ readfds = &fds;
+
+ dbg_printf ("select(%d, %x, %x, NULL, %x)\n",
+ pcm->fd + 1, readfds, writefds, w);
+ if (select (pcm->fd + 1, readfds, writefds, NULL, w) == -1)
+ return -errno;
+
+ return FD_ISSET (pcm->fd, &fds);
+}
+
+/**
+ * \brief allocate an invalid #snd_pcm_sw_params_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_pcm_sw_params_malloc (snd_pcm_sw_params_t ** ptr)
+{
+ *ptr = calloc (1, sizeof (snd_pcm_sw_params_t));
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief Extract period time from a configuration space
+ * \param params Configuration space
+ * \param val Returned approximate period duration in us
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if not exactly one is present
+ *
+ * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
+ */
+int INTERNAL (snd_pcm_hw_params_get_period_time) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_period_time()\n");
+ // TODO
+ return -EINVAL;
+}
+
+int INTERNAL (snd_pcm_hw_params_get_buffer_time) (const snd_pcm_hw_params_t *
+ params, unsigned int *val,
+ int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_buffer_time()\n");
+ // What's this?
+ return -EINVAL;
+}
+
+struct _snd_mask
+{
+ unsigned int bits[4];
+};
+
+struct _snd_pcm_access_mask
+{
+ unsigned int bits[4];
+};
+
+#define MASK_OFS(v) (v/32)
+#define MASK_BIT(v) (1<<(v%32))
+
+/**
+ * \brief reset all bits in a #snd_pcm_access_mask_t
+ * \param mask pointer to mask
+ */
+void
+snd_pcm_access_mask_none (snd_pcm_access_mask_t * mask)
+{
+ dbg_printf ("snd_pcm_access_mask_none()\n");
+ memset (mask, 0, sizeof (*mask));
+}
+
+/**
+ * \brief make an access type present in a #snd_pcm_access_mask_t
+ * \param mask pointer to mask
+ * \param val access type
+ */
+void
+snd_pcm_access_mask_set (snd_pcm_access_mask_t * mask, snd_pcm_access_t val)
+{
+ dbg_printf ("snd_pcm_access_mask_t(%d)\n", val);
+ mask->bits[MASK_OFS (val)] |= MASK_BIT (val);
+}
+
+/**
+ * \brief get size of #snd_pcm_access_mask_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_access_mask_sizeof ()
+{
+ return sizeof (snd_pcm_access_mask_t);
+}
+
+/**
+ * \brief Restrict a configuration space to contain only a set of access types
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param mask Access mask
+ * \return 0 otherwise a negative error code
+ */
+int
+snd_pcm_hw_params_set_access_mask (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_access_mask_t * mask)
+{
+ dbg_printf ("snd_pcm_hw_params_set_access_mask()\n");
+ // NOP
+ return 0;
+}
+
+/**
+ * \brief Read interleaved frames from a PCM using direct buffer (mmap)
+ * \param pcm PCM handle
+ * \param buffer frames containing buffer
+ * \param size frames to be written
+ * \return a positive number of frames actually read otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an overrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour was selected, then routine waits until
+ * all requested bytes are filled. The count of bytes can be less only
+ * if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_mmap_readi (snd_pcm_t * pcm, void *buffer, snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_mmap_readi()\n");
+ return snd_pcm_readi (pcm, buffer, size);
+}
+
+/**
+ * \brief Read non interleaved frames to a PCM using direct buffer (mmap)
+ * \param pcm PCM handle
+ * \param bufs frames containing buffers (one for each channel)
+ * \param size frames to be written
+ * \return a positive number of frames actually read otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an overrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour was selected, then routine waits until
+ * all requested bytes are filled. The count of bytes can be less only
+ * if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_mmap_readn (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_mmap_readn()\n");
+ return snd_pcm_readn (pcm, bufs, size);
+}
+
+/**
+ * \brief Write interleaved frames to a PCM using direct buffer (mmap)
+ * \param pcm PCM handle
+ * \param buffer frames containing buffer
+ * \param size frames to be written
+ * \return a positive number of frames actually written otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an underrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour is selected, then routine waits until
+ * all requested bytes are played or put to the playback ring buffer.
+ * The count of bytes can be less only if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_mmap_writei (snd_pcm_t * pcm, const void *buffer,
+ snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_mmap_writei()\n");
+
+ return snd_pcm_writei (pcm, buffer, size);
+}
+
+/**
+ * \brief Write non interleaved frames to a PCM using direct buffer (mmap)
+ * \param pcm PCM handle
+ * \param bufs frames containing buffers (one for each channel)
+ * \param size frames to be written
+ * \return a positive number of frames actually written otherwise a
+ * negative error code
+ * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
+ * \retval -EPIPE an underrun occurred
+ * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
+ *
+ * If the blocking behaviour is selected, then routine waits until
+ * all requested bytes are played or put to the playback ring buffer.
+ * The count of bytes can be less only if a signal or underrun occurred.
+ *
+ * If the non-blocking behaviour is selected, then routine doesn't wait at all.
+ */
+snd_pcm_sframes_t
+snd_pcm_mmap_writen (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size)
+{
+ dbg_printf ("snd_pcm_mmap_writen()\n");
+ return snd_pcm_writen (pcm, bufs, size);
+}
+
+/**
+ * \brief Link two PCMs
+ * \param pcm1 first PCM handle
+ * \param pcm2 first PCM handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * The two PCMs will start/stop/prepare in sync.
+ */
+int
+snd_pcm_link (snd_pcm_t * pcm1, snd_pcm_t * pcm2)
+{
+ dbg_printf ("snd_pcm_link()\n");
+ return -EINVAL;
+}
+
+/**
+ * \brief Set silence size inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Silence size in frames (0 for disabled)
+ * \return 0 otherwise a negative error code
+ *
+ * A portion of playback buffer is overwritten with silence when playback
+ * underrun is nearer than silence threshold (see
+ * #snd_pcm_sw_params_set_silence_threshold)
+ *
+ * The special case is when silence size value is equal or greater than
+ * boundary. The unused portion of the ring buffer (initial written samples
+ * are untouched) is filled with silence at start. Later, only just processed
+ * sample area is filled with silence. Note: silence_threshold must be set to zero.
+ */
+int
+snd_pcm_sw_params_set_silence_size (snd_pcm_t * pcm,
+ snd_pcm_sw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_silence_size()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Set silence threshold inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Silence threshold in frames
+ * \return 0 otherwise a negative error code
+ *
+ * A portion of playback buffer is overwritten with silence (see
+ * #snd_pcm_sw_params_set_silence_size) when playback underrun is nearer
+ * than silence threshold.
+ */
+int
+snd_pcm_sw_params_set_silence_threshold (snd_pcm_t * pcm, snd_pcm_sw_params_t
+ * params, snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_silence_threshold()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Restrict a configuration space to contain only one period size
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val approximate period size in frames
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code if configuration space would become empty
+ *
+ * Wanted exact value is <,=,> val following dir (-1,0,1)
+ */
+int
+snd_pcm_hw_params_set_period_size (snd_pcm_t * pcm,
+ snd_pcm_hw_params_t * params,
+ snd_pcm_uframes_t val, int dir)
+{
+ dbg_printf
+ ("snd_pcm_hw_params_set_period_size(pcm=%x, params=%x, val=%d, dir=%d)\n",
+ pcm, params, val, dir);
+ pcm->period_size = val;
+ return 0;
+}
+
+/**
+ * \brief Set stop threshold inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Stop threshold in frames
+ * \return 0 otherwise a negative error code
+ *
+ * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available
+ * frames is >= threshold. If the stop threshold is equal to boundary (also
+ * software parameter - sw_param) then automatic stop will be disabled
+ * (thus device will do the endless loop in the ring buffer).
+ */
+int
+snd_pcm_sw_params_set_stop_threshold (snd_pcm_t * pcm,
+ snd_pcm_sw_params_t * params,
+ snd_pcm_uframes_t val)
+{
+ dbg_printf ("snd_pcm_sw_params_set_stop_threshold()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Return 16 bit expressing silence for a PCM sample format
+ * \param format Sample format
+ * \return silence 16 bit word
+ */
+u_int16_t
+snd_pcm_format_silence_16 (snd_pcm_format_t format)
+{
+ dbg_printf ("snd_pcm_format_silence_16(%x)\n", format);
+ return 0;
+}
+
+/**
+ * \brief Return 8 bit expressing silence for a PCM sample format
+ * \param format Sample format
+ * \return silence 8 bit word
+ */
+u_int8_t
+snd_pcm_format_silence (snd_pcm_format_t format)
+{
+
+ dbg_printf ("snd_pcm_format_silence(%x)\n", format);
+
+ return 0x80;
+}
+
+
+/**
+ * \brief Return 32 bit expressing silence for a PCM sample format
+ * \param format Sample format
+ * \return silence 32 bit word
+ */
+u_int32_t
+snd_pcm_format_silence_32 (snd_pcm_format_t format)
+{
+ dbg_printf ("snd_pcm_format_silence_32(%x)\n", format);
+ return 0;
+}
+
+
+/**
+ * \brief Get available subdevices count from a PCM info container
+ * \param obj PCM info container
+ * \return available subdevices count of PCM
+ */
+unsigned int
+snd_pcm_info_get_subdevices_avail (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_subdevices_avail()\n");
+
+ return 1;
+}
+
+/**
+ * \brief get description of PCM sample format
+ * \param format PCM sample format
+ * \return ascii description of PCM sample format
+ */
+const char *
+snd_pcm_format_description (snd_pcm_format_t format)
+{
+ if (format > SND_PCM_FORMAT_LAST)
+ return NULL;
+ return snd_pcm_format_descriptions[format];
+}
+
+/**
+ * \brief Get subdevices count from a PCM info container
+ * \param obj PCM info container
+ * \return subdevices total count of PCM
+ */
+unsigned int
+snd_pcm_info_get_subdevices_count (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_subdevices_count()\n");
+
+ return 1;
+}
+
+/**
+ * \brief Silence a PCM samples buffer
+ * \param format Sample format
+ * \param data Buffer
+ * \return samples Samples count
+ */
+int
+snd_pcm_format_set_silence (snd_pcm_format_t format, void *data,
+ unsigned int samples)
+{
+ dbg_printf ("snd_pcm_format_set_silence()\n");
+
+ return 0;
+}
+
+
+/**
+ * \brief get identifier of PCM handle
+ * \param pcm PCM handle
+ * \return ascii identifier of PCM handle
+ *
+ * Returns the ASCII identifier of given PCM handle. It's the same
+ * identifier specified in snd_pcm_open().
+ */
+const char *
+snd_pcm_name (snd_pcm_t * pcm)
+{
+ return pcm->info.name;
+}
+
+/**
+ * \brief get name of PCM state
+ * \param state PCM state
+ * \return ascii name of PCM state
+ */
+const char *
+snd_pcm_state_name (snd_pcm_state_t state)
+{
+ if (state > SND_PCM_STATE_LAST)
+ return NULL;
+ return snd_pcm_state_names[state];
+
+}
+
+/**
+ * \brief get name of PCM stream type
+ * \param stream PCM stream type
+ * \return ascii name of PCM stream type
+ */
+const char *
+snd_pcm_stream_name (snd_pcm_stream_t stream)
+{
+ assert (stream <= SND_PCM_STREAM_LAST);
+ return snd_pcm_stream_names[stream];
+}
+
+/**
+ * \brief Extract maximum buffer time from a configuration space
+ * \param params Configuration space
+ * \param val approximate maximum buffer duration in us
+ * \param dir Sub unit direction
+ * \return 0 otherwise a negative error code
+ *
+ * Exact value is <,=,> the returned one following dir (-1,0,1)
+ */
+int INTERNAL (snd_pcm_hw_params_get_buffer_time_max) (const
+ snd_pcm_hw_params_t *
+ params,
+ unsigned int *val,
+ int *dir)
+{
+ dbg_printf ("snd_pcm_hw_params_get_buffer_time_max()\n");
+ return 0;
+}
+
+/**
+ * \brief Get subdevice name from a PCM info container
+ * \param obj PCM info container
+ * \return name of used PCM subdevice
+ */
+const char *
+snd_pcm_info_get_subdevice_name (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_subdevice_name()\n");
+
+ return "OSS subname";
+}
+
+int
+snd_device_name_hint (int card, const char * iface, void *** hints)
+{
+ dbg_printf ("snd_device_name_hint()\n");
+
+ return -1;
+}
+
+int
+snd_pcm_hw_params_is_monotonic (const snd_pcm_hw_params_t * params)
+{
+ return 0;
+}
+
+/**
+ * \brief get PCM sample format from name
+ * \param name PCM sample format name (case insensitive)
+ * \return PCM sample format
+ */
+snd_pcm_format_t
+snd_pcm_format_value (const char *name)
+{
+ snd_pcm_format_t format;
+ for (format = 0; format <= SND_PCM_FORMAT_LAST; format++)
+ {
+ if (snd_pcm_format_names[format] &&
+ strcasecmp (name, snd_pcm_format_names[format]) == 0)
+ {
+ return format;
+ }
+ }
+ for (format = 0; format <= SND_PCM_FORMAT_LAST; format++)
+ {
+ if (snd_pcm_format_descriptions[format] &&
+ strcasecmp (name, snd_pcm_format_descriptions[format]) == 0)
+ {
+ return format;
+ }
+ }
+ return SND_PCM_FORMAT_UNKNOWN;
+}
+
+
+/**
+ * \brief Get id from a PCM info container
+ * \param obj PCM info container
+ * \return short id of PCM
+ */
+const char *
+snd_pcm_info_get_id (const snd_pcm_info_t * obj)
+{
+ dbg_printf ("snd_pcm_info_get_id()\n");
+
+ return "OSS ID";
+}
+
+/**
+ * \brief Return nominal bits per a PCM sample
+ * \param format Sample format
+ * \return bits per sample, a negative error code if not applicable
+ */
+int
+snd_pcm_format_width (snd_pcm_format_t format)
+{
+ switch (format)
+ {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_U8:
+ return 8;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ return 16;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ case SNDRV_PCM_FORMAT_S18_3BE:
+ case SNDRV_PCM_FORMAT_U18_3LE:
+ case SNDRV_PCM_FORMAT_U18_3BE:
+ return 18;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ case SNDRV_PCM_FORMAT_U20_3LE:
+ case SNDRV_PCM_FORMAT_U20_3BE:
+ return 20;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ case SNDRV_PCM_FORMAT_U24_BE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_3BE:
+ case SNDRV_PCM_FORMAT_U24_3LE:
+ case SNDRV_PCM_FORMAT_U24_3BE:
+ return 24;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S32_BE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ case SNDRV_PCM_FORMAT_U32_BE:
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ case SNDRV_PCM_FORMAT_FLOAT_BE:
+ return 32;
+ case SNDRV_PCM_FORMAT_FLOAT64_LE:
+ case SNDRV_PCM_FORMAT_FLOAT64_BE:
+ return 64;
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+ return 32;
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ case SNDRV_PCM_FORMAT_A_LAW:
+ return 8;
+ case SNDRV_PCM_FORMAT_IMA_ADPCM:
+ return 4;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/**
+ * \brief Add an async handler for a PCM
+ * \param handler Returned handler handle
+ * \param pcm PCM handle
+ * \param callback Callback function
+ * \param private_data Callback private data
+ * \return 0 otherwise a negative error code on failure
+ *
+ * The asynchronous callback is called when period boundary elapses.
+ */
+int
+snd_async_add_pcm_handler (snd_async_handler_t ** handler, snd_pcm_t * pcm,
+ snd_async_callback_t callback, void *private_data)
+{
+ dbg_printf ("snd_async_add_pcm_handler()\n");
+
+ return -EINVAL;
+}
+
+void *
+snd_async_handler_get_callback_private (snd_async_handler_t * handler)
+{
+ // What's this?
+ dbg_printf ("snd_async_handler_get_callback_private()\n");
+ return NULL;
+}
+
+/*
+ * What's this?
+ */
+int
+snd_pcm_format_linear (snd_pcm_format_t format)
+{
+ return 1;
+}
+
+/*
+ * What's this?
+ */
+int
+snd_pcm_format_float (snd_pcm_format_t format)
+{
+ return 0;
+}
+
+/*
+ * What's this?
+ */
+int
+snd_pcm_format_signed (snd_pcm_format_t format)
+{
+ return (format != SND_PCM_FORMAT_U8);
+}
+
+/*
+ * What's this?
+ */
+snd_pcm_format_t
+snd_pcm_build_linear_format (int width, int pwidth, int unsignd,
+ int big_endian)
+{
+ printf ("Invalid ALSA call snd_pcm_build_linear_format()\n");
+ return 0;
+}
+
+int
+snd_pcm_format_cpu_endian (snd_pcm_format_t format)
+{
+ return 1;
+}
+
+int
+snd_pcm_format_little_endian (snd_pcm_format_t format)
+{
+ return 1;
+}
+
+/**
+ * \brief get size of #snd_pcm_format_mask_t
+ * \return size in bytes
+ */
+size_t
+snd_pcm_format_mask_sizeof ()
+{
+ return sizeof (snd_pcm_format_mask_t);
+}
+
+/**
+ * \brief test the presence of a format in a #snd_pcm_format_mask_t
+ * \param mask pointer to mask
+ * \param val format
+ */
+int
+snd_pcm_format_mask_test (const snd_pcm_format_mask_t * mask,
+ snd_pcm_format_t val)
+{
+ printf ("snd_pcm_format_mask_test()\n");
+ return 0;
+}
+
+/**
+ * \brief Return PCM handle related to an async handler
+ * \param handler Async handler handle
+ * \return PCM handle
+ */
+snd_pcm_t *
+snd_async_handler_get_pcm (snd_async_handler_t * handler)
+{
+ dbg_printf ("snd_async_handler_get_pcm()\n");
+ return NULL;
+}
+
+/**
+ * \brief Copy one or more areas
+ * \param dst_areas destination areas specification (one for each channel)
+ * \param dst_offset offset in frames inside destination area
+ * \param src_areas source areas specification (one for each channel)
+ * \param src_offset offset in frames inside source area
+ * \param channels channels count
+ * \param frames frames to copy
+ * \param format PCM sample format
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_pcm_areas_copy (const snd_pcm_channel_area_t * dst_areas,
+ snd_pcm_uframes_t dst_offset,
+ const snd_pcm_channel_area_t * src_areas,
+ snd_pcm_uframes_t src_offset, unsigned int channels,
+ snd_pcm_uframes_t frames, snd_pcm_format_t format)
+{
+ dbg_printf ("snd_pcm_areas_copy()\n");
+
+ return -EINVAL;
+}
+
+/**
+ * \brief Get format mask from a configuration space
+ * \param params Configuration space
+ * \param mask Returned Format mask
+ */
+void
+snd_pcm_hw_params_get_format_mask (snd_pcm_hw_params_t * params,
+ snd_pcm_format_mask_t * mask)
+{
+ printf ("snd_pcm_hw_params_get_format_mask()\n");
+}
+
+#if 1
+
+#ifdef USE_VERSIONED_SYMBOLS
+
+#define OBSOLETE1(name, what, new) \
+ symbol_version(__old_##name, name, what); \
+ default_symbol_version(__##name, name, new);
+
+#else
+
+#define OBSOLETE1(name, what, new) \
+ use_default_symbol_version(__##name, name, new);
+
+#endif /* USE_VERSIONED_SYMBOLS */
+
+#define __P_OLD_GET(pfx, name, val_type, ret_type) \
+ret_type pfx##name(const snd_pcm_hw_params_t *params) \
+{ \
+ val_type val; \
+ if (INTERNAL(name)(params, &val) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __P_OLD_GET1(pfx, name, val_type, ret_type) \
+ret_type pfx##name(const snd_pcm_hw_params_t *params, int *dir) \
+{ \
+ val_type val; \
+ if (INTERNAL(name)(params, &val, dir) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __OLD_GET(name, val_type, ret_type) __P_OLD_GET(__old_, name, val_type, ret_type)
+#define __OLD_GET1(name, val_type, ret_type) __P_OLD_GET1(__old_, name, val_type, ret_type)
+
+#define __P_OLD_NEAR(pfx, name, ret_type) \
+ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \
+{ \
+ if (INTERNAL(name)(pcm, params, &val) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __P_OLD_NEAR1(pfx, name, ret_type) \
+ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \
+{ \
+ if (INTERNAL(name)(pcm, params, &val, dir) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __OLD_NEAR(name, ret_type) __P_OLD_NEAR(__old_, name, ret_type)
+#define __OLD_NEAR1(name, ret_type) __P_OLD_NEAR1(__old_, name, ret_type)
+
+#define __P_OLD_SET_FL(pfx, name, ret_type) \
+ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \
+{ \
+ ret_type val; \
+ if (INTERNAL(name)(pcm, params, &val) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __P_OLD_SET_FL1(pfx, name, ret_type) \
+ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir) \
+{ \
+ ret_type val; \
+ if (INTERNAL(name)(pcm, params, &val, dir) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __OLD_SET_FL(name, ret_type) __P_OLD_SET_FL(__old_, name, ret_type)
+#define __OLD_SET_FL1(name, ret_type) __P_OLD_SET_FL1(__old_, name, ret_type)
+
+#define __P_OLD_GET_SW(pfx, name, ret_type) \
+ret_type pfx##name(snd_pcm_sw_params_t *params) \
+{ \
+ ret_type val; \
+ if (INTERNAL(name)(params, &val) < 0) \
+ return 0; \
+ return (ret_type)val; \
+}
+
+#define __OLD_GET_SW(name, ret_type) __P_OLD_GET_SW(__old_, name, ret_type)
+
+#endif /* DOC_HIDDEN */
+
+__OLD_NEAR1 (snd_pcm_hw_params_set_rate_near, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_set_rate_near, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_NEAR (snd_pcm_hw_params_set_channels_near, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_set_channels_near, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_period_size, snd_pcm_uframes_t,
+ snd_pcm_sframes_t);
+OBSOLETE1 (snd_pcm_hw_params_get_period_size, ALSA_0.9, ALSA_0.9.0rc4);
+
+
+__OLD_NEAR1 (snd_pcm_hw_params_set_buffer_time_near, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_set_buffer_time_near, ALSA_0.9,
+ ALSA_0.9.0rc4) __OLD_GET (snd_pcm_hw_params_get_buffer_size,
+ snd_pcm_uframes_t, snd_pcm_sframes_t);
+OBSOLETE1 (snd_pcm_hw_params_get_buffer_size, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_NEAR1 (snd_pcm_hw_params_set_period_time_near, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_set_period_time_near, ALSA_0.9,
+ ALSA_0.9.0rc4);
+
+__OLD_NEAR (snd_pcm_hw_params_set_buffer_size_near, snd_pcm_uframes_t);
+OBSOLETE1 (snd_pcm_hw_params_set_buffer_size_near, ALSA_0.9,
+ ALSA_0.9.0rc4);
+
+__OLD_NEAR1 (snd_pcm_hw_params_set_period_size_near, snd_pcm_uframes_t);
+OBSOLETE1 (snd_pcm_hw_params_set_period_size_near, ALSA_0.9,
+ ALSA_0.9.0rc4);
+
+__OLD_NEAR1 (snd_pcm_hw_params_set_periods_near, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_set_periods_near, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_period_time, unsigned int, int);
+OBSOLETE1 (snd_pcm_hw_params_get_period_time, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_buffer_time, unsigned int, int);
+OBSOLETE1 (snd_pcm_hw_params_get_buffer_time, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET_SW (snd_pcm_sw_params_get_xfer_align, snd_pcm_uframes_t);
+OBSOLETE1 (snd_pcm_sw_params_get_xfer_align, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_periods, unsigned int, int);
+OBSOLETE1 (snd_pcm_hw_params_get_periods, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET (snd_pcm_hw_params_get_access, snd_pcm_access_t, int);
+OBSOLETE1 (snd_pcm_hw_params_get_access, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_buffer_time_max, unsigned int,
+ unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_get_buffer_time_max, ALSA_0.9,
+ ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_tick_time, unsigned int, int);
+OBSOLETE1 (snd_pcm_hw_params_get_tick_time, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET (snd_pcm_hw_params_get_channels_max, unsigned int, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_get_channels_max, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET (snd_pcm_hw_params_get_channels_min, unsigned int, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_get_channels_min, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_rate_max, unsigned int, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_get_rate_max, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_rate_min, unsigned int, unsigned int);
+OBSOLETE1 (snd_pcm_hw_params_get_rate_min, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET (snd_pcm_hw_params_get_format, snd_pcm_format_t, int);
+OBSOLETE1 (snd_pcm_hw_params_get_format, ALSA_0.9, ALSA_0.9.0rc4);
+
+__OLD_GET1 (snd_pcm_hw_params_get_rate, unsigned int, int);
+OBSOLETE1 (snd_pcm_hw_params_get_rate, ALSA_0.9, ALSA_0.9.0rc4);
diff --git a/lib/libsalsa/rawmidi.c b/lib/libsalsa/rawmidi.c
new file mode 100644
index 0000000..4246357
--- /dev/null
+++ b/lib/libsalsa/rawmidi.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_open(%s)\n", name);
+
+ ALIB_INIT ();
+
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_close()\n");
+
+ return 0;
+}
+
+/**
+ * \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
+ */
+ssize_t
+snd_rawmidi_read (snd_rawmidi_t * rawmidi, void *buffer, size_t size)
+{
+ dbg_printf ("snd_rawmidi_read(%d)\n", size);
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_write(%d)\n", size);
+
+ return size;
+}
+
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_nonblock(%d)\n", nonblock);
+
+ return 0;
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_poll_descriptors_count()\n");
+
+ return 0;
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_poll_descriptors()\n");
+
+ return 0;
+}
+
+/**
+ * \brief get returned events from poll descriptors
+ * \param pcm 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)
+{
+ dbg_printf ("snd_rawmidi_poll_descriptors_revents()\n");
+
+ 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 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)
+{
+ dbg_printf ("snd_rawmidi_info_get_name()\n");
+
+ return "OSS rawmidi";
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_info_get_subdevices_count()\n");
+
+ return 1;
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_info_set_device(%d)\n", 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)
+{
+ dbg_printf ("snd_rawmidi_info_set_subdevice(%d)\n", 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)
+{
+ dbg_printf ("snd_rawmidi_info_set_stream(%d)\n", val);
+}
+
+/**
+ * \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)
+{
+ dbg_printf ("snd_rawmidi_info_get_subdevice_name()\n");
+
+ return "OSS rawmidi subdevice";
+}
diff --git a/lib/libsalsa/seq.c b/lib/libsalsa/seq.c
new file mode 100644
index 0000000..67f134b
--- /dev/null
+++ b/lib/libsalsa/seq.c
@@ -0,0 +1,2230 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+static int nports = 0;
+
+typedef struct _snd_seq_port_subscribe
+{
+ int dummy;
+} snd_seq_port_subscribe_t;
+
+typedef struct _snd_seq_queue_tempo
+{
+ int dummy;
+} snd_seq_queue_tempo_t;
+
+typedef struct _snd_seq_system_info
+{
+ int dummy;
+} snd_seq_system_info_t;
+
+struct _snd_seq_remove_events
+{
+ int dummy;
+};
+
+struct _snd_seq_query_subscribe
+{
+ int dummy;
+};
+
+/**
+ * \brief Open the ALSA sequencer
+ *
+ * \param seqp Pointer to a snd_seq_t pointer. This pointer must be
+ * kept and passed to most of the other sequencer functions.
+ * \param name The sequencer's "name". This is \em not a name you make
+ * up for your own purposes; it has special significance to the ALSA
+ * library. Usually you need to pass \c "default" here.
+ * \param streams The read/write mode of the sequencer. Can be one of
+ * three values:
+ * - #SND_SEQ_OPEN_OUTPUT - open the sequencer for output only
+ * - #SND_SEQ_OPEN_INPUT - open the sequencer for input only
+ * - #SND_SEQ_OPEN_DUPLEX - open the sequencer for output and input
+ * \note Internally, these are translated to \c O_WRONLY, \c O_RDONLY and
+ * \c O_RDWR respectively and used as the second argument to the C library
+ * open() call.
+ * \param mode Optional modifier. Can be either 0, or
+ * #SND_SEQ_NONBLOCK, which will make read/write operations
+ * non-blocking. This can also be set later using #snd_seq_nonblock().
+ * \return 0 on success otherwise a negative error code
+ *
+* Creates a new handle and opens a connection to the kernel
+ * sequencer interface.
+ * After a client is created successfully, an event
+ * with #SND_SEQ_EVENT_CLIENT_START is broadcast to announce port.
+ *
+ * \sa snd_seq_open_lconf(), snd_seq_close(), snd_seq_type(), snd_seq_name(),
+ * snd_seq_nonblock(), snd_seq_client_id()
+ */
+int
+snd_seq_open (snd_seq_t ** seqp, const char *name, int streams, int mode)
+{
+ snd_seq_t *seq;
+ int err, oss_mode;
+ static int instance = 0;
+
+ char *fname = "/dev/midi", *envname = NULL, tmp[128];
+
+ ALIB_INIT ();
+
+ dbg_printf ("snd_seq_open(name='%s', streams=%d, mode=%x)\n", name, streams,
+ mode);
+
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ instance++;
+
+ sprintf (tmp, "%s_mididev%d", alib_appname, instance);
+
+ if ((envname = getenv (tmp)) != NULL)
+ {
+ fname = envname;
+ }
+#if 0
+ if (streams != 1)
+ {
+ fprintf (stderr, "salsa: snd_seq_open doesn't support streams=%d\n",
+ streams);
+ return -EIO;
+ }
+#endif
+
+ if ((seq = malloc (sizeof (*seq))) == NULL)
+ return -ENOMEM;
+
+ dbg_printf ("Created sequencer seq=%x\n", seq);
+
+ memset (seq, 0, sizeof (*seq));
+
+ switch (streams)
+ {
+ case SND_SEQ_OPEN_INPUT:
+ oss_mode = O_RDONLY;
+ dbg_printf ("Open SND_SEQ_OPEN_INPUT\n");
+ break;
+ case SND_SEQ_OPEN_OUTPUT:
+ oss_mode = O_WRONLY;
+ dbg_printf ("Open SND_SEQ_OPEN_OUTPUT\n");
+ break;
+ case SND_SEQ_OPEN_DUPLEX:
+ dbg_printf ("SND_SEQ_OPEN_DUPLEX\n");
+ oss_mode = O_RDWR;
+ break;
+
+ default:
+ fprintf (stderr, "snd_seq_open: Unknown stream %x\n", streams);
+ return -ENODEV;
+ }
+
+ if ((seq->fd = open (fname, oss_mode, 0)) == -1)
+ {
+ err = errno;
+ perror (fname);
+
+ if (envname == NULL)
+ {
+ fprintf (stderr,
+ "You can select another filename using environment variable %s_mididev%d\n",
+ alib_appname, instance);
+ }
+ return -err;
+ }
+
+ seq->streams = streams;
+ seq->oss_mode = oss_mode;
+
+ if (streams == SND_SEQ_OPEN_INPUT || streams == SND_SEQ_OPEN_DUPLEX)
+ {
+ seq->parser = midiparser_create (midiparser_callback, seq);
+ if (seq->parser == NULL)
+ {
+ fprintf (stderr, "libsalsa: Can't create MIDI parser\n");
+ return -ENODEV;
+ }
+ }
+
+ *seqp = seq;
+ return 0;
+}
+
+/**
+ * \brief Close the sequencer
+ * \param handle Handle returned from #snd_seq_open()
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the sequencer client and releases its resources.
+ * After a client is closed, an event with
+ * #SND_SEQ_EVENT_CLIENT_EXIT is broadcast to announce port.
+ * The connection between other clients are disconnected.
+ * Call this just before exiting your program.
+ *
+ * \sa snd_seq_close()
+ */
+int
+snd_seq_close (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_close(seq=%x)\n", seq);
+
+ close (seq->fd);
+ free (seq);
+}
+
+/**
+ * \brief Set nonblock mode
+ * \param seq sequencer handle
+ * \param nonblock 0 = block, 1 = nonblock mode
+ * \return 0 on success otherwise a negative error code
+ *
+ * Change the blocking mode of the given client.
+ * In block mode, the client falls into sleep when it fills the
+ * output memory pool with full events. The client will be woken up
+ * after a certain amount of free space becomes available.
+ *
+ * \sa snd_seq_open()
+ */
+int
+snd_seq_nonblock (snd_seq_t * seq, int nonblock)
+{
+ dbg_printf ("snd_seq_nonblock(seq=%x, nonblock=%d)\n", seq, nonblock);
+
+ seq->nonblock = nonblock;
+ return 0;
+}
+
+/**
+ * \brief create a sequencer port on the current client
+ * \param seq sequencer handle
+ * \param port port information for the new port
+ * \return 0 on success otherwise a negative error code
+ *
+ * Creates a sequencer port on the current client.
+ * The attributes of created port is specified in \a info argument.
+ *
+ * The client field in \a info argument is overwritten with the current client id.
+ * The port id to be created can be specified via #snd_seq_port_info_set_port_specified.
+ * You can get the created port id by reading the port pointer via #snd_seq_port_info_get_port.
+ *
+ * Each port has the capability bit-masks to specify the access capability
+ * of the port from other clients.
+ * The capability bit flags are defined as follows:
+ * - #SND_SEQ_PORT_CAP_READ Readable from this port
+ * - #SND_SEQ_PORT_CAP_WRITE Writable to this port.
+ * - #SND_SEQ_PORT_CAP_SYNC_READ For synchronization (not implemented)
+ * - #SND_SEQ_PORT_CAP_SYNC_WRITE For synchronization (not implemented)
+ * - #SND_SEQ_PORT_CAP_DUPLEX Read/write duplex access is supported
+ * - #SND_SEQ_PORT_CAP_SUBS_READ Read subscription is allowed
+ * - #SND_SEQ_PORT_CAP_SUBS_WRITE Write subscription is allowed
+ * - #SND_SEQ_PORT_CAP_SUBS_NO_EXPORT Subscription management from 3rd client is disallowed
+ *
+ * Each port has also the type bitmasks defined as follows:
+ * - #SND_SEQ_PORT_TYPE_SPECIFIC Hardware specific port
+ * - #SND_SEQ_PORT_TYPE_MIDI_GENERIC Generic MIDI device
+ * - #SND_SEQ_PORT_TYPE_MIDI_GM General MIDI compatible device
+ * - #SND_SEQ_PORT_TYPE_MIDI_GS GS compatible device
+ * - #SND_SEQ_PORT_TYPE_MIDI_XG XG compatible device
+ * - #SND_SEQ_PORT_TYPE_MIDI_MT32 MT-32 compatible device
+ * - #SND_SEQ_PORT_TYPE_SYNTH Synth device
+ * - #SND_SEQ_PORT_TYPE_DIRECT_SAMPLE Sampling device (supporting download)
+ * - #SND_SEQ_PORT_TYPE_SAMPLE Sampling device (sample can be downloaded at any time)
+ * - #SND_SEQ_PORT_TYPE_APPLICATION Application (sequencer/editor)
+ *
+ * A port may contain specific midi channels, midi voices and synth voices.
+ * These values could be zero as default.
+ *
+ * \sa snd_seq_delete_port(), snd_seq_get_port_info(),
+ * snd_seq_create_simple_port()
+ */
+int
+snd_seq_create_port (snd_seq_t * seq, snd_seq_port_info_t * port)
+{
+ dbg_printf ("snd_seq_create_port(seq=%x, port=%x)\n", seq, port);
+
+ port->port = nports++;
+ return 0;
+}
+
+/**
+ * \brief Get the client id
+ * \param seq sequencer handle
+ * \return the client id
+ *
+ * Returns the id of the specified client.
+ * If an error occurs, function returns the negative error code.
+ * A client id is necessary to inquiry or to set the client information.
+ * A user client is assigned from 128 to 191.
+ *
+ * \sa snd_seq_open()
+ */
+int
+snd_seq_client_id (snd_seq_t * seq)
+{
+ static int client_id = 128;
+
+ dbg_printf ("snd_seq_client_id(seq=%x)=%d\n", seq, client_id);
+
+ return client_id++;
+}
+
+/**
+ * \brief Get client id of a client_info container
+ * \param info client_info container
+ * \return client id
+ *
+ * \sa snd_seq_get_client_info(), snd_seq_client_info_set_client(), snd_seq_client_id()
+ */
+int
+snd_seq_client_info_get_client (const snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_client_info_get_client()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get client type of a client_info container
+ * \param info client_info container
+ * \return client type
+ *
+ * The client type is either #SEQ_CLIENT_TYPE_KERNEL or #SEQ_CLIENT_TYPE_USER
+ * for kernel or user client respectively.
+ *
+ * \sa snd_seq_get_client_info()
+ */
+snd_seq_client_type_t
+snd_seq_client_info_get_type (const snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_client_info_get_type(infp=%x)\n", info);
+
+ return SND_SEQ_KERNEL_CLIENT; // TODO
+}
+
+/**
+ * \brief Set the client id of a client_info container
+ * \param info client_info container
+ * \param client client id
+ *
+ * \sa snd_seq_get_client_info(), snd_seq_client_info_get_client()
+ */
+void
+snd_seq_client_info_set_client (snd_seq_client_info_t * info, int client)
+{
+ dbg_printf ("snd_seq_client_info_set_client(%x, %d)\n", info, client);
+
+ info->client = client;
+}
+
+/**
+ * \brief get size of #snd_seq_client_info_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_client_info_sizeof ()
+{
+ dbg_printf ("snd_seq_client_info_sizeof()\n");
+
+ return sizeof (snd_seq_client_info_t);
+}
+
+/**
+ * \brief retrieve an event from sequencer
+ * \param seq sequencer handle
+ * \param ev event pointer to be stored
+ * \return
+ *
+ * Obtains an input event from sequencer.
+ * The event is created via snd_seq_create_event(), and its pointer is stored on * ev argument.
+ *
+ * This function firstly receives the event byte-stream data from sequencer
+ * as much as possible at once. Then it retrieves the first event record
+ * and store the pointer on ev.
+ * By calling this function sequentially, events are extracted from the input buffer.
+ *
+ * If there is no input from sequencer, function falls into sleep
+ * in blocking mode until an event is received,
+ * or returns \c -EAGAIN error in non-blocking mode.
+ * Occasionally, this function may return \c -ENOSPC error.
+ * This means that the input FIFO of sequencer overran, and some events are
+ * lost.
+ * Once this error is returned, the input FIFO is cleared automatically.
+ *
+ * Function returns the byte size of remaining events on the input buffer
+ * if an event is successfully received.
+ * Application can determine from the returned value whether to call
+ * input once more or not.
+ *
+ * \sa snd_seq_event_input_pending(), snd_seq_drop_input()
+ */
+int
+snd_seq_event_input (snd_seq_t * seq, snd_seq_event_t ** evp)
+{
+ static snd_seq_event_t *ev;
+ unsigned char buf[256];
+ int i, l;
+
+ dbg_printf2 ("snd_seq_event_input(seq=%x)\n", seq);
+
+ while (1)
+ {
+
+ if (seq->nextevent < seq->nevents)
+ {
+ *evp = &seq->events[seq->nextevent++];
+
+ return (seq->nevents - seq->nextevent) * sizeof (snd_seq_event_t);
+ }
+
+ seq->nextevent = seq->nevents = 0;
+ memset (seq->events, 0, sizeof (seq->events));
+
+ // TODO Handling of nonblocking mode
+ if ((l = read (seq->fd, buf, sizeof (buf))) == -1)
+ return -errno;
+
+ midiparser_input_buf (seq->parser, buf, l);
+
+ }
+
+}
+
+/**
+ * \brief output an event directly to the sequencer NOT through output buffer
+ * \param seq sequencer handle
+ * \param ev event to be output
+ * \return the byte size sent to sequencer or a negative error code
+ *
+ * This function sends an event to the sequencer directly not through the
+ * output buffer. When the event is a variable length event, a temporary
+ * buffer is allocated inside alsa-lib and the data is copied there before
+ * actually sent.
+ *
+ * \sa snd_seq_event_output()
+ */
+int
+snd_seq_event_output_direct (snd_seq_t * seq, snd_seq_event_t * ev)
+{
+ int err;
+
+ dbg_printf3 ("snd_seq_event_output_direct()\n");
+
+ if ((err = convert_event (seq, ev)) < 0)
+ return err;
+ if ((err = snd_seq_drain_output (seq)) < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * \brief (DEPRECATED) free an event
+ *
+ * In the former version, this function was used to
+ * release the event pointer which was allocated by snd_seq_event_input().
+ * In the current version, the event record is not allocated, so
+ * you don't have to call this function any more.
+ */
+int
+snd_seq_free_event (snd_seq_event_t * ev)
+{
+ return 0;
+}
+
+/**
+ * \brief obtain the current client information
+ * \param seq sequencer handle
+ * \param info the pointer to be stored
+ * \return 0 on success otherwise a negative error code
+ *
+ * Obtains the information of the current client stored on info.
+ * client and type fields are ignored.
+ *
+ * \sa snd_seq_get_any_client_info(), snd_seq_set_client_info(),
+ * snd_seq_query_next_client()
+ */
+int
+snd_seq_get_client_info (snd_seq_t * seq, snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_get_client_info(seq=%x, info=%x)\n", seq, info);
+
+ return 0;
+}
+
+/**
+ * \brief query the next matching port
+ * \param seq sequencer handle
+ * \param info query pattern and result
+
+ * Queries the next matching port on the client specified in
+ * \a info argument.
+ * The search begins at the next port specified in
+ * port field of \a info argument.
+ * For finding the first port at a certain client, give -1.
+ *
+ * If a matching port is found, its attributes are stored on
+ * \a info and function returns zero.
+ * Otherwise, a negative error code is returned.
+ *
+ * \sa snd_seq_get_port_info()
+ */
+int
+snd_seq_query_next_port (snd_seq_t * seq, snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_query_next_port()\n");
+
+ return -EINVAL;
+}
+
+/**
+ * \brief Set the name of a client_info container
+ * \param info client_info container
+ * \param name name string
+ *
+ * \sa snd_seq_get_client_info(), snd_seq_client_info_get_name(),
+ * snd_seq_set_client_name()
+ */
+void
+snd_seq_client_info_set_name (snd_seq_client_info_t * info, const char *name)
+{
+ dbg_printf ("snd_seq_client_info_set_name(%s)\n", name);
+
+ strncpy (info->name, name, sizeof (info->name) - 1);
+ info->name[sizeof (info->name) - 1] = 0;
+}
+
+/**
+ * \brief subscribe a port connection
+ * \param seq sequencer handle
+ * \param sub subscription information
+ * \return 0 on success otherwise a negative error code
+ *
+ * Subscribes a connection between two ports.
+ * The subscription information is stored in sub argument.
+ *
+ * \sa snd_seq_get_port_subscription(), snd_seq_unsubscribe_port(),
+ * snd_seq_connect_from(), snd_seq_connect_to()
+ */
+int
+snd_seq_subscribe_port (snd_seq_t * seq, snd_seq_port_subscribe_t * sub)
+{
+ dbg_printf ("snd_seq_subscribe_port()\n");
+
+ return -EINVAL;
+}
+
+/**
+ * \brief get size of #snd_seq_port_subscribe_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_port_subscribe_sizeof ()
+{
+ return sizeof (snd_seq_port_subscribe_t);
+}
+
+/**
+ * \brief Set sender address of a port_subscribe container
+ * \param info port_subscribe container
+ * \param addr sender address
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_sender()
+ */
+void
+snd_seq_port_subscribe_set_sender (snd_seq_port_subscribe_t * info,
+ const snd_seq_addr_t * addr)
+{
+ dbg_printf ("snd_seq_port_subscribe_set_sender()\n");
+}
+
+/**
+ * \brief Set destination address of a port_subscribe container
+ * \param info port_subscribe container
+ * \param addr destination address
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_dest()
+ */
+void
+snd_seq_port_subscribe_set_dest (snd_seq_port_subscribe_t * info,
+ const snd_seq_addr_t * addr)
+{
+ dbg_printf ("snd_seq_port_subscribe_set_dest()\n");
+}
+
+/**
+ * \brief Set the queue id of a port_subscribe container
+ * \param info port_subscribe container
+ * \param q queue id
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_queue()
+ */
+void
+snd_seq_port_subscribe_set_queue (snd_seq_port_subscribe_t * info, int q)
+{
+ dbg_printf ("snd_seq_port_subscribe_set_queue()\n");
+}
+
+/**
+ * \brief Set the real-time mode of a port_subscribe container
+ * \param info port_subscribe container
+ * \param val non-zero to enable
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_real()
+ */
+void
+snd_seq_port_subscribe_set_time_real (snd_seq_port_subscribe_t * info,
+ int val)
+{
+ dbg_printf ("snd_seq_port_subscribe_set_time_real()\n");
+}
+
+/**
+ * \brief Set the time-update mode of a port_subscribe container
+ * \param info port_subscribe container
+ * \param val non-zero to enable
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_update()
+ */
+void
+snd_seq_port_subscribe_set_time_update (snd_seq_port_subscribe_t * info, int
+ val)
+{
+ dbg_printf ("snd_seq_port_subscribe_set_time_update()\n");
+}
+
+/*
+ * Port
+ */
+
+/**
+ * \brief get size of #snd_seq_port_info_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_port_info_sizeof ()
+{
+ return sizeof (snd_seq_port_info_t);
+}
+
+/**
+ * \brief Get the capability bits of a port_info container
+ * \param info port_info container
+ * \return capability bits
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_capability()
+ */
+unsigned int
+snd_seq_port_info_get_capability (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_capability()\n");
+
+ return info->capability;
+}
+
+/**
+ * \brief Get client/port address of a port_info container
+ * \param info port_info container
+ * \return client/port address pointer
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_addr()
+ */
+const snd_seq_addr_t *
+snd_seq_port_info_get_addr (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_addr(info=%x)\n", info);
+
+ return NULL; // TODO
+}
+
+/**
+ * \brief set the capability bits of a port_info container
+ * \param info port_info container
+ * \param capability capability bits
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_capability()
+ */
+void
+snd_seq_port_info_set_capability (snd_seq_port_info_t * info,
+ unsigned int capability)
+{
+ dbg_printf ("snd_seq_port_info_set_capability()\n");
+}
+
+/**
+ * \brief Set the port-specified mode of a port_info container
+ * \param info port_info container
+ * \param val non-zero if specifying the port id at creation
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port_specified()
+ */
+void
+snd_seq_port_info_set_port_specified (snd_seq_port_info_t * info, int val)
+{
+ dbg_printf ("snd_seq_port_info_set_port_specified()\n");
+}
+
+/**
+ * \brief Get the midi channels of a port_info container
+ * \param info port_info container
+ * \return number of midi channels (default 0)
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_midi_channels()
+ */
+int
+snd_seq_port_info_get_midi_channels (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_midi_channels(info=%x)=%d\n",
+ info, info->midi_channels);
+
+ return info->midi_channels;
+}
+
+/**
+ * \brief set the midi channels of a port_info container
+ * \param info port_info container
+ * \param channels midi channels (default 0)
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_midi_channels()
+ */
+void
+snd_seq_port_info_set_midi_channels (snd_seq_port_info_t * info, int channels)
+{
+ dbg_printf ("snd_seq_port_info_set_midi_channels(info=%x, channels=%d)\n",
+ info, channels);
+ info->midi_channels = channels;
+}
+
+/**
+ * \brief Get the queue id to update timestamps
+ * \param info port_info container
+ * \return the queue id to get the timestamps
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_queue()
+ */
+int
+snd_seq_port_info_get_timestamp_queue (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_timestamp_queue(info=%x)\n", info);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Set the queue id for timestamping
+ * \param info port_info container
+ * \param queue the queue id to get timestamps
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_queue()
+ */
+void
+snd_seq_port_info_set_timestamp_queue (snd_seq_port_info_t * info, int queue)
+{
+ dbg_printf ("snd_seq_port_info_set_timestamp_queue(info=%x, queue=%d)\n",
+ info, queue);
+
+ // TODO
+}
+
+/**
+ * \brief Get whether the time-stamping of the given port is real-time mode
+ * \param info port_info container
+ * \return 1 if the time-stamping is in the real-time mode
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_real()
+ */
+int
+snd_seq_port_info_get_timestamp_real (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_timestamp_real(info=%x)\n", info);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Set whether the timestime is updated in the real-time mode
+ * \param info port_info container
+ * \param enable non-zero if updating the timestamps in real-time mode
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_real()
+ */
+void
+snd_seq_port_info_set_timestamp_real (snd_seq_port_info_t * info, int enable)
+{
+ dbg_printf ("snd_seq_port_info_set_timestamp_real(infp=%x, enable=%d)\n",
+ info, enable);
+}
+
+/**
+ * \brief Get the time-stamping mode of the given port in a port_info container * \param info port_info container
+ * \return 1 if the port updates timestamps of incoming events
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamping()
+ */
+int
+snd_seq_port_info_get_timestamping (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_timestamping(info=%x)\n", info);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Set the time-stamping mode of the given port
+ * \param info port_info container
+ * \param enable non-zero if updating the timestamps of incoming events
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamping()
+ */
+void
+snd_seq_port_info_set_timestamping (snd_seq_port_info_t * info, int enable)
+{
+ dbg_printf ("snd_seq_port_info_set_timestamping(info=%x, enable=%d)\n",
+ info, enable);
+
+ // TODO
+}
+
+/**
+ * \brief Set the name of a port_info container
+ * \param info port_info container
+ * \param name name string
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_name()
+ */
+void
+snd_seq_port_info_set_name (snd_seq_port_info_t * info, const char *name)
+{
+ dbg_printf ("snd_seq_port_info_set_name()\n");
+
+ strncpy (info->name, name, sizeof (info->name));
+}
+
+/**
+ * \brief Get the name of a port_info container
+ * \param info port_info container
+ * \return name string
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_name()
+ */
+const char *
+snd_seq_port_info_get_name (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_name()\n");
+
+ return "Port Name";
+}
+
+/**
+ * \brief Get port id of a port_info container
+ * \param info port_info container
+ * \return port id
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port()
+ */
+int
+snd_seq_port_info_get_port (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_port()\n");
+
+ return -EIO;
+}
+
+/**
+ * \brief Get the type bits of a port_info container
+ * \param info port_info container
+ * \return port type bits
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_type()
+ */
+unsigned int
+snd_seq_port_info_get_type (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_type()\n");
+
+ return info->type;
+}
+
+/**
+ * \brief Set the client id of a port_info container
+ * \param info port_info container
+ * \param client client id
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_client()
+ */
+void
+snd_seq_port_info_set_client (snd_seq_port_info_t * info, int client)
+{
+ dbg_printf ("snd_seq_port_info_set_client()\n");
+}
+
+/**
+ * \brief Set the port id of a port_info container
+ * \param info port_info container
+ * \param port port id
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port()
+ */
+void
+snd_seq_port_info_set_port (snd_seq_port_info_t * info, int port)
+{
+ dbg_printf ("snd_seq_port_info_set_port()\n");
+}
+
+/**
+ * \brief query the next matching client
+ * \param seq sequencer handle
+ * \param info query pattern and result
+ *
+ * Queries the next matching client with the given condition in
+ * info argument.
+ * The search begins at the client with an id one greater than
+ * client field in info.
+ * If name field in info is not empty, the client name is compared.
+ * If a matching client is found, its attributes are stored o
+ * info and returns zero.
+ * Otherwise returns a negative error code.
+ *
+ * \sa snd_seq_get_any_client_info()
+ */
+int
+snd_seq_query_next_client (snd_seq_t * seq, snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_query_next_client()\n");
+
+ return -EIO;
+}
+
+/**
+ * \brief set the current client information
+ * \param seq sequencer handle
+ * \param info the client info data to set
+ * \return 0 on success otherwise a negative error code
+ *
+ * Obtains the information of the current client stored on info.
+ * client and type fields are ignored.
+ *
+ * \sa snd_seq_get_client_info()
+ */
+int
+snd_seq_set_client_info (snd_seq_t * seq, snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_set_client_info(seq=%x, info=%x)\n", seq, info);
+
+ if (*info->name)
+ {
+ strcpy (seq->name, info->name);
+ ioctl (seq->fd, SNDCTL_SETNAME, seq->name);
+ ioctl (seq->fd, SNDCTL_SETSONG, seq->name);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief check events in input buffer
+ * \return the byte size of remaining input events on input buffer.
+ *
+ * If events remain on the input buffer of user-space, function returns
+ * the total byte size of events on it.
+ * If fetch_sequencer argument is non-zero,
+ * this function checks the presence of events on sequencer FIFO
+ * When events exist, they are transferred to the input buffer,
+ * and the number of received events are returned.
+ * If fetch_sequencer argument is zero and
+ * no events remain on the input buffer, function simply returns zero.
+ *
+ * \sa snd_seq_event_input()
+ */
+int
+snd_seq_event_input_pending (snd_seq_t * seq, int fetch_sequencer)
+{
+ dbg_printf ("snd_seq_event_input_pending()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get poll descriptors
+ * \param seq sequencer handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \param events polling events to be checked (\c POLLIN and \c POLLOUT)
+ * \return count of filled descriptors
+ *
+ * Get poll descriptors assigned to the sequencer handle.
+ * Since a sequencer handle can duplex streams, you need to set which direction(s)
+ * is/are polled in \a events argument. When \c POLLIN bit is specified,
+ * the incoming events to the ports are checked.
+ *
+ * To check the returned poll-events, call #snd_seq_poll_descriptors_revents()
+ * instead of reading the pollfd structs directly.
+ *
+ * \sa snd_seq_poll_descriptors_count(), snd_seq_poll_descriptors_revents()
+ */
+int
+snd_seq_poll_descriptors (snd_seq_t * seq, struct pollfd *pfds,
+ unsigned int space, short events)
+{
+ dbg_printf ("snd_seq_poll_descriptors(seq=%x)\n", seq);
+
+ pfds->fd = seq->fd;
+ pfds->events = 0;
+ pfds->revents = 0;
+
+ if (seq->oss_mode == O_WRONLY || seq->oss_mode == O_RDWR)
+ pfds->events = POLLOUT;
+ if (seq->oss_mode == O_RDONLY || seq->oss_mode == O_RDWR)
+ pfds->events = POLLIN;
+
+ return 1;
+}
+
+
+/**
+ * \brief Returns the number of poll descriptors
+ * \param seq sequencer handle
+ * \param events the poll events to be checked (\c POLLIN and \c POLLOUT)
+ * \return the number of poll descriptors.
+ *
+ * Get the number of poll descriptors. The polling events to be checked
+ * can be specified by the second argument. When both input and output
+ * are checked, pass \c POLLIN|POLLOUT
+ *
+ * \sa snd_seq_poll_descriptors()
+ */
+int
+snd_seq_poll_descriptors_count (snd_seq_t * seq, short events)
+{
+ dbg_printf ("snd_seq_poll_descriptors_count(seq=%x, events=%x)\n",
+ seq, events);
+ return 1;
+}
+
+/**
+ * \brief create a queue
+ * \param seq sequencer handle
+ * \param info queue information to initialize
+ * \return the queue id (zero or positive) on success otherwise a negative error code
+ *
+ * \sa snd_seq_alloc_queue()
+ */
+int
+snd_seq_create_queue (snd_seq_t * seq, snd_seq_queue_info_t * info)
+{
+ dbg_printf ("snd_seq_create_queue()\n");
+
+ return 0;
+}
+
+/**
+ * \brief simple subscription (w/o exclusive & time conversion)
+ * \param myport the port id as sender
+ * \param dest_client destination client id
+ * \param dest_port destination port id
+ * \return 0 on success or negative error code
+ *
+ * Connect from the given receiver port in the current client
+ * to the given destination client:port.
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_disconnect_to()
+ */
+int
+snd_seq_connect_to (snd_seq_t * seq, int myport, int dest_client,
+ int dest_port)
+{
+ dbg_printf ("snd_seq_connect_to(%d->%d/%d)\n", myport, dest_client,
+ dest_port);
+
+ return 0;
+}
+
+/**
+ * \brief simple subscription (w/o exclusive & time conversion)
+ * \param myport the port id as receiver
+ * \param src_client sender client id
+ * \param src_port sender port id
+ * \return 0 on success or negative error code
+ *
+ * Connect from the given sender client:port to the given destination port in the
+ * current client.
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from()
+ */
+int
+snd_seq_connect_from (snd_seq_t * seq, int myport, int src_client,
+ int src_port)
+{
+ dbg_printf
+ ("snd_seq_connect_from(seq=%x, myport=%d, src_client=%d, src_port=%d)\n",
+ seq, myport, src_client, src_port);
+
+ return 0;
+}
+
+/**
+ * \brief queue controls - start/stop/continue
+ * \param seq sequencer handle
+ * \param q queue id to control
+ * \param type event type
+ * \param value event value
+ * \param ev event instance
+ *
+ * This function sets up general queue control event and sends it.
+ * To send at scheduled time, set the schedule in \a ev.
+ * If \a ev is NULL, the event is composed locally and sent immediately
+ * to the specified queue. In any cases, you need to call #snd_seq_drain_output()
+ * appropriately to feed the event.
+ *
+ * \sa snd_seq_alloc_queue()
+ */
+int
+snd_seq_control_queue (snd_seq_t * seq, int q, int type, int value,
+ snd_seq_event_t * ev)
+{
+ dbg_printf ("snd_seq_control_queue()\n");
+
+ return 0;
+}
+
+/**
+ * \brief drain output buffer to sequencer
+ * \param seq sequencer handle
+ * \return 0 when all events are drained and sent to sequencer.
+ * When events still remain on the buffer, the byte size of remaining
+ * events are returned. On error a negative error code is returned.
+ *
+ * This function drains all pending events on the output buffer.
+ * The function returns immediately after the events are sent to the queues
+ * regardless whether the events are processed or not.
+ * To get synchronization with the all event processes, use
+ * #snd_seq_sync_output_queue() after calling this function.
+ *
+ * \sa snd_seq_event_output(), snd_seq_sync_output_queue()
+ */
+int
+snd_seq_drain_output (snd_seq_t * seq)
+{
+ dbg_printf3 ("snd_seq_drain_output(seq=%x)\n", seq);
+
+ return 0;
+}
+
+
+/**
+ * \brief remove all events on output buffer
+ * \param seq sequencer handle
+ *
+ * Removes all events on both user-space output buffer and
+ * output memory pool on kernel.
+ *
+ * \sa snd_seq_drain_output(), snd_seq_drop_output_buffer(), snd_seq_remove_events()
+ */
+int
+snd_seq_drop_output (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_drop_output()\n");
+
+ return 0;
+}
+
+/**
+ * \brief output an event
+ * \param seq sequencer handle
+ * \param ev event to be output
+ * \return the number of remaining events or a negative error code
+ *
+ * An event is once expanded on the output buffer.
+ * The output buffer will be drained automatically if it becomes full.
+ *
+ * If events remain unprocessed on output buffer before drained,
+ * the size of total byte data on output buffer is returned.
+ * If the output buffer is empty, this returns zero.
+ *
+ * \sa snd_seq_event_output_direct(), snd_seq_event_output_buffer(),
+ * snd_seq_event_output_pending(), snd_seq_drain_output(),
+ * snd_seq_drop_output(), snd_seq_extract_output(),
+ * snd_seq_remove_events()
+ */
+int
+snd_seq_event_output (snd_seq_t * seq, snd_seq_event_t * ev)
+{
+ dbg_printf3 ("snd_seq_event_output(seq=%x, ev=%x)\n", seq, ev);
+
+ return convert_event (seq, ev);
+}
+
+/**
+ * \brief delete the specified queue
+ * \param seq sequencer handle
+ * \param q queue id to delete
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_alloc_queue()
+ */
+int
+snd_seq_free_queue (snd_seq_t * seq, int q)
+{
+ dbg_printf ("snd_seq_free_queue()\n");
+
+ return 0;
+}
+
+/**
+ * \brief obtain the information of the given client
+ * \param seq sequencer handle
+ * \param client client id
+ * \param info the pointer to be stored
+ * \return 0 on success otherwise a negative error code
+ *
+ * Obtains the information of the client with a client id specified by
+ * info argument.
+ * The obtained information is written on info parameter.
+ *
+ * \sa snd_seq_get_client_info()
+ */
+int
+snd_seq_get_any_client_info (snd_seq_t * seq, int client,
+ snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_get_any_client_info()\n");
+
+ strcpy (info->name, seq->name);
+
+ return 0;
+}
+
+/**
+ * \brief obtain the information of a port on an arbitrary client
+ * \param seq sequencer handle
+ * \param client client id to get
+ * \param port port id to get
+ * \param info pointer information returns
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_get_port_info()
+ */
+int
+snd_seq_get_any_port_info (snd_seq_t * seq, int client, int port,
+ snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_get_any_port_info()\n");
+
+ return 0;
+}
+
+/**
+ * \brief allocate an empty #snd_seq_port_info_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_port_info_malloc (snd_seq_port_info_t ** ptr)
+{
+ snd_seq_port_info_t *p;
+
+ dbg_printf ("snd_seq_port_info_malloc()\n");
+
+ if ((p = malloc (sizeof (*p))) == NULL)
+ return -ENOMEM;
+
+ *ptr = p;
+
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_port_info_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_port_info_free (snd_seq_port_info_t * obj)
+{
+ free (obj);
+}
+
+/**
+ * \brief allocate an empty #snd_seq_queue_tempo_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_queue_tempo_malloc (snd_seq_queue_tempo_t ** ptr)
+{
+ assert (ptr);
+ *ptr = calloc (1, sizeof (snd_seq_queue_tempo_t));
+ dbg_printf ("snd_seq_queue_tempo_malloc()=%x\n", *ptr);
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_queue_tempo_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_queue_tempo_free (snd_seq_queue_tempo_t * obj)
+{
+ dbg_printf ("snd_seq_queue_tempo_free(%x)\n", obj);
+ free (obj);
+}
+
+/**
+ * \brief Set the ppq of a queue_status container
+ * \param info queue_status container
+ * \param ppq ppq value
+ *
+ * \sa snd_seq_get_queue_tempo()
+ */
+void
+snd_seq_queue_tempo_set_ppq (snd_seq_queue_tempo_t * info, int ppq)
+{
+ dbg_printf ("snd_seq_queue_tempo_set_ppq(info=%x, %d)\n", info, ppq);
+}
+
+/**
+ * \brief Set the tempo of a queue_status container
+ * \param info queue_status container
+ * \param tempo tempo value
+ *
+ * \sa snd_seq_get_queue_tempo()
+ */
+void
+snd_seq_queue_tempo_set_tempo (snd_seq_queue_tempo_t * info,
+ unsigned int tempo)
+{
+ dbg_printf ("snd_seq_queue_tempo_set_tempo(info=%x, %d)\n", info, tempo);
+}
+
+/**
+ * \brief get size of #snd_seq_queue_tempo_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_queue_tempo_sizeof ()
+{
+ return sizeof (snd_seq_queue_tempo_t);
+}
+
+/**
+ * \brief set the queue timer information
+ * \param seq sequencer handle
+ * \param q queue id to change the timer
+ * \param timer timer information
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_get_queue_timer()
+ */
+int
+snd_seq_set_queue_timer (snd_seq_t * seq, int q,
+ snd_seq_queue_timer_t * timer)
+{
+ dbg_printf ("snd_seq_get_queue_timer(seq=%x, q=%d, timer=%X)\n", seq, q,
+ timer);
+ return -ENXIO; // TODO
+}
+
+
+/**
+ * \brief Opens a new connection to the timer query interface.
+ * \param timer Returned 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_timer_query_open (snd_timer_query_t ** timer, const char *name, int mode)
+{
+ dbg_printf ("snd_timer_query_open(name=%s, mode=%x)\n", name, mode);
+ return -ENXIO; // TODO
+}
+
+/**
+ * \brief obtain the current tempo of the queue
+ * \param seq sequencer handle
+ * \param q queue id to be queried
+ * \param tempo pointer to store the current tempo
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_set_queue_tempo()
+ */
+int
+snd_seq_get_queue_tempo (snd_seq_t * seq, int q,
+ snd_seq_queue_tempo_t * tempo)
+{
+ dbg_printf ("snd_seq_get_queue_tempo(seq=%x, q=%d, tempo=%x)\n", seq, q,
+ tempo);
+
+ return 0;
+}
+
+/**
+ * \brief allocate an empty #snd_seq_client_info_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_client_info_malloc (snd_seq_client_info_t ** ptr)
+{
+ dbg_printf ("snd_seq_client_info_malloc()\n");
+
+ *ptr = malloc (sizeof (snd_seq_client_info_t));
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_client_info_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_client_info_free (snd_seq_client_info_t * obj)
+{
+ dbg_printf ("snd_seq_client_info_free()\n");
+
+ free (obj);
+}
+
+/**
+ * \brief Get the name of a client_info container
+ * \param info client_info container
+ * \return name string
+ *
+ * \sa snd_seq_get_client_info(), snd_seq_client_info_set_name()
+ */
+const char *
+snd_seq_client_info_get_name (snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_client_info_get_name()\n");
+ return "OSS seq client";
+}
+
+/**
+ * \brief Get the number of opened ports of a client_info container
+ * \param info client_info container
+ * \return number of opened ports
+ *
+ * \sa snd_seq_get_client_info()
+ */
+int
+snd_seq_client_info_get_num_ports (const snd_seq_client_info_t * info)
+{
+ dbg_printf ("snd_seq_client_info_get_num_ports()\n");
+
+ return 1;
+}
+
+/**
+ * \brief Get size of #snd_seq_system_info_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_system_info_sizeof ()
+{
+ return sizeof (snd_seq_system_info_t);
+}
+
+
+/**
+ * \brief Allocate an empty #snd_seq_system_info_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_system_info_malloc (snd_seq_system_info_t ** ptr)
+{
+ dbg_printf ("snd_seq_system_info_malloc()\n");
+
+ *ptr = malloc (sizeof (snd_seq_system_info_t));
+ if (*ptr == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief Frees a previously allocated #snd_seq_system_info_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_system_info_free (snd_seq_system_info_t * obj)
+{
+ free (obj);
+}
+
+/**
+ * \brief obtain the sequencer system information
+ * \param seq sequencer handle
+ * \param info the pointer to be stored
+ * \return 0 on success otherwise a negative error code
+ *
+ * Stores the global system information of ALSA sequencer system.
+ * The returned data contains
+ * the maximum available numbers of queues, clients, ports and channels.
+ */
+int
+snd_seq_system_info (snd_seq_t * seq, snd_seq_system_info_t * info)
+{
+ dbg_printf ("snd_seq_system_info()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get maximum number of clients
+ * \param info #snd_seq_system_info_t container
+ * \return maximum number of clients
+ *
+ * \sa snd_seq_system_info()
+ */
+int
+snd_seq_system_info_get_clients (const snd_seq_system_info_t * info)
+{
+ dbg_printf ("snd_seq_system_info_get_clients()\n");
+
+ return 4;
+}
+
+/**
+ * \brief Get maximum number of queues
+ * \param info #snd_seq_system_info_t container
+ * \return maximum number of queues
+ *
+ * \sa snd_seq_system_info()
+ */
+int
+snd_seq_system_info_get_queues (const snd_seq_system_info_t * info)
+{
+ dbg_printf ("snd_seq_system_info_get_queues(info=%x)\n", info);
+
+ return 1; // TODO
+}
+
+/**
+ * \brief Get maximum number of ports
+ * \param info #snd_seq_system_info_t container
+ * \return maximum number of ports
+ *
+ * \sa snd_seq_system_info()
+ */
+int
+snd_seq_system_info_get_ports (const snd_seq_system_info_t * info)
+{
+ dbg_printf ("snd_seq_system_info_get_ports()\n");
+
+ return 4;
+}
+
+/**
+ * \brief allocate a queue with the specified name
+ * \param seq sequencer handle
+ * \param name the name of the new queue
+ * \return the queue id (zero or positive) on success otherwise a negative error code
+ *
+ * \sa snd_seq_alloc_queue()
+ */
+int
+snd_seq_alloc_named_queue (snd_seq_t * seq, const char *name)
+{
+ dbg_printf ("snd_seq_alloc_named_queue(seq=%x, name=%s)\n", seq, name);
+
+ return 0;
+}
+
+
+/**
+ * \brief Get client id of a port_info container
+ * \param info port_info container
+ * \return client id
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_client()
+ */
+int
+snd_seq_port_info_get_client (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_client()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get the port-specified mode of a port_info container
+ * \param info port_info container
+ * \return 1 if port id is specified at creation
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port_specified()
+ */
+int
+snd_seq_port_info_get_port_specified (const snd_seq_port_info_t * info)
+{
+ dbg_printf ("snd_seq_port_info_get_port_specified()\n");
+
+ return 0;
+}
+
+/**
+ * \brief Get the type bits of a port_info container
+ * \param info port_info container
+ * \return port type bits
+ *
+ * \sa snd_seq_get_port_info(), snd_seq_port_info_get_type()
+ */
+void
+snd_seq_port_info_set_type (snd_seq_port_info_t * info, unsigned int type)
+{
+ dbg_printf ("snd_seq_port_info_set_type(%u)\n", type);
+}
+
+
+/**
+ * \brief Get the ppq of a queue_status container
+ * \param info queue_status container
+ * \return ppq value
+ *
+ * \sa snd_seq_get_queue_tempo()
+ */
+int
+snd_seq_queue_tempo_get_ppq (const snd_seq_queue_tempo_t * info)
+{
+ dbg_printf ("snd_seq_queue_tempo_get_ppq()\n");
+
+ return 0;
+}
+
+
+/**
+ * \brief Get the tempo of a queue_status container
+ * \param info queue_status container
+ * \return tempo value
+ *
+ * \sa snd_seq_get_queue_tempo()
+ */
+unsigned int
+snd_seq_queue_tempo_get_tempo (const snd_seq_queue_tempo_t * info)
+{
+ dbg_printf ("snd_seq_queue_tempo_get_tempo()\n");
+
+ return 0;
+}
+
+/**
+ * \brief set the tempo of the queue
+ * \param seq sequencer handle
+ * \param q queue id to change the tempo
+ * \param tempo tempo information
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_get_queue_tempo()
+ */
+int
+snd_seq_set_queue_tempo (snd_seq_t * seq, int q,
+ snd_seq_queue_tempo_t * tempo)
+{
+ dbg_printf ("snd_seq_set_queue_tempo(seq=%x, q=%d, tempo=%x)\n", seq, q,
+ tempo);
+
+ return 0;
+}
+
+/**
+ * \brief allocate a queue
+ * \param seq sequencer handle
+ * \return the queue id (zero or positive) on success otherwise a negative error code
+ *
+ * \sa snd_seq_alloc_named_queue(), snd_seq_create_queue(), snd_seq_free_queue(),
+ * snd_seq_get_queue_info()
+ */
+int
+snd_seq_alloc_queue (snd_seq_t * seq)
+{
+ static int queue_num = 0;
+ dbg_printf ("snd_seq_alloc_queue(seq=%x)=%d\n", seq, queue_num);
+
+ return queue_num++;
+}
+
+#define FIXED_EV(x) (_SND_SEQ_TYPE(SND_SEQ_EVFLG_FIXED) | _SND_SEQ_TYPE(x))
+
+/** Event types conversion array */
+const unsigned int snd_seq_event_types[256] = {
+ [SND_SEQ_EVENT_SYSTEM...SND_SEQ_EVENT_RESULT]
+ = FIXED_EV (SND_SEQ_EVFLG_RESULT),
+ [SND_SEQ_EVENT_NOTE]
+ =
+ FIXED_EV (SND_SEQ_EVFLG_NOTE) |
+ _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_NOTE_TWOARG),
+ [SND_SEQ_EVENT_NOTEON...SND_SEQ_EVENT_KEYPRESS] =
+ FIXED_EV (SND_SEQ_EVFLG_NOTE),
+ [SND_SEQ_EVENT_CONTROLLER...SND_SEQ_EVENT_REGPARAM] =
+ FIXED_EV (SND_SEQ_EVFLG_CONTROL),
+ [SND_SEQ_EVENT_START...SND_SEQ_EVENT_STOP] = FIXED_EV (SND_SEQ_EVFLG_QUEUE),
+ [SND_SEQ_EVENT_SETPOS_TICK]
+ =
+ FIXED_EV (SND_SEQ_EVFLG_QUEUE) |
+ _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_TICK),
+ [SND_SEQ_EVENT_SETPOS_TIME] =
+ FIXED_EV (SND_SEQ_EVFLG_QUEUE) |
+ _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_TIME),
+ [SND_SEQ_EVENT_TEMPO...SND_SEQ_EVENT_SYNC_POS] =
+ FIXED_EV (SND_SEQ_EVFLG_QUEUE) |
+ _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_VALUE),
+ [SND_SEQ_EVENT_TUNE_REQUEST...SND_SEQ_EVENT_SENSING] =
+ FIXED_EV (SND_SEQ_EVFLG_NONE),
+ [SND_SEQ_EVENT_ECHO...SND_SEQ_EVENT_OSS] =
+ FIXED_EV (SND_SEQ_EVFLG_RAW) | FIXED_EV (SND_SEQ_EVFLG_SYSTEM),
+ [SND_SEQ_EVENT_CLIENT_START...SND_SEQ_EVENT_PORT_CHANGE] =
+ FIXED_EV (SND_SEQ_EVFLG_MESSAGE),
+ [SND_SEQ_EVENT_PORT_SUBSCRIBED...SND_SEQ_EVENT_PORT_UNSUBSCRIBED] =
+ FIXED_EV (SND_SEQ_EVFLG_CONNECTION),
+ [SND_SEQ_EVENT_USR0...SND_SEQ_EVENT_USR9] =
+ FIXED_EV (SND_SEQ_EVFLG_RAW) | FIXED_EV (SND_SEQ_EVFLG_USERS),
+ [SND_SEQ_EVENT_SYSEX...SND_SEQ_EVENT_BOUNCE] =
+ _SND_SEQ_TYPE (SND_SEQ_EVFLG_VARIABLE),
+ [SND_SEQ_EVENT_USR_VAR0...SND_SEQ_EVENT_USR_VAR4] =
+ _SND_SEQ_TYPE (SND_SEQ_EVFLG_VARIABLE) |
+ _SND_SEQ_TYPE (SND_SEQ_EVFLG_USERS),
+ [SND_SEQ_EVENT_NONE] = FIXED_EV (SND_SEQ_EVFLG_NONE),
+};
+
+/**
+ * \brief obtain the running state of the queue
+ * \param seq sequencer handle
+ * \param q queue id to query
+ * \param status pointer to store the current status
+ * \return 0 on success otherwise a negative error code
+ *
+ * Obtains the running state of the specified queue q.
+ */
+int
+snd_seq_get_queue_status (snd_seq_t * seq, int q,
+ snd_seq_queue_status_t * status)
+{
+ dbg_printf ("snd_seq_get_queue_status(seq=%x. q=%d)\n", seq, q);
+
+ return 0;
+}
+
+/**
+ * \brief allocate an empty #snd_seq_queue_status_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_queue_status_malloc (snd_seq_queue_status_t ** ptr)
+{
+ dbg_printf ("snd_seq_queue_status_malloc()\n");
+ *ptr = calloc (1, sizeof (snd_seq_queue_status_t));
+ dbg_printf ("snd_seq_queue_status_malloc()=%x\n", *ptr);
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_queue_status_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_queue_status_free (snd_seq_queue_status_t * obj)
+{
+ dbg_printf ("snd_seq_queue_status_free(%x)\n", obj);
+
+ free (obj);
+}
+
+/**
+ * \brief Get the tick time of a queue_status container
+ * \param info queue_status container
+ * \return tick time
+ *
+ * \sa snd_seq_get_queue_status()
+ */
+snd_seq_tick_time_t
+snd_seq_queue_status_get_tick_time (const snd_seq_queue_status_t * info)
+{
+ dbg_printf ("snd_seq_queue_status_get_tick_time(info=%x)\n", info);
+
+ return 0;
+}
+
+/**
+ * \brief get size of #snd_seq_remove_events_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_remove_events_sizeof ()
+{
+ return sizeof (snd_seq_remove_events_t);
+}
+
+/**
+ * \brief allocate an empty #snd_seq_remove_events_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_remove_events_malloc (snd_seq_remove_events_t ** ptr)
+{
+ assert (ptr);
+ *ptr = calloc (1, sizeof (snd_seq_remove_events_t));
+ dbg_printf ("snd_seq_remove_events_malloc()=%x\n", *ptr);
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_remove_events_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_remove_events_free (snd_seq_remove_events_t * obj)
+{
+ free (obj);
+}
+
+/**
+ * \brief Set the removal condition bits
+ * \param info remove_events container
+ * \param flags removal condition bits
+ *
+ * \sa snd_seq_remove_events()
+ */
+void
+snd_seq_remove_events_set_condition (snd_seq_remove_events_t * info,
+ unsigned int flags)
+{
+ dbg_printf ("snd_seq_remove_events_set_condition(rmp=%x, flags=%lu)\n",
+ info, flags);
+}
+
+/**
+ * \brief Set the queue as removal condition
+ * \param info remove_events container
+ * \param queue queue id
+ *
+ * \sa snd_seq_remove_events()
+ */
+void
+snd_seq_remove_events_set_queue (snd_seq_remove_events_t * info, int queue)
+{
+ dbg_printf ("snd_seq_remove_events_set_queue(rmp=%x, q=%d)\n", info, queue);
+}
+
+/**
+ * \brief remove events on input/output buffers and pools
+ * \param seq sequencer handle
+ * \param rmp remove event container
+ *
+ * Removes matching events with the given condition from input/output buffers
+ * and pools.
+ * The removal condition is specified in \a rmp argument.
+ *
+ * \sa snd_seq_event_output(), snd_seq_drop_output(), snd_seq_reset_pool_output()
+ */
+int
+snd_seq_remove_events (snd_seq_t * seq, snd_seq_remove_events_t * rmp)
+{
+ dbg_printf ("snd_seq_remove_events(seq=%x, rmp=%x)\n", seq, rmp);
+
+ return 1;
+}
+
+
+/**
+ * \brief clear input buffer and and remove events in sequencer queue
+ * \param seq sequencer handle
+ *
+ * \sa snd_seq_drop_input_buffer(), snd_seq_remove_events()
+ */
+int
+snd_seq_drop_input (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_drop_input(seq=%x)\n", seq);
+
+ return 0;
+}
+
+/**
+ * \brief remove all events on user-space output buffer
+ * \param seq sequencer handle
+ *
+ * Removes all events on user-space output buffer.
+ * Unlike snd_seq_drain_output(), this function doesn't remove
+ * events on output memory pool of sequencer.
+ *
+ * \sa snd_seq_drop_output()
+ */
+int
+snd_seq_drop_output_buffer (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_drop_output_buffer(seq=%x)\n", seq);
+
+ return 0;
+}
+
+/**
+ * \brief extract the first event in output buffer
+ * \param seq sequencer handle
+ * \param ev_res event pointer to be extracted
+ * \return 0 on success otherwise a negative error code
+ *
+ * Extracts the first event in output buffer.
+ * If ev_res is NULL, just remove the event.
+ *
+ * \sa snd_seq_event_output()
+ */
+int
+snd_seq_extract_output (snd_seq_t * seq, snd_seq_event_t ** ev_res)
+{
+ dbg_printf ("snd_seq_extract_output(seq=%x)\n", seq);
+
+ return -EIO;
+}
+
+/**
+ * \brief get size of #snd_seq_queue_status_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_queue_status_sizeof ()
+{
+ return sizeof (snd_seq_queue_status_t);
+}
+
+/**
+ * \brief Return the size of output buffer
+ * \param seq sequencer handle
+ * \return the size of output buffer in bytes
+ *
+ * Obtains the size of output buffer.
+ * This buffer is used to store decoded byte-stream of output events
+ * before transferring to sequencer.
+ *
+ * \sa snd_seq_set_output_buffer_size()
+ */
+size_t
+snd_seq_get_output_buffer_size (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_get_output_buffer_size(seq=%x)\n", seq);
+
+ return 1024;
+}
+
+/**
+ * \brief Change the size of output buffer
+ * \param seq sequencer handle
+ * \param size the size of output buffer to be changed in bytes
+ * \return 0 on success otherwise a negative error code
+ *
+ * Changes the size of output buffer.
+ *
+ * \sa snd_seq_get_output_buffer_size()
+ */
+int
+snd_seq_set_output_buffer_size (snd_seq_t * seq, size_t size)
+{
+ dbg_printf ("snd_seq_set_output_buffer_size(seq=%x, size=%d)\n", seq, size);
+ return 0;
+}
+
+/**
+ * \brief unsubscribe a connection between ports
+ * \param seq sequencer handle
+ * \param sub subscription information to disconnect
+ * \return 0 on success otherwise a negative error code
+ *
+ * Unsubscribes a connection between two ports,
+ * described in sender and dest fields in sub argument.
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from(), snd_seq_disconnect_to()
+ */
+int
+snd_seq_unsubscribe_port (snd_seq_t * seq, snd_seq_port_subscribe_t * sub)
+{
+ dbg_printf ("snd_seq_unsubscribe_port(seq=%x, sub=%x)\n", seq, sub);
+
+ return 0;
+}
+
+/**
+ * \brief Get the queue id of a queue_timer container
+ * \param info queue_timer container
+ * \return queue id
+ *
+ * \sa snd_seq_get_queue_timer()
+ */
+int
+snd_seq_queue_timer_get_queue (const snd_seq_queue_timer_t * info)
+{
+ dbg_printf ("snd_seq_queue_timer_get_queue(timer=%x)\n", info);
+
+ return 0;
+}
+
+/**
+ * \brief obtain the queue timer information
+ * \param seq sequencer handle
+ * \param q queue id to query
+ * \param timer pointer to store the timer information
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_set_queue_timer()
+ */
+int
+snd_seq_get_queue_timer (snd_seq_t * seq, int q,
+ snd_seq_queue_timer_t * timer)
+{
+ dbg_printf ("snd_seq_get_queue_timer(seq=%x, q=%d, timer=%x)\n",
+ seq, 1, timer);
+
+ return 0;
+}
+
+/**
+ * \brief Set the timer id of a queue_timer container
+ * \param info queue_timer container
+ * \param id timer id pointer
+ *
+ * \sa snd_seq_get_queue_timer()
+ */
+void
+snd_seq_queue_timer_set_id (snd_seq_queue_timer_t * info,
+ const snd_timer_id_t * id)
+{
+ dbg_printf ("snd_seq_queue_timer_set_id(timer=%x, id=%x)\n", info, id);
+}
+
+/**
+ * \brief get size of #snd_seq_queue_timer_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_queue_timer_sizeof ()
+{
+ return sizeof (snd_seq_queue_timer_t);
+}
+
+/**
+ * \brief get size of #snd_seq_query_subscribe_t
+ * \return size in bytes
+ */
+size_t
+snd_seq_query_subscribe_sizeof ()
+{
+ return sizeof (snd_seq_query_subscribe_t);
+}
+
+/**
+ * \brief allocate an empty #snd_seq_query_subscribe_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int
+snd_seq_query_subscribe_malloc (snd_seq_query_subscribe_t ** ptr)
+{
+ *ptr = calloc (1, sizeof (snd_seq_query_subscribe_t));
+
+ dbg_printf ("snd_seq_query_subscribe_malloc()=%x\n", *ptr);
+ if (!*ptr)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees a previously allocated #snd_seq_query_subscribe_t
+ * \param pointer to object to free
+ */
+void
+snd_seq_query_subscribe_free (snd_seq_query_subscribe_t * obj)
+{
+ dbg_printf ("snd_seq_query_subscribe_free(obj=%x)\n", obj);
+ free (obj);
+}
+
+/**
+ * \brief Get the address of subscriber of a query_subscribe container
+ * \param info query_subscribe container
+ * \return subscriber's address pointer
+ *
+ * \sa snd_seq_query_port_subscribers()
+ */
+const snd_seq_addr_t *
+snd_seq_query_subscribe_get_addr (const snd_seq_query_subscribe_t * info)
+{
+ dbg_printf ("snd_seq_query_subscribe_get_addr(info=%x)\n", info);
+
+ return NULL; // TODO
+}
+
+/**
+ * \brief Get the index of subscriber of a query_subscribe container
+ * \param info query_subscribe container
+ * \return subscriber's index
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_index()
+ */
+int
+snd_seq_query_subscribe_get_index (const snd_seq_query_subscribe_t * info)
+{
+ dbg_printf ("snd_seq_query_subscribe_get_index(info=%x)\n", info);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Set the subscriber's index to be queried
+ * \param info query_subscribe container
+ * \param index index to be queried
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_index()
+ */
+void
+snd_seq_query_subscribe_set_index (snd_seq_query_subscribe_t * info,
+ int index)
+{
+ dbg_printf ("snd_seq_query_subscribe_t(info=%x, index=%d)\n", info, index);
+
+ // TODO
+}
+
+/**
+ * \brief Get the client/port address of a query_subscribe container
+ * \param info query_subscribe container
+ * \return client/port address pointer
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_root()
+ */
+const snd_seq_addr_t *
+snd_seq_query_subscribe_get_root (const snd_seq_query_subscribe_t * info)
+{
+ dbg_printf ("snd_seq_query_subscribe_get_root(info=%x)\n", info);
+
+ return NULL; // TODO
+}
+
+/**
+ * \brief Set the client/port address of a query_subscribe container
+ * \param info query_subscribe container
+ * \param addr client/port address pointer
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_root()
+ */
+void
+snd_seq_query_subscribe_set_root (snd_seq_query_subscribe_t * info,
+ const snd_seq_addr_t * addr)
+{
+ dbg_printf ("snd_seq_query_subscribe_set_root(info=%d, addr=%x)\n",
+ info, addr);
+}
+
+/**
+ * \brief Get the query type of a query_subscribe container
+ * \param info query_subscribe container
+ * \return query type
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_type()
+ */
+snd_seq_query_subs_type_t
+snd_seq_query_subscribe_get_type (const snd_seq_query_subscribe_t * info)
+{
+ dbg_printf ("snd_seq_query_subscribe_get_type(info=%x)\n", info);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Set the query type of a query_subscribe container
+ * \param info query_subscribe container
+ * \param type query type
+ *
+ * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_type()
+ */
+void
+snd_seq_query_subscribe_set_type (snd_seq_query_subscribe_t * info,
+ snd_seq_query_subs_type_t type)
+{
+ dbg_printf ("snd_seq_query_subscribe_set_type(info=%x, type=%x)\n",
+ info, type);
+
+ // TODO
+}
+
+/**
+ * \brief obtain subscription information
+ * \param seq sequencer handle
+ * \param sub pointer to return the subscription information
+ * \return 0 on success otherwise a negative error code
+ *
+ * \sa snd_seq_subscribe_port(), snd_seq_query_port_subscribers()
+ */
+int
+snd_seq_get_port_subscription (snd_seq_t * seq,
+ snd_seq_port_subscribe_t * sub)
+{
+ dbg_printf ("snd_seq_get_port_subscription(seq=%x, sub=%x)\n", seq, sub);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief query port subscriber list
+ * \param seq sequencer handle
+ * \param subs subscription to query
+ * \return 0 on success otherwise a negative error code
+ *
+ * Queries the subscribers accessing to a port.
+ * The query information is specified in subs argument.
+ *
+ * At least, the client id, the port id, the index number and
+ * the query type must be set to perform a proper query.
+ * As the query type, #SND_SEQ_QUERY_SUBS_READ or #SND_SEQ_QUERY_SUBS_WRITE
+ * can be specified to check whether the readers or the writers to the port.
+ * To query the first subscription, set 0 to the index number. To list up
+ * all the subscriptions, call this function with the index numbers from 0
+ * until this returns a negative value.
+ *
+ * \sa snd_seq_get_port_subscription()
+ */
+int
+snd_seq_query_port_subscribers (snd_seq_t * seq, snd_seq_query_subscribe_t *
+ subs)
+{
+ dbg_printf ("snd_seq_query_port_subscribers(seq=%x, subs=%x)\n", seq, subs);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief Get the real time of a queue_status container
+ * \param info queue_status container
+ * \param time real time
+ *
+ * \sa snd_seq_get_queue_status()
+ */
+const snd_seq_real_time_t *
+snd_seq_queue_status_get_real_time (const snd_seq_queue_status_t * info)
+{
+ dbg_printf ("snd_seq_queue_status_get_real_time(info=%x)\n", info);
+
+ return NULL; // TODO
+}
diff --git a/lib/libsalsa/seq_input.c b/lib/libsalsa/seq_input.c
new file mode 100644
index 0000000..b61d22a
--- /dev/null
+++ b/lib/libsalsa/seq_input.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+static snd_seq_event_t *
+alloc_event (snd_seq_t * seq)
+{
+ snd_seq_event_t *ev;
+
+ if (seq->nevents >= MAX_EVENTS)
+ {
+ fprintf (stderr, "libsalsa: Local buffer overflow - event dropped\n");
+ return NULL;
+ }
+
+ ev = &seq->events[seq->nevents++];
+
+ ev->type = SND_SEQ_EVENT_SENSING; /* NOP message */
+
+ return ev;
+}
+
+static void
+voice_message (snd_seq_t * seq, unsigned char msg, unsigned char ch,
+ unsigned char *parms, int len)
+{
+ snd_seq_event_t *ev;
+ if ((ev = alloc_event (seq)) == NULL)
+ return;
+
+ dbg_printf3 ("Voice message %02x, ch=%d, %3d, %3d\n", msg, ch, parms[0],
+ parms[1]);
+
+ switch (msg)
+ {
+ case MIDI_NOTEON:
+ ev->type = SND_SEQ_EVENT_NOTEON;
+ ev->data.note.channel = ch;
+ ev->data.note.note = parms[0];
+ ev->data.note.velocity = parms[1];
+ break;
+
+ case MIDI_NOTEOFF:
+ ev->type = SND_SEQ_EVENT_NOTEOFF;
+ ev->data.note.channel = ch;
+ ev->data.note.note = parms[0];
+ ev->data.note.velocity = parms[1];
+ break;
+ }
+}
+
+static void
+channel_message (snd_seq_t * seq, unsigned char msg, unsigned char ch,
+ unsigned char *parms, int len)
+{
+ snd_seq_event_t *ev;
+ if ((ev = alloc_event (seq)) == NULL)
+ return;
+
+ dbg_printf3 ("Channel message %02x, ch=%d, %3d, %3d\n", msg, ch, parms[0],
+ parms[1]);
+}
+
+static void
+realtime_message (snd_seq_t * seq, unsigned char msg, unsigned char *parms,
+ int len)
+{
+ snd_seq_event_t *ev;
+ if ((ev = alloc_event (seq)) == NULL)
+ return;
+
+ dbg_printf3 ("Realtime message %02x, %2x\n", msg, parms[0]);
+}
+
+static void
+sysex_message (snd_seq_t * seq, unsigned char *parms, int len)
+{
+ int i;
+ snd_seq_event_t *ev;
+ if ((ev = alloc_event (seq)) == NULL)
+ return;
+
+
+ if (alib_verbose > 2)
+ {
+ printf ("Sysex message: ");
+ for (i = 0; i < len; i++)
+ printf ("%02x ", parms[i]);
+ printf ("\n");
+ }
+}
+
+void
+midiparser_callback (void *context, int category, unsigned char msg,
+ unsigned char ch, unsigned char *parms, int len)
+{
+
+ switch (category)
+ {
+ case CAT_VOICE:
+ voice_message ((snd_seq_t *) context, msg, ch, parms, len);
+ break;
+
+ case CAT_CHN:
+ channel_message ((snd_seq_t *) context, msg, ch, parms, len);
+ break;
+
+ case CAT_REALTIME:
+ realtime_message ((snd_seq_t *) context, msg, parms, len);
+ break;
+
+ case CAT_SYSEX:
+ sysex_message ((snd_seq_t *) context, parms, len);
+ break;
+
+ case CAT_MTC:
+ default:
+ dbg_printf ("Unknown MIDI message category %d\n", category);
+ }
+}
diff --git a/lib/libsalsa/seq_output.c b/lib/libsalsa/seq_output.c
new file mode 100644
index 0000000..6170dc2
--- /dev/null
+++ b/lib/libsalsa/seq_output.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+static int
+midi_out3 (snd_seq_t * seq, int msg, int parm1, int parm2)
+{
+ unsigned char buf[3];
+ int l;
+
+ if (msg < 0 || msg >= 0xff)
+ return -ERANGE;
+ if (parm1 < 0 || parm1 > 0x7f)
+ return -ERANGE;
+ if (parm2 < 0 || parm2 > 0x7f)
+ return -ERANGE;
+
+ buf[0] = msg;
+ buf[1] = parm1;
+ buf[2] = parm2;
+
+ if ((l = write (seq->fd, buf, 3)) != 3)
+ {
+ if (l == -1)
+ return -errno;
+
+ return -EBADE; /* Randomly selected error */
+ }
+
+ return 0;
+}
+
+static int
+midi_out2 (snd_seq_t * seq, int msg, int parm1)
+{
+ unsigned char buf[3];
+ int l;
+
+ if (msg < 0 || msg >= 0xff)
+ return -ERANGE;
+ if (parm1 < 0 || parm1 > 0x7f)
+ return -ERANGE;
+
+ buf[0] = msg;
+ buf[1] = parm1;
+
+ if ((l = write (seq->fd, buf, 2)) != 2)
+ {
+ if (l == -1)
+ return -errno;
+
+ return -EBADE; /* Randomly selected error */
+ }
+
+ return 0;
+}
+
+int
+convert_event (snd_seq_t * seq, snd_seq_event_t * ev)
+{
+ int value;
+
+ dbg_printf3
+ ("Event %2d: flags=%08x tag=%08x, q=%2d, time=%d, src=%x, dst=%x\n",
+ ev->type, ev->flags, ev->tag, ev->queue, ev->time, ev->source, ev->dest);
+
+ switch (ev->type)
+ {
+ case SND_SEQ_EVENT_CONTROLLER:
+ dbg_printf3 ("\tSND_SEQ_EVENT_CONTRLLER %2d, %3d, %3d\n",
+ ev->data.control.channel,
+ ev->data.control.param, ev->data.control.value);
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0xB0 + ev->data.control.channel,
+ ev->data.control.param, ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_PGMCHANGE:
+ dbg_printf3 ("\tSND_SEQ_EVENT_PGMCHANGE %2d, %3d, %3d\n",
+ ev->data.control.channel,
+ ev->data.control.param, ev->data.control.value);
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out2 (seq, 0xC0 + ev->data.control.channel,
+ ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_CHANPRESS:
+ dbg_printf3 ("\tSND_SEQ_EVENT_CHANPRESS %2d, %5d\n",
+ ev->data.control.channel, ev->data.control.value);
+ value = ev->data.control.value + 8192;
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0xD0 + ev->data.control.channel,
+ value & 0x7f, (value >> 7) & 0x7f);
+ break;
+
+ case SND_SEQ_EVENT_PITCHBEND:
+ dbg_printf3 ("\tSND_SEQ_EVENT_PITCHBEND %2d, %5d\n",
+ ev->data.control.channel, ev->data.control.value);
+ value = ev->data.control.value + 8192;
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0xE0 + ev->data.control.channel,
+ value & 0x7f, (value >> 7) & 0x7f);
+ break;
+
+ case SND_SEQ_EVENT_NOTEON:
+ dbg_printf3 ("\tSND_SEQ_EVENT_NOTEON %2d, %3d, %d\n",
+ ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0x90 + ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_NOTEOFF:
+ dbg_printf3 ("\tSND_SEQ_EVENT_NOTEOFF %2d, %3d, %d\n",
+ ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0x80 + ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_KEYPRESS:
+ dbg_printf3 ("\tSND_SEQ_EVENT_KEYPRESS %2d, %3d, %d\n",
+ ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ if (ev->data.control.channel > 15)
+ return -ERANGE;
+ return midi_out3 (seq, 0xA0 + ev->data.note.channel,
+ ev->data.note.note, ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_SYSTEM:
+ dbg_printf ("\tSND_SEQ_EVENT_SYSTEM\n");
+ break;
+ case SND_SEQ_EVENT_RESULT:
+ dbg_printf ("\tSND_SEQ_EVENT_RESULT\n");
+ break;
+ case SND_SEQ_EVENT_NOTE:
+ dbg_printf ("\tSND_SEQ_EVENT_NOTE\n");
+ break;
+ case SND_SEQ_EVENT_CONTROL14:
+ dbg_printf ("\tSND_SEQ_EVENT_CONTROL14\n");
+ break;
+ case SND_SEQ_EVENT_NONREGPARAM:
+ dbg_printf ("\tSND_SEQ_EVENT_NONREGPARAM\n");
+ break;
+ case SND_SEQ_EVENT_REGPARAM:
+ dbg_printf ("\tSND_SEQ_EVENT_REGPARAM\n");
+ break;
+ case SND_SEQ_EVENT_SONGPOS:
+ dbg_printf ("\tSND_SEQ_EVENT_SONGPOS\n");
+ break;
+ case SND_SEQ_EVENT_SONGSEL:
+ dbg_printf ("\tSND_SEQ_EVENT_SONGSEL\n");
+ break;
+ case SND_SEQ_EVENT_QFRAME:
+ dbg_printf ("\tSND_SEQ_EVENT_QFRAME\n");
+ break;
+ case SND_SEQ_EVENT_TIMESIGN:
+ dbg_printf ("\tSND_SEQ_EVENT_TIMESIGN\n");
+ break;
+ case SND_SEQ_EVENT_KEYSIGN:
+ dbg_printf ("\tSND_SEQ_EVENT_KEYSIGN\n");
+ break;
+ case SND_SEQ_EVENT_START:
+ dbg_printf ("\tSND_SEQ_EVENT_START\n");
+ break;
+ case SND_SEQ_EVENT_CONTINUE:
+ dbg_printf ("\tSND_SEQ_EVENT_CONTINUE\n");
+ break;
+ case SND_SEQ_EVENT_STOP:
+ dbg_printf ("\tSND_SEQ_EVENT_STOP\n");
+ break;
+ case SND_SEQ_EVENT_SETPOS_TICK:
+ dbg_printf ("\tSND_SEQ_EVENT_SETPOS_TICK\n");
+ break;
+ case SND_SEQ_EVENT_SETPOS_TIME:
+ dbg_printf ("\tSND_SEQ_EVENT_SETPOS_TIME\n");
+ break;
+ case SND_SEQ_EVENT_TEMPO:
+ dbg_printf ("\tSND_SEQ_EVENT_TEMPO\n");
+ break;
+ case SND_SEQ_EVENT_CLOCK:
+ dbg_printf ("\tSND_SEQ_EVENT_CLOCK\n");
+ break;
+ case SND_SEQ_EVENT_TICK:
+ dbg_printf ("\tSND_SEQ_EVENT_TICK\n");
+ break;
+ case SND_SEQ_EVENT_QUEUE_SKEW:
+ dbg_printf ("\tSND_SEQ_EVENT_QUEUE_SKEW\n");
+ break;
+ case SND_SEQ_EVENT_SYNC_POS:
+ dbg_printf ("\tSND_SEQ_EVENT_SYNC_POS\n");
+ break;
+ case SND_SEQ_EVENT_TUNE_REQUEST:
+ dbg_printf ("\tSND_SEQ_EVENT_TUNE_REQUEST\n");
+ break;
+ case SND_SEQ_EVENT_RESET:
+ dbg_printf ("\tSND_SEQ_EVENT_RESET\n");
+ break;
+ case SND_SEQ_EVENT_SENSING:
+ dbg_printf ("\tSND_SEQ_EVENT_SENSING\n");
+ break;
+ case SND_SEQ_EVENT_ECHO:
+ dbg_printf ("\tSND_SEQ_EVENT_ECHO\n");
+ break;
+ case SND_SEQ_EVENT_OSS:
+ dbg_printf ("\tSND_SEQ_EVENT_OSS\n");
+ break;
+ case SND_SEQ_EVENT_CLIENT_START:
+ dbg_printf ("\tSND_SEQ_EVENT_CLIENT_START\n");
+ break;
+ case SND_SEQ_EVENT_CLIENT_EXIT:
+ dbg_printf ("\tSND_SEQ_EVENT_CLIENT_EXIT\n");
+ break;
+ case SND_SEQ_EVENT_CLIENT_CHANGE:
+ dbg_printf ("\tSND_SEQ_EVENT_CLIENT_CHANGE\n");
+ break;
+ case SND_SEQ_EVENT_PORT_START:
+ dbg_printf ("\tSND_SEQ_EVENT_PORT_START\n");
+ break;
+ case SND_SEQ_EVENT_PORT_EXIT:
+ dbg_printf ("\tSND_SEQ_EVENT_PORT_EXIT\n");
+ break;
+ case SND_SEQ_EVENT_PORT_CHANGE:
+ dbg_printf ("\tSND_SEQ_EVENT_PORT_CHANGE\n");
+ break;
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+ dbg_printf ("\tSND_SEQ_EVENT_PORT_SUBSCRIBED\n");
+ break;
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+ dbg_printf ("\tSND_SEQ_EVENT_PORT_UNSUBSCRIBED\n");
+ break;
+ case SND_SEQ_EVENT_USR0:
+ dbg_printf ("\tSND_SEQ_EVENT_USR0\n");
+ break;
+ case SND_SEQ_EVENT_USR1:
+ dbg_printf ("\tSND_SEQ_EVENT_USR1\n");
+ break;
+ case SND_SEQ_EVENT_USR2:
+ dbg_printf ("\tSND_SEQ_EVENT_USR2\n");
+ break;
+ case SND_SEQ_EVENT_USR3:
+ dbg_printf ("\tSND_SEQ_EVENT_USR3\n");
+ break;
+ case SND_SEQ_EVENT_USR4:
+ dbg_printf ("\tSND_SEQ_EVENT_USR4\n");
+ break;
+ case SND_SEQ_EVENT_USR5:
+ dbg_printf ("\tSND_SEQ_EVENT_USR5\n");
+ break;
+ case SND_SEQ_EVENT_USR6:
+ dbg_printf ("\tSND_SEQ_EVENT_USR6\n");
+ break;
+ case SND_SEQ_EVENT_USR7:
+ dbg_printf ("\tSND_SEQ_EVENT_USR7\n");
+ break;
+ case SND_SEQ_EVENT_USR8:
+ dbg_printf ("\tSND_SEQ_EVENT_USR8\n");
+ break;
+ case SND_SEQ_EVENT_USR9:
+ dbg_printf ("\tSND_SEQ_EVENT_USR9\n");
+ break;
+ case SND_SEQ_EVENT_SYSEX:
+ dbg_printf ("\tSND_SEQ_EVENT_SYSEX\n");
+ break;
+ case SND_SEQ_EVENT_BOUNCE:
+ dbg_printf ("\tSND_SEQ_EVENT_BOUNCE\n");
+ break;
+ case SND_SEQ_EVENT_USR_VAR0:
+ dbg_printf ("\tSND_SEQ_EVENT_USR_VAR0\n");
+ break;
+ case SND_SEQ_EVENT_USR_VAR1:
+ dbg_printf ("\tSND_SEQ_EVENT_USR_VAR1\n");
+ break;
+ case SND_SEQ_EVENT_USR_VAR2:
+ dbg_printf ("\tSND_SEQ_EVENT_USR_VAR2\n");
+ break;
+ case SND_SEQ_EVENT_USR_VAR3:
+ dbg_printf ("\tSND_SEQ_EVENT_USR_VAR3\n");
+ break;
+ case SND_SEQ_EVENT_USR_VAR4:
+ dbg_printf ("\tSND_SEQ_EVENT_USR_VAR4\n");
+ break;
+ case SND_SEQ_EVENT_NONE:
+ dbg_printf ("\tSND_SEQ_EVENT_NONE\n");
+ break;
+ default:
+ dbg_printf ("\tUnknown event type %d\n", ev->type);
+ }
+ return 0;
+}
diff --git a/lib/libsalsa/seqmid.c b/lib/libsalsa/seqmid.c
new file mode 100644
index 0000000..e3ad1d0
--- /dev/null
+++ b/lib/libsalsa/seqmid.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+/**
+ * \brief create a port - simple version
+ * \param seq sequencer handle
+ * \param name the name of the port
+ * \param caps capability bits
+ * \param type type bits
+ * \return the created port number or negative error code
+ *
+ * Creates a port with the given capability and type bits.
+ *
+ * \sa snd_seq_create_port(), snd_seq_delete_simple_port()
+ */
+int
+snd_seq_create_simple_port (snd_seq_t * seq, const char *name,
+ unsigned int caps, unsigned int type)
+{
+ snd_seq_port_info_t pinfo;
+ int result;
+
+ dbg_printf
+ ("snd_seq_create_simple_port(seq=%x, name='%s', caps=%x, type=%x)\n", seq,
+ name, caps, type);
+
+ memset (&pinfo, 0, sizeof (pinfo));
+ if (name)
+ strncpy (pinfo.name, name, sizeof (pinfo.name) - 1);
+ pinfo.capability = caps;
+ pinfo.type = type;
+ pinfo.midi_channels = 16;
+ pinfo.midi_voices = 64; /* XXX */
+ pinfo.synth_voices = 0; /* XXX */
+
+ result = snd_seq_create_port (seq, &pinfo);
+ if (result < 0)
+ return result;
+ else
+ return pinfo.port;
+}
+
+/**
+ * \brief delete the port
+ * \param seq sequencer handle
+ * \param port port id
+ * \return 0 on success or negative error code
+ *
+ * \sa snd_seq_delete_port(), snd_seq_create_simple_port()
+ */
+int
+snd_seq_delete_simple_port (snd_seq_t * seq, int port)
+{
+ dbg_printf ("snd_seq_delete_simple_port()\n");
+
+ return 0;
+}
+
+/**
+ * \brief set client name
+ * \param seq sequencer handle
+ * \param name name string
+ * \return 0 on success or negative error code
+ *
+ * \sa snd_seq_set_client_info()
+ */
+int
+snd_seq_set_client_name (snd_seq_t * seq, const char *name)
+{
+ snd_seq_client_info_t info;
+ int err;
+
+ dbg_printf ("snd_seq_set_client_name(seq=%x, name='%s')\n", seq, name);
+
+ if ((err = snd_seq_get_client_info (seq, &info)) < 0)
+ return err;
+ strncpy (info.name, name, sizeof (info.name) - 1);
+ return snd_seq_set_client_info (seq, &info);
+}
+
+/**
+ * \brief change the output pool size of the given client
+ * \param seq sequencer handle
+ * \param size output pool size
+ * \return 0 on success or negative error code
+ *
+ * \sa snd_seq_set_client_pool()
+ */
+int
+snd_seq_set_client_pool_output (snd_seq_t * seq, size_t size)
+{
+ dbg_printf ("snd_seq_set_client_pool_output(seq=%x, size=%d)\n", seq, size);
+ return 0;
+}
+
+/**
+ * \brief parse the given string and get the sequencer address
+ * \param seq sequencer handle
+ * \param addr the address pointer to be returned
+ * \param arg the string to be parsed
+ * \return 0 on success or negative error code
+ *
+ * This function parses the sequencer client and port numbers from the given string.
+ * The client and port tokes are separated by either colon or period, e.g. 128:1.
+ * When \a seq is not NULL, the function accepts also a client name not only
+ * digit numbers.
+ */
+int
+snd_seq_parse_address (snd_seq_t * seq, snd_seq_addr_t * addr,
+ const char *arg)
+{
+ dbg_printf ("snd_seq_parse_address()\n");
+
+ return 0;
+}
+
+/**
+ * \brief wait until all events are processed
+ * \param seq sequencer handle
+ * \return 0 on success or negative error code
+ *
+ * This function waits until all events of this client are processed.
+ *
+ * \sa snd_seq_drain_output()
+ */
+int
+snd_seq_sync_output_queue (snd_seq_t * seq)
+{
+ dbg_printf ("snd_seq_sync_output_queue()\n");
+
+ return 0;
+}
+
+/**
+ * \brief simple disconnection
+ * \param myport the port id as sender
+ * \param dest_client destination client id
+ * \param dest_port destination port id
+ * \return 0 on success or negative error code
+ *
+ * Remove connection from the given sender client:port
+ * to the given destination port in the current client.
+ *
+ * \sa snd_seq_unsubscribe_port(), snd_seq_connect_to()
+ */
+int
+snd_seq_disconnect_to (snd_seq_t * seq, int myport, int dest_client,
+ int dest_port)
+{
+ dbg_printf
+ ("snd_seq_disconnect_to(seq=%x, myport=%d, dest_client=%d, dest_port=%d)\n",
+ seq, myport, dest_client, dest_port);
+
+ return 0;
+}
+
+/**
+ * \brief change the input pool size of the given client
+ * \param seq sequencer handle
+ * \param size input pool size
+ * \return 0 on success or negative error code
+ *
+ * \sa snd_seq_set_client_pool()
+ */
+int
+snd_seq_set_client_pool_input (snd_seq_t * seq, size_t size)
+{
+ dbg_printf ("snd_seq_set_client_pool_input(seq=%x, size=%d)\n", seq, size);
+
+ return 0;
+}
+
+/**
+ * \brief change the output room size of the given client
+ * \param seq sequencer handle
+ * \param size output room size
+ * \return 0 on success or negative error code
+ *
+ * \sa snd_seq_set_client_pool()
+ */
+int
+snd_seq_set_client_pool_output_room (snd_seq_t * seq, size_t size)
+{
+ dbg_printf ("snd_seq_set_client_pool_output_room(seq=%x, size=%d)\n", seq,
+ size);
+
+ return 0;
+}
diff --git a/lib/libsalsa/stubs.c b/lib/libsalsa/stubs.c
new file mode 100644
index 0000000..f13771f
--- /dev/null
+++ b/lib/libsalsa/stubs.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+extern int alib_verbose;
+
+#define STUB(x) \
+int x(void) \
+{ \
+ if (alib_verbose>0)printf("libsalsa: Stub for " #x " called.\n"); \
+ return -53; \
+}
+
+#define STUB_NULL(x) \
+void* x(void) \
+{ \
+ if (alib_verbose>0)printf("libsalsa: Stub for " #x " called.\n"); \
+ return (void*)0; \
+}
+
+STUB (snd_ctl_elem_info_get_count)
+STUB (snd_hctl_elem_write)
+STUB (snd_hctl_first_elem)
+STUB (snd_ctl_elem_info_get_item_name)
+STUB (snd_hctl_elem_get_callback_private)
+STUB_NULL (snd_ctl_card_info_get_driver)
+STUB (snd_ctl_elem_value_get_enumerated)
+STUB (snd_hctl_set_callback)
+STUB (snd_ctl_elem_info_set_item)
+STUB (snd_hctl_load)
+STUB (snd_ctl_elem_info_get_step)
+STUB (snd_ctl_elem_value_set_enumerated)
+STUB (snd_ctl_elem_info_get_name)
+STUB (snd_hctl_handle_events)
+STUB (snd_ctl_elem_info_sizeof)
+STUB (snd_ctl_elem_value_get_boolean)
+STUB (snd_ctl_elem_value_malloc)
+STUB (snd_ctl_elem_id_set_index)
+STUB (snd_ctl_elem_value_get_integer)
+STUB (snd_hctl_nonblock)
+STUB (snd_hctl_get_count)
+STUB (snd_ctl_card_info_get_longname)
+STUB (snd_hctl_elem_next)
+STUB (snd_ctl_elem_info_get_index)
+STUB (snd_hctl_elem_read)
+STUB (snd_hctl_find_elem)
+STUB (snd_ctl_elem_value_set_integer)
+STUB (snd_hctl_elem_set_callback)
+STUB (snd_hctl_poll_descriptors)
+STUB (snd_ctl_elem_info_get_items)
+STUB (snd_ctl_elem_info_get_max)
+STUB (snd_hctl_open)
+STUB (snd_ctl_elem_value_set_boolean)
+STUB (snd_ctl_elem_id_set_interface)
+STUB (snd_hctl_set_callback_private)
+STUB (snd_ctl_elem_id_sizeof)
+STUB (snd_ctl_elem_info_get_type)
+STUB (snd_hctl_close)
+STUB (snd_ctl_elem_info_malloc)
+STUB (snd_ctl_elem_info_get_min)
+STUB (snd_hctl_elem_info)
+STUB (snd_hctl_elem_set_callback_private) STUB (snd_ctl_elem_id_set_name)
diff --git a/lib/libsalsa/timer.c b/lib/libsalsa/timer.c
new file mode 100644
index 0000000..3ea5da6
--- /dev/null
+++ b/lib/libsalsa/timer.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "local.h"
+
+struct _snd_timer
+{
+ int dummy;
+};
+
+struct _snd_timer_id
+{
+ int dummy;
+};
+
+struct _snd_timer_info
+{
+ int dummy;
+};
+
+/**
+ * \brief Opens a new connection to the timer interface.
+ * \param timer Returned handle (NULL if not wanted)
+ * \param name ASCII identifier of the timer handle
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ *
+ * Opens a new connection to the timer interface specified with
+ * an ASCII identifier and mode.
+ */
+int
+snd_timer_open (snd_timer_t ** tmr, const char *name, int mode)
+{
+ snd_timer_t *timer;
+
+ ALIB_INIT ();
+ if (!alib_appcheck ())
+ {
+ dbg_printf ("snd_timer_open(%s, %x) refused,\n", name, mode);
+ return -ENODEV;
+ }
+
+ timer = malloc (sizeof (*timer));
+
+ dbg_printf ("snd_timer_open(name='%s', mode=%x)=%x\n", name, mode, timer);
+
+ if (timer == NULL)
+ return -ENOMEM;
+
+ *tmr = timer;
+
+ return 0;
+}
+
+/**
+ * \brief close timer handle
+ * \param timer timer handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified timer handle and frees all associated
+ * resources.
+ */
+int
+snd_timer_close (snd_timer_t * timer)
+{
+ dbg_printf ("snd_timer_close(%x)\n", timer);
+
+ free (timer);
+ return 0;
+}
+
+/**
+ * \brief get size of the snd_timer_id_t structure in bytes
+ * \return size of the snd_timer_id_t structure in bytes
+ */
+size_t
+snd_timer_id_sizeof ()
+{
+ return sizeof (snd_timer_id_t);
+}
+
+/**
+ * \brief get timer card
+ * \param params pointer to #snd_timer_id_t structure
+ * \return timer card number
+ */
+int
+snd_timer_id_get_card (snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_id_get_card(tid=%x)\n", tid);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief get timer class
+ * \param tid pointer to #snd_timer_id_t structure
+ * \return timer class
+ */
+int
+snd_timer_id_get_class (snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_id_get_class(tid=%x)\n", tid);
+
+ return 0; // TODO
+}
+
+
+/**
+ * \brief get timer device
+ * \param params pointer to #snd_timer_id_t structure
+ * \return timer device number
+ */
+int
+snd_timer_id_get_device (snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_id_get_device(tid=%x)\n", tid);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief get timer sub-class
+ * \param params pointer to #snd_timer_id_t structure
+ * \return timer sub-class
+ */
+int
+snd_timer_id_get_sclass (snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_id_get_sclass(tid=%x)\n", tid);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief get timer subdevice
+ * \param params pointer to #snd_timer_id_t structure
+ * \return timer subdevice number
+ */
+int
+snd_timer_id_get_subdevice (snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_id_get_subdevice(tid=%x)\n", tid);
+
+ return 0; // TODO
+}
+
+/**
+ * \brief set timer card
+ * \param tid pointer to #snd_timer_id_t structure
+ * \param card card number
+ */
+void
+snd_timer_id_set_card (snd_timer_id_t * tid, int card)
+{
+ dbg_printf ("snd_timer_id_set_card(tid=%x, card=%d)\n", tid, card);
+
+ // TODO
+}
+
+/**
+ * \brief set timer class
+ * \param tid pointer to #snd_timer_id_t structure
+ * \param dev_class class of timer device
+ */
+void
+snd_timer_id_set_class (snd_timer_id_t * tid, int dev_class)
+{
+ dbg_printf ("snd_timer_id_set_class(tid=%x, dev_class=%d)\n", tid,
+ dev_class);
+ // TODO
+}
+
+/**
+ * \brief set timer device
+ * \param tid pointer to #snd_timer_id_t structure
+ * \param device device number
+ */
+void
+snd_timer_id_set_device (snd_timer_id_t * tid, int device)
+{
+ dbg_printf ("snd_timer_id_set_device(tid=%x, device=%d)\n", tid, device);
+
+ // TODO
+}
+
+/**
+ * \brief set timer sub-class
+ * \param tid pointer to #snd_timer_id_t structure
+ * \param dev_sclass sub-class of timer device
+ */
+void
+snd_timer_id_set_sclass (snd_timer_id_t * tid, int dev_sclass)
+{
+ dbg_printf ("snd_timer_id_set_sclass(tid=%x, dev_sclass=%d)\n",
+ tid, dev_sclass);
+ // TODO
+}
+
+/**
+ * \brief set timer subdevice
+ * \param tid pointer to #snd_timer_id_t structure
+ * \param subdevice subdevice number
+ */
+void
+snd_timer_id_set_subdevice (snd_timer_id_t * tid, int subdevice)
+{
+ dbg_printf ("snd_timer_id_set_subdevice(tid=%x, subdevice=%d)\n",
+ tid, subdevice);
+
+ // TODO
+}
+
+/**
+ * \brief get size of the snd_timer_info_t structure in bytes
+ * \return size of the snd_timer_info_t structure in bytes
+ */
+size_t
+snd_timer_info_sizeof ()
+{
+ return sizeof (snd_timer_info_t);
+}
+
+/**
+ * \brief allocate a new snd_timer_info_t structure
+ * \param ptr returned pointer
+ * \return 0 on success otherwise a negative error code if fails
+ *
+ * Allocates a new snd_timer_info_t structure using the standard
+ * malloc C library function.
+ */
+int
+snd_timer_info_malloc (snd_timer_info_t ** info)
+{
+ *info = calloc (1, sizeof (snd_timer_info_t));
+ dbg_printf ("snd_timer_info_malloc()=%x\n", *info);
+ if (!*info)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * \brief frees the snd_timer_info_t structure
+ * \param info pointer to the snd_timer_info_t structure to free
+ *
+ * Frees the given snd_timer_info_t structure using the standard
+ * free C library function.
+ */
+void
+snd_timer_info_free (snd_timer_info_t * info)
+{
+ dbg_printf ("snd_timer_info_free(%x)\n", info);
+ free (info);
+}
+
+/**
+ * \brief get information about timer handle
+ * \param timer timer handle
+ * \param info pointer to a snd_timer_info_t structure to be filled
+ * \return 0 on success otherwise a negative error code
+ */
+int
+snd_timer_info (snd_timer_t * timer, snd_timer_info_t * info)
+{
+ dbg_printf ("snd_timer_info(timer=%x, info=%x)\n", timer, info);
+
+ // TODO
+
+ return 0;
+}
+
+/**
+ * \brief get timer name
+ * \param info pointer to #snd_timer_info_t structure
+ * \return timer name
+ */
+const char *
+snd_timer_info_get_name (snd_timer_info_t * info)
+{
+ dbg_printf ("snd_timer_info_get_name(info=%x)\n", info);
+
+ return "OSS Timer"; // TODO
+}
+
+
+/**
+ * \brief get timer resolution in us
+ * \param info pointer to #snd_timer_info_t structure
+ * \return timer resolution
+ */
+long
+snd_timer_info_get_resolution (snd_timer_info_t * info)
+{
+ dbg_printf ("snd_timer_info_get_resolution(info=%x)\n", info);
+
+ return 1000; // TODO
+}
+
+
+static int
+snd_timer_query_open_conf (snd_timer_query_t ** timer,
+ const char *name, snd_config_t * timer_root,
+ snd_config_t * timer_conf, int mode)
+{
+ dbg_printf
+ ("snd_timer_query_open_conf(name='%s', root=%x, conf=%x, mode=%x)\n",
+ name, timer_root, timer_conf, mode);
+ ALIB_INIT ();
+ if (!alib_appcheck ())
+ return -ENODEV;
+
+ return -EIO;
+}
+
+/**
+ * \brief close timer query handle
+ * \param timer timer handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified timer handle and frees all associated
+ * resources.
+ */
+int
+snd_timer_query_close (snd_timer_query_t * timer)
+{
+ dbg_printf ("snd_timer_query_close(timer=%x)\n", timer);
+
+ return 0;
+}
+
+/**
+ * \brief obtain the next timer identification
+ * \param timer timer handle
+ * \param tid timer identification
+ * \return 0 on success otherwise a negative error code
+ *
+ * if tid->dev_class is -1, then the first device is returned
+ * if result tid->dev_class is -1, no more devices are left
+ */
+int
+snd_timer_query_next_device (snd_timer_query_t * timer, snd_timer_id_t * tid)
+{
+ dbg_printf ("snd_timer_query_next_device(timer=%x, tid=%x)\n", timer, tid);
+
+ return -1;
+}