mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Compare commits
97 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d62b1d5407 | ||
|
|
3a97718124 | ||
|
|
782b0597c2 | ||
|
|
4ad4d9590a | ||
|
|
5f524e3004 | ||
|
|
ee5a58f48e | ||
|
|
07ec2ad34c | ||
|
|
8df60992b7 | ||
|
|
368ea9af82 | ||
|
|
8ab0228f51 | ||
|
|
81d70a2713 | ||
|
|
c748afe123 | ||
|
|
8291d2c601 | ||
|
|
e51cba0973 | ||
|
|
6073f53051 | ||
|
|
8b75db9676 | ||
|
|
15f2b27612 | ||
|
|
7e01443ecc | ||
|
|
a4e47461ec | ||
|
|
647c001321 | ||
|
|
0d2acc2084 | ||
|
|
90eb3c1e96 | ||
|
|
95d0274b60 | ||
|
|
e088d08c76 | ||
|
|
d8300e5cb7 | ||
|
|
70f4c95df5 | ||
|
|
d5f19bcabc | ||
|
|
42b8f1299f | ||
|
|
fb285b366f | ||
|
|
1b9a073e6a | ||
|
|
6855cb838d | ||
|
|
e9e3c01ff7 | ||
|
|
8f6fef8b1a | ||
|
|
12f6790910 | ||
|
|
7fbd47ce79 | ||
|
|
0c7086777a | ||
|
|
df8f1cc1ec | ||
|
|
e550dcdd90 | ||
|
|
305168fd22 | ||
|
|
0bb35d4980 | ||
|
|
995e279081 | ||
|
|
1101c397aa | ||
|
|
c8bc54a9ca | ||
|
|
a7de48692f | ||
|
|
ea8972c83b | ||
|
|
35d2efefa9 | ||
|
|
cdd5a9fa10 | ||
|
|
137eca7720 | ||
|
|
e1cf4d3f68 | ||
|
|
3fe7d9a49b | ||
|
|
352cbc5eb9 | ||
|
|
76d2d285c1 | ||
|
|
07cee0ba05 | ||
|
|
6880219ad4 | ||
|
|
76edab4e59 | ||
|
|
785fd327ad | ||
|
|
49295a4e17 | ||
|
|
4e7a510095 | ||
|
|
a3865b2439 | ||
|
|
073dc7577a | ||
|
|
93d7645d84 | ||
|
|
513ef7ace4 | ||
|
|
9ac93d1252 | ||
|
|
fc58f8fcc3 | ||
|
|
2adc30e983 | ||
|
|
3b9f3b9431 | ||
|
|
645668dca2 | ||
|
|
f81236cf7e | ||
|
|
b154d9145f | ||
|
|
9b6dfb3eb6 | ||
|
|
f08f4aceec | ||
|
|
3e38164ee5 | ||
|
|
fa673b719c | ||
|
|
769d1db1b0 | ||
|
|
ddc4c668ba | ||
|
|
d969439813 | ||
|
|
f090a93ea8 | ||
|
|
28948f2fcc | ||
|
|
530e2f8131 | ||
|
|
48101de6fa | ||
|
|
24c7f42733 | ||
|
|
568b2ac1db | ||
|
|
ade099fab7 | ||
|
|
30f8ba74c5 | ||
|
|
8734673c21 | ||
|
|
32e2c8d8a2 | ||
|
|
2071eb8a44 | ||
|
|
f8df023597 | ||
|
|
18579adfbc | ||
|
|
8da704ef4f | ||
|
|
3390f31664 | ||
|
|
6da898cf40 | ||
|
|
ef38bff00e | ||
|
|
cacc5bd5c1 | ||
|
|
f784035a90 | ||
|
|
6167b8ce3e | ||
|
|
6767f623ca |
85 changed files with 3097 additions and 5988 deletions
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
- name: Prepare environment
|
||||
run: |
|
||||
dnf -y upgrade
|
||||
dnf -y install @development-tools libtool bzip2
|
||||
dnf -y install @development-tools libtool bzip2 awk
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
@ -64,7 +64,7 @@ jobs:
|
|||
cd alsa-lib-$(cat version)
|
||||
make install
|
||||
- name: Archive package
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: alsa-lib-test-package
|
||||
path: artifacts/
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -35,7 +35,6 @@ include/version.h
|
|||
include/alsa
|
||||
include/asoundlib.h
|
||||
utils/alsa-lib.spec
|
||||
alsalisp/alsalisp
|
||||
aserver/aserver
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
|
|
@ -65,6 +64,8 @@ test/playmidi1
|
|||
test/queue_timer
|
||||
test/rawmidi
|
||||
test/seq
|
||||
test/seq-ump-example
|
||||
test/timer
|
||||
test/umpinfo
|
||||
test/lsb/config
|
||||
test/lsb/midi_event
|
||||
|
|
|
|||
|
|
@ -10,11 +10,6 @@ endif
|
|||
if BUILD_PCM_PLUGIN_SHM
|
||||
SUBDIRS += aserver
|
||||
endif
|
||||
if BUILD_MIXER
|
||||
if BUILD_ALISP
|
||||
SUBDIRS += alsalisp
|
||||
endif
|
||||
endif
|
||||
SUBDIRS += test utils
|
||||
EXTRA_DIST=README.md ChangeLog INSTALL TODO NOTES configure gitcompile libtool \
|
||||
depcomp version MEMORY-LEAK m4/attributes.m4
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
noinst_PROGRAMS = alsalisp
|
||||
|
||||
alsalisp_SOURCES = alsalisp.c
|
||||
alsalisp_LDADD = ../src/libasound.la
|
||||
|
||||
all: alsalisp
|
||||
|
||||
AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/src/alisp
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* ALSA lisp implementation
|
||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@perex.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "asoundlib.h"
|
||||
#include "alisp.h"
|
||||
|
||||
static int verbose = 0;
|
||||
static int warning = 0;
|
||||
static int debug = 0;
|
||||
|
||||
static void interpret_filename(const char *file)
|
||||
{
|
||||
struct alisp_cfg cfg;
|
||||
snd_input_t *in;
|
||||
snd_output_t *out;
|
||||
int err;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
if (file != NULL && strcmp(file, "-") != 0) {
|
||||
if ((err = snd_input_stdio_open(&in, file, "r")) < 0) {
|
||||
fprintf(stderr, "unable to open filename '%s' (%s)\n", file, snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((err = snd_input_stdio_attach(&in, stdin, 0)) < 0) {
|
||||
fprintf(stderr, "unable to attach stdin '%s' (%s)\n", file, snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (snd_output_stdio_attach(&out, stdout, 0) < 0) {
|
||||
snd_input_close(in);
|
||||
fprintf(stderr, "unable to attach stdout (%s)\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
cfg.verbose = verbose;
|
||||
cfg.warning = warning;
|
||||
cfg.debug = debug;
|
||||
cfg.in = in;
|
||||
cfg.out = cfg.eout = cfg.vout = cfg.wout = cfg.dout = out;
|
||||
err = alsa_lisp(&cfg, NULL);
|
||||
if (err < 0)
|
||||
fprintf(stderr, "alsa lisp returned error %i (%s)\n", err, strerror(err));
|
||||
else if (verbose)
|
||||
printf("file %s passed ok via alsa lisp interpreter\n", file);
|
||||
snd_output_close(out);
|
||||
snd_input_close(in);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: alsalisp [-vdw] [file...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "vdw")) != -1) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'w':
|
||||
warning = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1)
|
||||
interpret_filename(NULL);
|
||||
else
|
||||
while (*argv)
|
||||
interpret_filename(*argv++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
(setq card (Acall 'card_next -1))
|
||||
(setq card (Aresult card))
|
||||
(while (>= card 0)
|
||||
(progn
|
||||
(princ "found card: " card "\n")
|
||||
(princ " name : " (Aresult (Acall 'card_get_name card)) "\n")
|
||||
(princ " longname: " (Aresult (Acall 'card_get_longname card)) "\n")
|
||||
(setq card (Acall 'card_next card))
|
||||
(setq card (Aresult card))
|
||||
)
|
||||
)
|
||||
(unsetq card)
|
||||
|
||||
(princ "card_get_index test (SI7018): " (Acall 'card_get_index "SI7018") "\n")
|
||||
(princ "card_get_index test (ABCD): " (Acall 'card_get_index "ABCD") "\n")
|
||||
|
||||
(setq hctl (Acall 'hctl_open 'default nil))
|
||||
(if (= (Aerror hctl) 0)
|
||||
(progn
|
||||
(princ "open success: " hctl "\n")
|
||||
(setq hctl (Ahandle hctl))
|
||||
(princ "open hctl: " hctl "\n")
|
||||
(setq hctl (Acall 'hctl_close hctl))
|
||||
(if (= hctl 0)
|
||||
(princ "close success\n")
|
||||
(princ "close failed: " hctl "\n")
|
||||
)
|
||||
)
|
||||
(progn
|
||||
(princ "open failed: " hctl "\n")
|
||||
)
|
||||
)
|
||||
(unsetq hctl)
|
||||
|
||||
(setq ctl (Acall 'ctl_open 'default nil))
|
||||
(if (= (Aerror ctl) 0)
|
||||
(progn
|
||||
(princ "ctl open success: " ctl "\n")
|
||||
(setq ctl (Ahandle ctl))
|
||||
(setq info (Aresult (Acall 'ctl_card_info ctl)))
|
||||
(princ "ctl card info: " info "\n")
|
||||
(princ "ctl card info (mixername): " (cdr (assq "mixername" info)) "\n")
|
||||
(unsetq info)
|
||||
(setq hctl (Acall 'hctl_open_ctl ctl))
|
||||
(if (= (Aerror hctl) 0)
|
||||
(progn
|
||||
(princ "hctl open success: " hctl "\n")
|
||||
(setq hctl (Ahandle hctl))
|
||||
(princ "open hctl: " hctl "\n")
|
||||
(princ "load hctl: " (Acall 'hctl_load hctl) "\n")
|
||||
(princ "first : " (Acall 'hctl_first_elem hctl) "\n")
|
||||
(princ "last : " (Acall 'hctl_last_elem hctl) "\n")
|
||||
(princ "next (first): " (Acall 'hctl_elem_next (Acall 'hctl_first_elem hctl)) "\n")
|
||||
(princ "prev (last) : " (Acall 'hctl_elem_prev (Acall 'hctl_last_elem hctl)) "\n")
|
||||
(setq elem (Acall 'hctl_first_elem hctl))
|
||||
(while elem
|
||||
(progn
|
||||
(setq info (Acall 'hctl_elem_info elem))
|
||||
(princ info "\n")
|
||||
(setq value (Acall 'hctl_elem_read elem))
|
||||
(princ value "\n")
|
||||
(when (equal (cdr (assq "name" (car (cdr (assq "id" (Aresult info)))))) "Master Playback Volume")
|
||||
(princ "write Master: " (Acall 'hctl_elem_write elem (20 20)) "\n")
|
||||
)
|
||||
(unsetq info value)
|
||||
(gc)
|
||||
(setq elem (Acall 'hctl_elem_next elem))
|
||||
)
|
||||
)
|
||||
(unsetq elem)
|
||||
(setq hctl (Acall 'hctl_close hctl))
|
||||
(if (= hctl 0)
|
||||
(princ "hctl close success\n")
|
||||
(princ "hctl close failed: " hctl "\n")
|
||||
)
|
||||
)
|
||||
(progn
|
||||
(princ "hctl open failed: " hctl "\n")
|
||||
(Acall 'ctl_close ctl)
|
||||
)
|
||||
)
|
||||
(unsetq hctl)
|
||||
)
|
||||
(progn
|
||||
(princ "ctl open failed: " ctl "\n")
|
||||
)
|
||||
)
|
||||
(unsetq ctl)
|
||||
|
||||
(&stat-memory)
|
||||
(&dump-memory "memory.dump")
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
(princ "Hello ALSA world\n")
|
||||
(princ "One " 1 "\n")
|
||||
(princ "Two " (+ 1 1) "\n")
|
||||
|
||||
(defun myprinc (o) (progn (princ o)))
|
||||
(myprinc "Printed via myprinc function!\n")
|
||||
(unsetq myprinc)
|
||||
|
||||
(defun printnum (from to) (while (<= from to) (princ " " from) (setq from (+ from 1))))
|
||||
(princ "Numbers 1-10: ") (printnum 1 10) (princ "\n")
|
||||
(unsetq printnum)
|
||||
|
||||
(defun factorial (n) (if (> n 1) (* n (factorial (- n 1))) 1))
|
||||
(princ "Factorial of 10: " (factorial 10) "\n")
|
||||
(princ "Float test 1.1 + 1.35 = " (+ 1.1 1.35) "\n")
|
||||
(princ "Factorial of 10.0: " (factorial 10.0) "\n")
|
||||
(princ "Factorial of 20.0: " (factorial 20.0) "\n")
|
||||
(unsetq factorial)
|
||||
|
||||
(setq alist '((one . first) (two . second) (three . third)))
|
||||
(princ "alist = " alist "\n")
|
||||
(princ "alist assoc one = " (assoc 'one alist) "\n")
|
||||
(princ "alist rassoc third = " (rassoc 'third alist) "\n")
|
||||
(unsetq alist)
|
||||
|
||||
(&stat-memory)
|
||||
|
|
@ -1 +0,0 @@
|
|||
(princ "itest.lisp file included!\n")
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
;
|
||||
; Test code for all basic alsa lisp commands.
|
||||
; The test is indended to find memory leaks.
|
||||
;
|
||||
; Copyright (c) 2003 Jaroslav Kysela <perex@perex.cz>
|
||||
; License: GPL v2 (http://www.gnu.org/licenses/gpl.html)
|
||||
;
|
||||
|
||||
;
|
||||
; Basic commands
|
||||
;
|
||||
|
||||
(!=) (&check-memory)
|
||||
(!= 0) (&check-memory)
|
||||
(!= 0 1) (&check-memory)
|
||||
(!= 1 1) (&check-memory)
|
||||
(!= 0 1 2) (&check-memory)
|
||||
(!= 'aaaa 'bbbb) (&check-memory)
|
||||
|
||||
(%) (&check-memory)
|
||||
(% 11) (&check-memory)
|
||||
(% 11 5) (&check-memory)
|
||||
(% 11.5 5.1) (&check-memory)
|
||||
(% 11.5 5.1 2.2) (&check-memory)
|
||||
(% 'aaaa 'bbbb) (&check-memory)
|
||||
|
||||
(&check-memory) (&check-memory)
|
||||
(&check-memory "abcd") (&check-memory)
|
||||
(&dump-memory "-") (&check-memory)
|
||||
(&dump-memory) (&check-memory)
|
||||
(&dump-objects "-") (&check-memory)
|
||||
(&dump-objects) (&check-memory)
|
||||
(&stat-memory) (&check-memory)
|
||||
(&stat-memory "abcd") (&check-memory)
|
||||
|
||||
(*) (&check-memory)
|
||||
(* 1) (&check-memory)
|
||||
(* 1 2) (&check-memory)
|
||||
(* 1.1 2.2) (&check-memory)
|
||||
(* 1.1 2.2 3.3) (&check-memory)
|
||||
(* 'aaaa) (&check-memory)
|
||||
|
||||
(+) (&check-memory)
|
||||
(+ 1) (&check-memory)
|
||||
(+ 1 2) (&check-memory)
|
||||
(+ 1.1 2.2) (&check-memory)
|
||||
(+ 1.1 2.2 3.3) (&check-memory)
|
||||
(+ 'aaaa) (&check-memory)
|
||||
(+ 'aaaa 'bbbb) (&check-memory)
|
||||
(+ "aaaa") (&check-memory)
|
||||
(+ "aaaa" "bbbb") (&check-memory)
|
||||
(+ "aaaa" "bbbb" "cccc") (&check-memory)
|
||||
|
||||
(-) (&check-memory)
|
||||
(- 1) (&check-memory)
|
||||
(- 1 2) (&check-memory)
|
||||
(- 1.1 2.2) (&check-memory)
|
||||
(- 1.1 2.2 3.3) (&check-memory)
|
||||
(- 'aaaa) (&check-memory)
|
||||
(- 'aaaa 'bbbb) (&check-memory)
|
||||
|
||||
(/) (&check-memory)
|
||||
(/ 1) (&check-memory)
|
||||
(/ 1 2) (&check-memory)
|
||||
(/ 1.1 2.2) (&check-memory)
|
||||
(/ 1.1 2.2 3.3) (&check-memory)
|
||||
(/ 'aaaa) (&check-memory)
|
||||
(/ 'aaaa 'bbbb) (&check-memory)
|
||||
|
||||
(<) (&check-memory)
|
||||
(< 0) (&check-memory)
|
||||
(< 0 1) (&check-memory)
|
||||
(< 1 0) (&check-memory)
|
||||
(< 0 1 2) (&check-memory)
|
||||
|
||||
(<=) (&check-memory)
|
||||
(<= 0) (&check-memory)
|
||||
(<= 0 1) (&check-memory)
|
||||
(<= 1 0) (&check-memory)
|
||||
(<= 0 1 2) (&check-memory)
|
||||
|
||||
(=) (&check-memory)
|
||||
(= 0) (&check-memory)
|
||||
(= 0 1) (&check-memory)
|
||||
(= 1 1) (&check-memory)
|
||||
(= 0 1 2) (&check-memory)
|
||||
|
||||
(>) (&check-memory)
|
||||
(> 0) (&check-memory)
|
||||
(> 0 1) (&check-memory)
|
||||
(> 1 0) (&check-memory)
|
||||
(> 0 1 2) (&check-memory)
|
||||
|
||||
(>= 0) (&check-memory)
|
||||
(>= 0 1) (&check-memory)
|
||||
(>= 1 0) (&check-memory)
|
||||
(>= 0 1 2) (&check-memory)
|
||||
|
||||
(and) (&check-memory)
|
||||
(and 0) (&check-memory)
|
||||
(and 1) (&check-memory)
|
||||
(and 0 0 0) (&check-memory)
|
||||
|
||||
(quote a) (&check-memory)
|
||||
|
||||
(assoc) (&check-memory)
|
||||
(assoc 'one) (&check-memory)
|
||||
(assoc 'one '((one . first))) (&check-memory)
|
||||
(assoc 'one '((two . second))) (&check-memory)
|
||||
(assoc 'one '((one . first) (two . second))) (&check-memory)
|
||||
|
||||
(assq) (&check-memory)
|
||||
(assq 'one) (&check-memory)
|
||||
(assq "one" '(("one" . "first"))) (&check-memory)
|
||||
(assq "one" '(("two" . "second"))) (&check-memory)
|
||||
(assq "one" '(("one" . "first") ("two" . "second"))) (&check-memory)
|
||||
|
||||
(atom) (&check-memory)
|
||||
(atom 'one) (&check-memory)
|
||||
(atom "one") (&check-memory)
|
||||
(atom "one" 'two) (&check-memory)
|
||||
|
||||
(funcall) (&check-memory)
|
||||
|
||||
(car) (&check-memory)
|
||||
(car '(one . two)) (&check-memory)
|
||||
|
||||
(cdr) (&check-memory)
|
||||
(cdr '(one . two)) (&check-memory)
|
||||
|
||||
(concat) (&check-memory)
|
||||
(concat 'aaaa) (&check-memory)
|
||||
(concat 'aaaa 'bbbb) (&check-memory)
|
||||
(concat "aaaa") (&check-memory)
|
||||
(concat "aaaa" "bbbb") (&check-memory)
|
||||
(concat "aaaa" "bbbb" "cccc") (&check-memory)
|
||||
|
||||
(cond) (&check-memory)
|
||||
(cond 0) (&check-memory)
|
||||
(cond 0 1) (&check-memory)
|
||||
(cond 0 1 2) (&check-memory)
|
||||
(cond 0 1 2 3) (&check-memory)
|
||||
(cond (0 'a) (1 'b) (0 'd)) (&check-memory)
|
||||
(cond 1) (&check-memory)
|
||||
(cond 1 1) (&check-memory)
|
||||
(cond 1 1 2) (&check-memory)
|
||||
(cond 1 1 2 3) (&check-memory)
|
||||
|
||||
(cons) (&check-memory)
|
||||
(cons "a") (&check-memory)
|
||||
(cons "a" "b") (&check-memory)
|
||||
(cons "a" "b" "c") (&check-memory)
|
||||
|
||||
(eq) (&check-memory)
|
||||
(eq 1) (&check-memory)
|
||||
(eq 0 0) (&check-memory)
|
||||
(eq "a" "b") (&check-memory)
|
||||
(eq "a" "b" "c") (&check-memory)
|
||||
|
||||
(equal) (&check-memory)
|
||||
(equal 1) (&check-memory)
|
||||
(equal 0 0) (&check-memory)
|
||||
(equal "a" "b") (&check-memory)
|
||||
(equal "a" "b" "c") (&check-memory)
|
||||
|
||||
(exfun) (&check-memory)
|
||||
(exfun 'abcd) (&check-memory)
|
||||
(exfun 'abcd 'ijkl) (&check-memory)
|
||||
|
||||
(format) (&check-memory)
|
||||
(format 1) (&check-memory)
|
||||
(format 'a) (&check-memory)
|
||||
(format "a" "b" "c") (&check-memory)
|
||||
(format "1.2") (&check-memory)
|
||||
(format "%c" 43) (&check-memory)
|
||||
(format "%d" 12) (&check-memory)
|
||||
(format "%i" 12) (&check-memory)
|
||||
(format "%f" 12.1) (&check-memory)
|
||||
(format "%s" "abcd") (&check-memory)
|
||||
(format "%s %i %i" "abcd" 1 2) (&check-memory)
|
||||
|
||||
(garbage-collect) (&check-memory)
|
||||
(gc) (&check-memory)
|
||||
|
||||
(if) (&check-memory)
|
||||
(if t) (&check-memory)
|
||||
(if t 'a) (&check-memory)
|
||||
(if t 'a 'b) (&check-memory)
|
||||
(if nil) (&check-memory)
|
||||
(if nil 'a) (&check-memory)
|
||||
(if nil 'a 'b) (&check-memory)
|
||||
|
||||
(include "itest.lisp") (&check-memory)
|
||||
|
||||
(list) (&check-memory)
|
||||
(list "a") (&check-memory)
|
||||
(list "a" "b") (&check-memory)
|
||||
(list "a" "b" "c") (&check-memory)
|
||||
|
||||
(not) (&check-memory)
|
||||
(not 0) (&check-memory)
|
||||
(not nil) (&check-memory)
|
||||
(not t) (&check-memory)
|
||||
(not 'a) (&check-memory)
|
||||
(not 'a 'b 'c 'd) (&check-memory)
|
||||
|
||||
(nth) (&check-memory)
|
||||
(nth 2) (&check-memory)
|
||||
(nth 2 nil) (&check-memory)
|
||||
(nth 2 '(('one 'two 'three))) (&check-memory)
|
||||
|
||||
(null) (&check-memory)
|
||||
(null 0) (&check-memory)
|
||||
(null nil) (&check-memory)
|
||||
(null t) (&check-memory)
|
||||
(null 'a) (&check-memory)
|
||||
(null 'a 'b 'c 'd) (&check-memory)
|
||||
|
||||
(or) (&check-memory)
|
||||
(or 0) (&check-memory)
|
||||
(or 1) (&check-memory)
|
||||
(or 0 0 0) (&check-memory)
|
||||
|
||||
(path) (&check-memory)
|
||||
(path 0) (&check-memory)
|
||||
(path 1) (&check-memory)
|
||||
(path 0 0 0) (&check-memory)
|
||||
(path "data") (&check-memory)
|
||||
|
||||
(princ) (&check-memory)
|
||||
(princ "\nabcd\n") (&check-memory)
|
||||
(princ "a" "b" "c\n") (&check-memory)
|
||||
|
||||
(prog1) (&check-memory)
|
||||
(prog1 1) (&check-memory)
|
||||
(prog1 1 2 3 4) (&check-memory)
|
||||
|
||||
(prog2) (&check-memory)
|
||||
(prog2 1) (&check-memory)
|
||||
(prog2 1 2 3 4) (&check-memory)
|
||||
|
||||
(progn) (&check-memory)
|
||||
(progn 1) (&check-memory)
|
||||
(progn 1 2 3 4) (&check-memory)
|
||||
|
||||
(quote) (&check-memory)
|
||||
(quote a) (&check-memory)
|
||||
|
||||
(rassoc) (&check-memory)
|
||||
(rassoc 'first) (&check-memory)
|
||||
(rassoc 'first '((one . first))) (&check-memory)
|
||||
(rassoc 'first '((two . second))) (&check-memory)
|
||||
(rassoc 'first '((one . first) (two . second))) (&check-memory)
|
||||
|
||||
(rassq) (&check-memory)
|
||||
(rassq "first") (&check-memory)
|
||||
(rassq "first" '(("one" . "first"))) (&check-memory)
|
||||
(rassq "first" '(("two" . "second"))) (&check-memory)
|
||||
(rassq "first" '(("one" . "first") ("two" . "second"))) (&check-memory)
|
||||
|
||||
(set) (&check-memory)
|
||||
(set "a") (unset "a") (&check-memory)
|
||||
(set "a" 1) (unset "a") (&check-memory)
|
||||
(set a 1) (unset a) (&check-memory)
|
||||
(set "a" 1 2) (unset "a") (&check-memory)
|
||||
|
||||
(setf) (&check-memory)
|
||||
(setf a) (unsetf a) (&check-memory)
|
||||
(setf a 1) (unsetf a) (&check-memory)
|
||||
(setf a 1 2) (unsetf a) (&check-memory)
|
||||
|
||||
(setq) (&check-memory)
|
||||
(setq a) (unsetq a) (&check-memory)
|
||||
(setq a 1) (unsetq a) (&check-memory)
|
||||
(setq a 1 2) (unsetq a) (&check-memory)
|
||||
|
||||
(string-equal) (&check-memory)
|
||||
(string-equal 1) (&check-memory)
|
||||
(string-equal "a") (&check-memory)
|
||||
(string-equal "a" "a") (&check-memory)
|
||||
(string-equal "a" "b") (&check-memory)
|
||||
(string-equal "a" "b" "c") (&check-memory)
|
||||
|
||||
(string-to-integer) (&check-memory)
|
||||
(string-to-integer 1) (&check-memory)
|
||||
(string-to-integer 1.5) (&check-memory)
|
||||
(string-to-integer "a") (&check-memory)
|
||||
(string-to-integer "a" "a") (&check-memory)
|
||||
(string-to-integer "a" "b") (&check-memory)
|
||||
(string-to-integer "a" "b" "c") (&check-memory)
|
||||
|
||||
(string-to-float) (&check-memory)
|
||||
(string-to-float 1) (&check-memory)
|
||||
(string-to-float 1.5) (&check-memory)
|
||||
(string-to-float "a") (&check-memory)
|
||||
(string-to-float "a" "a") (&check-memory)
|
||||
(string-to-float "a" "b") (&check-memory)
|
||||
(string-to-float "a" "b" "c") (&check-memory)
|
||||
|
||||
(string=) (&check-memory)
|
||||
(string= 1) (&check-memory)
|
||||
(string= "a") (&check-memory)
|
||||
(string= "a" "a") (&check-memory)
|
||||
(string= "a" "b") (&check-memory)
|
||||
(string= "a" "b" "c") (&check-memory)
|
||||
|
||||
(unless) (&check-memory)
|
||||
(unless 1) (&check-memory)
|
||||
(unless 0 1 2) (&check-memory)
|
||||
(unless t 2 3 4) (&check-memory)
|
||||
(unless nil 2 3 4) (&check-memory)
|
||||
|
||||
(unset) (&check-memory)
|
||||
(unset "a") (&check-memory)
|
||||
|
||||
(unsetf) (&check-memory)
|
||||
(unsetf a) (&check-memory)
|
||||
(unsetf a b) (&check-memory)
|
||||
|
||||
(unsetq) (&check-memory)
|
||||
(unsetq a) (&check-memory)
|
||||
(unsetq a b) (&check-memory)
|
||||
|
||||
(when) (&check-memory)
|
||||
(when 0) (&check-memory)
|
||||
(when 0 1) (&check-memory)
|
||||
(when t 1) (&check-memory)
|
||||
(when nil 1) (&check-memory)
|
||||
|
||||
(while) (&check-memory)
|
||||
(while nil) (&check-memory)
|
||||
(while nil 1) (&check-memory)
|
||||
(while nil 1 2 3 4) (&check-memory)
|
||||
|
||||
;
|
||||
; more complex command sequences
|
||||
;
|
||||
|
||||
(setq abcd "abcd")
|
||||
(unsetq abcd)
|
||||
(&check-memory)
|
||||
|
||||
(setq abcd (("abcd" . "efgh") ("1234" . "5678")))
|
||||
(unsetq abcd)
|
||||
(&check-memory)
|
||||
|
||||
(defun myfun () (princ "a\n"))
|
||||
(exfun 'myfun)
|
||||
(unsetq myfun)
|
||||
(&check-memory)
|
||||
|
||||
(defun myfun () (princ "a\n"))
|
||||
(funcall 'myfun)
|
||||
(funcall 'myfun 'aaaaa)
|
||||
(unsetq myfun)
|
||||
(&check-memory)
|
||||
|
||||
(defun myfun (o) (princ o "a\n"))
|
||||
(funcall 'myfun)
|
||||
(funcall 'myfun 'aaaaa)
|
||||
(unsetq myfun)
|
||||
(&check-memory)
|
||||
|
||||
(defun myfun (o p) (princ o p "\n"))
|
||||
(funcall 'myfun)
|
||||
(funcall 'myfun 'aaaaa)
|
||||
(funcall 'myfun 'aaaaa 'bbbbb)
|
||||
(unsetq myfun)
|
||||
(&check-memory)
|
||||
|
||||
(defun printnum (from to) (while (<= from to) (princ " " from) (setq from (+ from 1))))
|
||||
(princ "Numbers 1-10:") (printnum 1 10) (princ "\n")
|
||||
(unsetq printnum)
|
||||
|
||||
;
|
||||
; game over
|
||||
;
|
||||
|
||||
(princ "*********************\n")
|
||||
(princ "OK, all tests passed!\n")
|
||||
(princ "*********************\n")
|
||||
(&stat-memory)
|
||||
28
configure.ac
28
configure.ac
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(alsa-lib, 1.2.12)
|
||||
AC_INIT(alsa-lib, 1.2.14)
|
||||
|
||||
AC_CONFIG_SRCDIR([src/control/control.c])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
|
@ -71,6 +71,15 @@ EOF
|
|||
exit 1
|
||||
fi
|
||||
|
||||
dnl Do not use --with-pic for shared libraries (consider to use PIE)
|
||||
if test "$enable_static" = "yes" -a "$pic_mode" = "yes"; then
|
||||
cat <<EOF
|
||||
Please, do not enable PIC (--with-pic) for static library. Consider
|
||||
to remove this option or use PIE flags.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dnl ALSA configuration directory
|
||||
AC_ARG_WITH(configdir,
|
||||
AS_HELP_STRING([--with-configdir=dir],
|
||||
|
|
@ -410,10 +419,6 @@ AC_ARG_ENABLE(ucm,
|
|||
AC_ARG_ENABLE(topology,
|
||||
AS_HELP_STRING([--disable-topology], [disable the DSP topology component]),
|
||||
[build_topology="$enableval"], [build_topology="yes"])
|
||||
AC_ARG_ENABLE(alisp,
|
||||
AS_HELP_STRING([--enable-alisp], [enable the alisp component]),
|
||||
[build_alisp="$enableval"], [build_alisp="no"])
|
||||
test "$softfloat" = "yes" && build_alisp="no"
|
||||
AC_ARG_ENABLE(old-symbols,
|
||||
AS_HELP_STRING([--disable-old-symbols], [disable old obsoleted symbols]),
|
||||
[keep_old_symbols="$enableval"], [keep_old_symbols="yes"])
|
||||
|
|
@ -474,6 +479,12 @@ fi
|
|||
AC_SUBST(PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_INCLUDES)
|
||||
|
||||
if test "$build_rawmidi" != "yes"; then
|
||||
if test "$build_seq" = "yes"; then
|
||||
AC_ERROR([Cannot enable sequencer without rawmidi])
|
||||
fi
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([BUILD_MIXER], [test x$build_mixer = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM], [test x$build_pcm = xyes])
|
||||
AM_CONDITIONAL([BUILD_RAWMIDI], [test x$build_rawmidi = xyes])
|
||||
|
|
@ -481,7 +492,6 @@ AM_CONDITIONAL([BUILD_HWDEP], [test x$build_hwdep = xyes])
|
|||
AM_CONDITIONAL([BUILD_SEQ], [test x$build_seq = xyes])
|
||||
AM_CONDITIONAL([BUILD_UCM], [test x$build_ucm = xyes])
|
||||
AM_CONDITIONAL([BUILD_TOPOLOGY], [test x$build_topology = xyes])
|
||||
AM_CONDITIONAL([BUILD_ALISP], [test x$build_alisp = xyes])
|
||||
AM_CONDITIONAL([BUILD_MIXER_MODULES], [test x$build_mixer_modules = xyes])
|
||||
AM_CONDITIONAL([BUILD_MIXER_PYMODULES], [test x$build_mixer_pymodules = xyes])
|
||||
|
||||
|
|
@ -619,6 +629,7 @@ AM_CONDITIONAL([BUILD_PCM_PLUGIN_DSNOOP], [test x$build_pcm_dsnoop = xyes])
|
|||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_ASYM], [test x$build_pcm_asym = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_IEC958], [test x$build_pcm_iec958 = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_SOFTVOL], [test x$build_pcm_softvol = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_EXTERNAL], [test x$build_pcm_extplug = xyes -o x$build_pcm_ioplug = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_EXTPLUG], [test x$build_pcm_extplug = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_IOPLUG], [test x$build_pcm_ioplug = xyes])
|
||||
AM_CONDITIONAL([BUILD_PCM_PLUGIN_MMAP_EMUL], [test x$build_pcm_mmap_emul = xyes])
|
||||
|
|
@ -757,13 +768,13 @@ AC_CONFIG_FILES(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
|
|||
src/pcm/Makefile src/pcm/scopes/Makefile \
|
||||
src/rawmidi/Makefile src/timer/Makefile \
|
||||
src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
|
||||
src/alisp/Makefile src/topology/Makefile \
|
||||
src/topology/Makefile \
|
||||
src/conf/Makefile \
|
||||
src/conf/cards/Makefile \
|
||||
src/conf/ctl/Makefile \
|
||||
src/conf/pcm/Makefile \
|
||||
modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
|
||||
alsalisp/Makefile aserver/Makefile \
|
||||
aserver/Makefile \
|
||||
test/Makefile test/lsb/Makefile \
|
||||
utils/Makefile utils/alsa-lib.spec utils/alsa.pc utils/alsa-topology.pc)
|
||||
|
||||
|
|
@ -811,6 +822,7 @@ test "$build_pcm" = "yes" && echo "#include <alsa/timer.h>" >> include/asoundlib
|
|||
test "$build_hwdep" = "yes" && echo "#include <alsa/hwdep.h>" >> include/asoundlib.h
|
||||
echo "#include <alsa/control.h>" >> include/asoundlib.h
|
||||
test "$build_mixer" = "yes" && echo "#include <alsa/mixer.h>" >> include/asoundlib.h
|
||||
test "$build_seq" = "yes" && echo "#include <alsa/ump_msg.h>" >> include/asoundlib.h
|
||||
test "$build_seq" = "yes" && echo "#include <alsa/seq_event.h>" >> include/asoundlib.h
|
||||
test "$build_seq" = "yes" && echo "#include <alsa/seq.h>" >> include/asoundlib.h
|
||||
test "$build_seq" = "yes" && echo "#include <alsa/seqmid.h>" >> include/asoundlib.h
|
||||
|
|
|
|||
|
|
@ -9,14 +9,16 @@ doc:
|
|||
doxygen doxygen.cfg
|
||||
|
||||
doc-pack: doc
|
||||
-chmod a+r $(top_srcdir)/doc/doxygen/html/*
|
||||
-chmod a-w $(top_srcdir)/doc/doxygen/html/*
|
||||
-chmod -R a+r $(top_srcdir)/doc/doxygen/html/*
|
||||
-chmod -R a-w $(top_srcdir)/doc/doxygen/html/*
|
||||
if ! test -z "$(AMTAR)"; then \
|
||||
$(AMTAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \
|
||||
else \
|
||||
$(TAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \
|
||||
fi
|
||||
-chmod -R u+w $(top_srcdir)/doc/doxygen/html/*
|
||||
rm -rf $(top_srcdir)/doc/doxygen/html/*
|
||||
|
||||
doc-clean:
|
||||
-chmod -R u+w $(top_srcdir)/doc/doxygen/html/*
|
||||
rm -rf $(top_srcdir)/doc/doxygen/html/*
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ INPUT = @top_srcdir@/doc/index.doxygen \
|
|||
@top_srcdir@/include/control.h \
|
||||
@top_srcdir@/include/pcm.h \
|
||||
@top_srcdir@/include/rawmidi.h \
|
||||
@top_srcdir@/include/ump.h \
|
||||
@top_srcdir@/include/ump_msg.h \
|
||||
@top_srcdir@/include/timer.h \
|
||||
@top_srcdir@/include/hwdep.h \
|
||||
@top_srcdir@/include/seq.h \
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ set -e
|
|||
bits32=
|
||||
cbits32=
|
||||
modules=
|
||||
alisp=
|
||||
lto=
|
||||
if [ $# -ne 0 ]; then
|
||||
endloop=
|
||||
|
|
@ -20,10 +19,6 @@ if [ $# -ne 0 ]; then
|
|||
modules=yes
|
||||
echo "Forced mixer modules build..."
|
||||
shift ;;
|
||||
alisp)
|
||||
alisp=yes
|
||||
echo "Forced alisp code build..."
|
||||
shift ;;
|
||||
python2)
|
||||
python2=yes
|
||||
echo "Forced python2 interpreter build..."
|
||||
|
|
@ -71,10 +66,6 @@ if [ "$modules" = "yes" ]; then
|
|||
args="$args --enable-mixer-pymods"
|
||||
fi
|
||||
|
||||
if [ "$alisp" = "yes" ]; then
|
||||
args="$args --enable-alisp"
|
||||
fi
|
||||
|
||||
if [ "$python2" = "yes" ]; then
|
||||
args="$args --enable-python2"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -22,15 +22,16 @@ endif
|
|||
if BUILD_PCM_PLUGIN_RATE
|
||||
alsainclude_HEADERS += pcm_rate.h
|
||||
endif
|
||||
if BUILD_PCM_PLUGIN_EXTPLUG
|
||||
alsainclude_HEADERS += pcm_external.h pcm_extplug.h
|
||||
endif
|
||||
if BUILD_PCM_PLUGIN_IOPLUG
|
||||
if !BUILD_PCM_PLUGIN_EXTPLUG
|
||||
alsainclude_HEADERS += pcm_external.h
|
||||
endif
|
||||
alsainclude_HEADERS += pcm_ioplug.h
|
||||
if BUILD_PCM_PLUGIN_EXTERNAL
|
||||
# FIXME: pcm_external.h includes both pcm_extplug.h and pcm_ioplug.h
|
||||
alsainclude_HEADERS += pcm_external.h pcm_extplug.h pcm_ioplug.h
|
||||
endif
|
||||
#if BUILD_PCM_PLUGIN_EXTPLUG
|
||||
#alsainclude_HEADERS += pcm_extplug.h
|
||||
#endif
|
||||
#if BUILD_PCM_PLUGIN_IOPLUG
|
||||
#alsainclude_HEADERS += pcm_ioplug.h
|
||||
#endif
|
||||
endif
|
||||
|
||||
if BUILD_RAWMIDI
|
||||
|
|
@ -57,10 +58,6 @@ if BUILD_TOPOLOGY
|
|||
alsainclude_HEADERS += topology.h
|
||||
endif
|
||||
|
||||
if BUILD_ALISP
|
||||
alsainclude_HEADERS += alisp.h
|
||||
endif
|
||||
|
||||
noinst_HEADERS = alsa sys.h search.h list.h aserver.h local.h alsa-symbols.h \
|
||||
asoundlib-head.h asoundlib-tail.h bswap.h type_compat.h
|
||||
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* ALSA lisp implementation
|
||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@perex.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
struct alisp_cfg {
|
||||
int verbose: 1,
|
||||
warning: 1,
|
||||
debug: 1;
|
||||
snd_input_t *in; /* program code */
|
||||
snd_output_t *out; /* program output */
|
||||
snd_output_t *eout; /* error output */
|
||||
snd_output_t *vout; /* verbose output */
|
||||
snd_output_t *wout; /* warning output */
|
||||
snd_output_t *dout; /* debug output */
|
||||
};
|
||||
|
||||
struct alisp_instance;
|
||||
struct alisp_object;
|
||||
struct alisp_seq_iterator;
|
||||
|
||||
struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input);
|
||||
void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg);
|
||||
int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **instance);
|
||||
void alsa_lisp_free(struct alisp_instance *instance);
|
||||
int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result,
|
||||
const char *id, const char *args, ...)
|
||||
#ifndef DOC_HIDDEN
|
||||
__attribute__ ((format (printf, 4, 5)))
|
||||
#endif
|
||||
;
|
||||
void alsa_lisp_result_free(struct alisp_instance *instance,
|
||||
struct alisp_seq_iterator *result);
|
||||
int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id,
|
||||
struct alisp_seq_iterator **seq);
|
||||
int alsa_lisp_seq_next(struct alisp_seq_iterator **seq);
|
||||
int alsa_lisp_seq_count(struct alisp_seq_iterator *seq);
|
||||
int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val);
|
||||
int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr);
|
||||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/asoundef.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_ASOUNDEF_H
|
||||
#define __ALSA_ASOUNDEF_H
|
||||
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@
|
|||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_CONF_H
|
||||
#define __ALSA_CONF_H
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/control.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_CONTROL_H
|
||||
#define __ALSA_CONTROL_H
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,13 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ALSA_CONTROL_EXTERNAL_H
|
||||
#define __ALSA_CONTROL_EXTERNAL_H
|
||||
|
||||
#include "control.h"
|
||||
#ifndef __ASOUNDLIB_LOCAL
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/error.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_ERROR_H
|
||||
#define __ALSA_ERROR_H
|
||||
|
||||
|
|
@ -40,7 +46,6 @@ extern "C" {
|
|||
|
||||
#define SND_ERROR_BEGIN 500000 /**< Lower boundary of sound error codes. */
|
||||
#define SND_ERROR_INCOMPATIBLE_VERSION (SND_ERROR_BEGIN+0) /**< Kernel/library protocols are not compatible. */
|
||||
#define SND_ERROR_ALISP_NIL (SND_ERROR_BEGIN+1) /**< Lisp encountered an error during acall. */
|
||||
|
||||
const char *snd_strerror(int errnum);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,12 +25,15 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/global.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_GLOBAL_H_
|
||||
#define __ALSA_GLOBAL_H_
|
||||
|
||||
/* for timeval and timespec */
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/hwdep.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_HWDEP_H
|
||||
#define __ALSA_HWDEP_H
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/input.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_INPUT_H
|
||||
#define __ALSA_INPUT_H
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
/* for timeval and timespec */
|
||||
#include <time.h>
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#elif defined(HAVE_SYS_ENDIAN_H)
|
||||
|
|
@ -187,6 +190,7 @@
|
|||
#include "hwdep.h"
|
||||
#include "control.h"
|
||||
#include "mixer.h"
|
||||
#include "ump_msg.h"
|
||||
#include "seq_event.h"
|
||||
#include "seq.h"
|
||||
|
||||
|
|
@ -208,6 +212,7 @@
|
|||
#define snd_seq_result sndrv_seq_result
|
||||
#define snd_seq_queue_skew sndrv_seq_queue_skew
|
||||
#define snd_seq_ev_queue_control sndrv_seq_ev_queue_control
|
||||
#define snd_seq_ev_ump_notify sndrv_seq_ev_ump_notify
|
||||
#define snd_seq_client_t sndrv_seq_client_t
|
||||
#define snd_seq_client_type_t sndrv_seq_client_type_t
|
||||
|
||||
|
|
@ -262,6 +267,7 @@ int _snd_safe_strtod(const char *str, double *val);
|
|||
int snd_send_fd(int sock, void *data, size_t len, int fd);
|
||||
int snd_receive_fd(int sock, void *data, size_t len, int *fd);
|
||||
size_t snd_strlcpy(char *dst, const char *src, size_t size);
|
||||
size_t snd_strlcat(char *dst, const char *src, size_t size);
|
||||
|
||||
/*
|
||||
* error messages
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/mixer.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_MIXER_H
|
||||
#define __ALSA_MIXER_H
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,15 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/input.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_OUTPUT_H
|
||||
#define __ALSA_OUTPUT_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/pcm.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_PCM_H
|
||||
#define __ALSA_PCM_H
|
||||
|
||||
|
|
@ -33,8 +39,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \defgroup PCM PCM Interface
|
||||
* See the \ref pcm page for more details.
|
||||
|
|
@ -508,6 +512,9 @@ typedef union _snd_pcm_sync_id {
|
|||
unsigned int id32[4];
|
||||
} snd_pcm_sync_id_t;
|
||||
|
||||
/** synchronization ID size (see snd_pcm_hw_params_get_sync) */
|
||||
#define SND_PCM_HW_PARAMS_SYNC_SIZE 16
|
||||
|
||||
/** Infinite wait for snd_pcm_wait() */
|
||||
#define SND_PCM_WAIT_INFINITE (-1)
|
||||
/** Wait for next i/o in snd_pcm_wait() */
|
||||
|
|
@ -747,6 +754,7 @@ int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
|
|||
unsigned int *rate_den);
|
||||
int snd_pcm_hw_params_get_sbits(const snd_pcm_hw_params_t *params);
|
||||
int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params);
|
||||
const unsigned char * snd_pcm_hw_params_get_sync(const snd_pcm_hw_params_t *params);
|
||||
|
||||
#if 0
|
||||
typedef struct _snd_pcm_hw_strategy snd_pcm_hw_strategy_t;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@
|
|||
#ifndef __ALSA_PCM_EXTERNAL_H
|
||||
#define __ALSA_PCM_EXTERNAL_H
|
||||
|
||||
#include "pcm.h"
|
||||
#ifndef __ASOUNDLIB_LOCAL
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ALSA_PCM_EXTERNAL_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
#warning "use #include <alsa/pcm_external.h>, <alsa/pcm_extplug.h> should not be used directly"
|
||||
#include <alsa/pcm_external.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_PCM_EXTPLUG_H
|
||||
#define __ALSA_PCM_EXTPLUG_H
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ALSA_PCM_EXTERNAL_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
#warning "use #include <alsa/pcm_external.h>, <alsa/pcm_ioplug.h> should not be used directly"
|
||||
#include <alsa/pcm_external.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_PCM_IOPLUG_H
|
||||
#define __ALSA_PCM_IOPLUG_H
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#error "use #include <alsa/asoundlib.h>, <alsa/pcm_old.h> should not be used directly"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Old ALSA 0.9.x API
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@
|
|||
#ifndef __ALSA_PCM_RATE_H
|
||||
#define __ALSA_PCM_RATE_H
|
||||
|
||||
#ifndef __ASOUNDLIB_LOCAL
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/rawmidi.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_RAWMIDI_H
|
||||
#define __ALSA_RAWMIDI_H
|
||||
|
||||
|
|
@ -94,7 +100,8 @@ typedef enum _snd_rawmidi_read_mode {
|
|||
} snd_rawmidi_read_mode_t;
|
||||
|
||||
/** rawmidi info bit flags */
|
||||
#define SND_RAWMIDI_INFO_UMP 0x00000008 /* rawmidi is UMP */
|
||||
#define SND_RAWMIDI_INFO_UMP 0x00000008 /**< rawmidi is UMP */
|
||||
#define SNDRV_RAWMIDI_INFO_STREAM_INACTIVE 0x00000010 /**< the selected substream is inactive */
|
||||
|
||||
int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
|
||||
const char *name, int mode);
|
||||
|
|
@ -124,6 +131,7 @@ const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *obj);
|
|||
const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *obj);
|
||||
unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *obj);
|
||||
unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *obj);
|
||||
int snd_rawmidi_info_get_tied_device(const snd_rawmidi_info_t *obj);
|
||||
void snd_rawmidi_info_set_device(snd_rawmidi_info_t *obj, unsigned int val);
|
||||
void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *obj, unsigned int val);
|
||||
void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *obj, snd_rawmidi_stream_t val);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/seq.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_SEQ_H
|
||||
#define __ALSA_SEQ_H
|
||||
|
||||
|
|
@ -250,8 +256,8 @@ typedef struct _snd_seq_port_info snd_seq_port_info_t;
|
|||
|
||||
/** port direction */
|
||||
#define SND_SEQ_PORT_DIR_UNKNOWN 0 /**< Unknown */
|
||||
#define SND_SEQ_PORT_DIR_INPUT 1 /**< Input only */
|
||||
#define SND_SEQ_PORT_DIR_OUTPUT 2 /**< Output only */
|
||||
#define SND_SEQ_PORT_DIR_INPUT 1 /**< Input only; sink, receiver */
|
||||
#define SND_SEQ_PORT_DIR_OUTPUT 2 /**< Output only; source, transmitter */
|
||||
#define SND_SEQ_PORT_DIR_BIDIRECTION 3 /**< Input/output bidirectional */
|
||||
|
||||
/* port type */
|
||||
|
|
@ -318,6 +324,7 @@ int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info);
|
|||
int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info);
|
||||
int snd_seq_port_info_get_direction(const snd_seq_port_info_t *info);
|
||||
int snd_seq_port_info_get_ump_group(const snd_seq_port_info_t *info);
|
||||
int snd_seq_port_info_get_ump_is_midi1(const snd_seq_port_info_t *info);
|
||||
|
||||
void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client);
|
||||
void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port);
|
||||
|
|
@ -334,6 +341,7 @@ void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int realtim
|
|||
void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue);
|
||||
void snd_seq_port_info_set_direction(snd_seq_port_info_t *info, int direction);
|
||||
void snd_seq_port_info_set_ump_group(snd_seq_port_info_t *info, int ump_group);
|
||||
void snd_seq_port_info_set_ump_is_midi1(snd_seq_port_info_t *info, int is_midi1);
|
||||
|
||||
int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t *info);
|
||||
int snd_seq_delete_port(snd_seq_t *handle, int port);
|
||||
|
|
@ -506,13 +514,16 @@ unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info);
|
|||
int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info);
|
||||
unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info);
|
||||
unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info);
|
||||
unsigned int snd_seq_queue_tempo_get_tempo_base(const snd_seq_queue_tempo_t *info);
|
||||
void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo);
|
||||
void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq);
|
||||
void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew);
|
||||
void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base);
|
||||
void snd_seq_queue_tempo_set_tempo_base(snd_seq_queue_tempo_t *info, unsigned int tempo_base);
|
||||
|
||||
int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
|
||||
int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
|
||||
int snd_seq_has_queue_tempo_base(snd_seq_t *handle);
|
||||
|
||||
/*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/seq_event.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_SEQ_EVENT_H
|
||||
#define __ALSA_SEQ_EVENT_H
|
||||
|
||||
|
|
@ -133,6 +139,11 @@ enum snd_seq_event_type {
|
|||
/** Ports disconnected; event data type = #snd_seq_connect_t */
|
||||
SND_SEQ_EVENT_PORT_UNSUBSCRIBED,
|
||||
|
||||
/** UMP Endpoint info has changed; event data type = #snd_seq_ev_ump_notify_t */
|
||||
SND_SEQ_EVENT_UMP_EP_CHANGE,
|
||||
/** UMP Block info has changed; event data type = #snd_seq_ev_ump_notify_t */
|
||||
SND_SEQ_EVENT_UMP_BLOCK_CHANGE,
|
||||
|
||||
/** user-defined event; event data type = any (fixed size) */
|
||||
SND_SEQ_EVENT_USR0 = 90,
|
||||
/** user-defined event; event data type = any (fixed size) */
|
||||
|
|
@ -292,6 +303,12 @@ typedef struct snd_seq_ev_queue_control {
|
|||
} param; /**< data value union */
|
||||
} snd_seq_ev_queue_control_t;
|
||||
|
||||
/** UMP info change notify */
|
||||
typedef struct snd_seq_ev_ump_notify {
|
||||
unsigned char client; /**< Client number */
|
||||
unsigned char block; /**< Block number (optional) */
|
||||
} snd_seq_ev_ump_notify_t;
|
||||
|
||||
/** Sequencer event data */
|
||||
typedef union snd_seq_event_data {
|
||||
snd_seq_ev_note_t note; /**< note information */
|
||||
|
|
@ -304,6 +321,7 @@ typedef union snd_seq_event_data {
|
|||
snd_seq_addr_t addr; /**< address */
|
||||
snd_seq_connect_t connect; /**< connect information */
|
||||
snd_seq_result_t result; /**< operation result code */
|
||||
snd_seq_ev_ump_notify_t ump_notify; /**< UMP info change notification */
|
||||
} snd_seq_event_data_t;
|
||||
|
||||
/** Sequencer event */
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/seq_midi_event.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_SEQ_MIDI_EVENT_H
|
||||
#define __ALSA_SEQ_MIDI_EVENT_H
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/seqmid.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_SEQMID_H
|
||||
#define __ALSA_SEQMID_H
|
||||
|
||||
|
|
@ -520,6 +526,13 @@ int snd_seq_reset_pool_input(snd_seq_t *seq);
|
|||
((ev)->type = SND_SEQ_EVENT_SYSEX,\
|
||||
snd_seq_ev_set_variable(ev, datalen, dataptr))
|
||||
|
||||
/* Helper API functions for UMP endpoint and block creations */
|
||||
int snd_seq_create_ump_endpoint(snd_seq_t *seq,
|
||||
const snd_ump_endpoint_info_t *info,
|
||||
unsigned int num_groups);
|
||||
int snd_seq_create_ump_block(snd_seq_t *seq, int blkid,
|
||||
const snd_ump_block_info_t *info);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -3,22 +3,6 @@
|
|||
* Main header file for the ALSA sequencer
|
||||
* Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
|
||||
* (c) 1998-1999 by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __SOUND_ASEQUENCER_H
|
||||
#define __SOUND_ASEQUENCER_H
|
||||
|
|
@ -26,7 +10,7 @@
|
|||
#include <sound/asound.h>
|
||||
|
||||
/** version of the sequencer */
|
||||
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
|
||||
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 5)
|
||||
|
||||
/**
|
||||
* definition of sequencer event types
|
||||
|
|
@ -108,6 +92,9 @@
|
|||
#define SNDRV_SEQ_EVENT_PORT_SUBSCRIBED 66 /* ports connected */
|
||||
#define SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED 67 /* ports disconnected */
|
||||
|
||||
#define SNDRV_SEQ_EVENT_UMP_EP_CHANGE 68 /* UMP EP info has changed */
|
||||
#define SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE 69 /* UMP block info has changed */
|
||||
|
||||
/* 70-89: synthesizer events - obsoleted */
|
||||
|
||||
/** user-defined events with fixed length
|
||||
|
|
@ -269,6 +256,12 @@ struct snd_seq_ev_quote {
|
|||
struct snd_seq_event *event; /* quoted event */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* UMP info change notify */
|
||||
struct snd_seq_ev_ump_notify {
|
||||
unsigned char client; /* Client number */
|
||||
unsigned char block; /* Block number (optional) */
|
||||
};
|
||||
|
||||
union snd_seq_event_data { /* event data... */
|
||||
struct snd_seq_ev_note note;
|
||||
struct snd_seq_ev_ctrl control;
|
||||
|
|
@ -281,6 +274,7 @@ union snd_seq_event_data { /* event data... */
|
|||
struct snd_seq_connect connect;
|
||||
struct snd_seq_result result;
|
||||
struct snd_seq_ev_quote quote;
|
||||
struct snd_seq_ev_ump_notify ump_notify;
|
||||
};
|
||||
|
||||
/* sequencer event */
|
||||
|
|
@ -477,6 +471,8 @@ struct snd_seq_remove_events {
|
|||
#define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1)
|
||||
#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2)
|
||||
|
||||
#define SNDRV_SEQ_PORT_FLG_IS_MIDI1 (1<<3) /* Keep MIDI 1.0 protocol */
|
||||
|
||||
/* port direction */
|
||||
#define SNDRV_SEQ_PORT_DIR_UNKNOWN 0
|
||||
#define SNDRV_SEQ_PORT_DIR_INPUT 1
|
||||
|
|
@ -539,11 +535,12 @@ struct snd_seq_queue_status {
|
|||
/* queue tempo */
|
||||
struct snd_seq_queue_tempo {
|
||||
int queue; /* sequencer queue */
|
||||
unsigned int tempo; /* current tempo, us/tick */
|
||||
unsigned int tempo; /* current tempo, us/tick (or different time-base below) */
|
||||
int ppq; /* time resolution, ticks/quarter */
|
||||
unsigned int skew_value; /* queue skew */
|
||||
unsigned int skew_base; /* queue skew base */
|
||||
char reserved[24]; /* for the future */
|
||||
unsigned short tempo_base; /* tempo base in nsec unit; either 10 or 1000 */
|
||||
char reserved[22]; /* for the future */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -616,7 +613,7 @@ struct snd_seq_client_ump_info {
|
|||
int client; /* client number to inquire/set */
|
||||
int type; /* type to inquire/set */
|
||||
unsigned char info[512]; /* info (either UMP ep or block info) */
|
||||
} __packed;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* IOCTL commands
|
||||
|
|
|
|||
|
|
@ -3,22 +3,6 @@
|
|||
* Advanced Linux Sound Architecture - ALSA - Driver
|
||||
* Copyright (c) 1994-2003 by Jaroslav Kysela <perex@perex.cz>,
|
||||
* Abramo Bagnara <abramo@alsa-project.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_ASOUND_H
|
||||
|
|
@ -28,7 +12,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
#else
|
||||
#include <sys/endian.h>
|
||||
#include <endian.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -54,8 +38,10 @@
|
|||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#define AES_IEC958_STATUS_SIZE 24
|
||||
|
||||
struct snd_aes_iec958 {
|
||||
unsigned char status[24]; /* AES/IEC958 channel status bits */
|
||||
unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
|
||||
unsigned char subcode[147]; /* AES/IEC958 subcode bits */
|
||||
unsigned char pad; /* nothing */
|
||||
unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */
|
||||
|
|
@ -154,7 +140,7 @@ struct snd_hwdep_dsp_image {
|
|||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15)
|
||||
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 18)
|
||||
|
||||
typedef unsigned long snd_pcm_uframes_t;
|
||||
typedef signed long snd_pcm_sframes_t;
|
||||
|
|
@ -200,6 +186,11 @@ typedef int __bitwise snd_pcm_format_t;
|
|||
#define SNDRV_PCM_FORMAT_S24_BE ((snd_pcm_format_t) 7) /* low three bytes */
|
||||
#define SNDRV_PCM_FORMAT_U24_LE ((snd_pcm_format_t) 8) /* low three bytes */
|
||||
#define SNDRV_PCM_FORMAT_U24_BE ((snd_pcm_format_t) 9) /* low three bytes */
|
||||
/*
|
||||
* For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
|
||||
* available bit count in most significant bit. It's for the case of so-called 'left-justified' or
|
||||
* `right-padding` sample which has less width than 32 bit.
|
||||
*/
|
||||
#define SNDRV_PCM_FORMAT_S32_LE ((snd_pcm_format_t) 10)
|
||||
#define SNDRV_PCM_FORMAT_S32_BE ((snd_pcm_format_t) 11)
|
||||
#define SNDRV_PCM_FORMAT_U32_LE ((snd_pcm_format_t) 12)
|
||||
|
|
@ -301,7 +292,8 @@ typedef int __bitwise snd_pcm_subformat_t;
|
|||
#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */
|
||||
#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */
|
||||
#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */
|
||||
|
||||
#define SNDRV_PCM_INFO_EXPLICIT_SYNC 0x10000000 /* needs explicit sync of pointers and data */
|
||||
#define SNDRV_PCM_INFO_NO_REWINDS 0x20000000 /* hardware can only support monotonic changes of appl_ptr */
|
||||
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
|
||||
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
|
||||
|
||||
|
|
@ -340,7 +332,7 @@ union snd_pcm_sync_id {
|
|||
unsigned char id[16];
|
||||
unsigned short id16[8];
|
||||
unsigned int id32[4];
|
||||
};
|
||||
} __attribute__((deprecated));
|
||||
|
||||
struct snd_pcm_info {
|
||||
unsigned int device; /* RO/WR (control): device number */
|
||||
|
|
@ -354,7 +346,7 @@ struct snd_pcm_info {
|
|||
int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */
|
||||
unsigned int subdevices_count;
|
||||
unsigned int subdevices_avail;
|
||||
union snd_pcm_sync_id sync; /* hardware synchronization ID */
|
||||
unsigned char pad1[16]; /* was: hardware synchronization ID */
|
||||
unsigned char reserved[64]; /* reserved for future... */
|
||||
};
|
||||
|
||||
|
|
@ -393,8 +385,8 @@ typedef int snd_pcm_hw_param_t;
|
|||
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
|
||||
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
|
||||
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */
|
||||
#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress the silence fill
|
||||
* for draining
|
||||
#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling
|
||||
* of the silence samples
|
||||
*/
|
||||
|
||||
struct snd_interval {
|
||||
|
|
@ -422,11 +414,12 @@ struct snd_pcm_hw_params {
|
|||
unsigned int rmask; /* W: requested masks */
|
||||
unsigned int cmask; /* R: changed masks */
|
||||
unsigned int info; /* R: Info flags for returned setup */
|
||||
unsigned int msbits; /* R: used most significant bits */
|
||||
unsigned int msbits; /* R: used most significant bits (in sample bit-width) */
|
||||
unsigned int rate_num; /* R: rate numerator */
|
||||
unsigned int rate_den; /* R: rate denominator */
|
||||
snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */
|
||||
unsigned char reserved[64]; /* reserved for future */
|
||||
unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */
|
||||
unsigned char reserved[48]; /* reserved for future */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -442,9 +435,14 @@ struct snd_pcm_sw_params {
|
|||
snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */
|
||||
snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */
|
||||
snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */
|
||||
snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */
|
||||
snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */
|
||||
snd_pcm_uframes_t silence_size; /* silence block size */
|
||||
/*
|
||||
* The following two thresholds alleviate playback buffer underruns; when
|
||||
* hw_avail drops below the threshold, the respective action is triggered:
|
||||
*/
|
||||
snd_pcm_uframes_t stop_threshold; /* - stop playback */
|
||||
snd_pcm_uframes_t silence_threshold; /* - pre-fill buffer with silence */
|
||||
snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary,
|
||||
* fill played area with silence immediately */
|
||||
snd_pcm_uframes_t boundary; /* pointers wrap point */
|
||||
unsigned int proto; /* protocol version */
|
||||
unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */
|
||||
|
|
@ -577,7 +575,8 @@ struct __snd_pcm_mmap_status64 {
|
|||
struct __snd_pcm_mmap_control64 {
|
||||
__pad_before_uframe __pad1;
|
||||
snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
|
||||
__pad_before_uframe __pad2;
|
||||
__pad_before_uframe __pad2; // This should be __pad_after_uframe, but binary
|
||||
// backwards compatibility constraints prevent a fix.
|
||||
|
||||
__pad_before_uframe __pad3;
|
||||
snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
|
||||
|
|
@ -709,7 +708,7 @@ enum {
|
|||
* Raw MIDI section - /dev/snd/midi??
|
||||
*/
|
||||
|
||||
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
|
||||
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5)
|
||||
|
||||
enum {
|
||||
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
|
||||
|
|
@ -721,6 +720,9 @@ enum {
|
|||
#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
|
||||
#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
|
||||
#define SNDRV_RAWMIDI_INFO_UMP 0x00000008
|
||||
#define SNDRV_RAWMIDI_INFO_STREAM_INACTIVE 0x00000010
|
||||
|
||||
#define SNDRV_RAWMIDI_DEVICE_UNKNOWN 0
|
||||
|
||||
struct snd_rawmidi_info {
|
||||
unsigned int device; /* RO/WR (control): device number */
|
||||
|
|
@ -733,7 +735,8 @@ struct snd_rawmidi_info {
|
|||
unsigned char subname[32]; /* name of active or selected subdevice */
|
||||
unsigned int subdevices_count;
|
||||
unsigned int subdevices_avail;
|
||||
unsigned char reserved[64]; /* reserved for future use */
|
||||
int tied_device; /* R: tied rawmidi device (UMP/legacy) */
|
||||
unsigned char reserved[60]; /* reserved for future use */
|
||||
};
|
||||
|
||||
#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0)
|
||||
|
|
@ -759,7 +762,7 @@ struct snd_rawmidi_framing_tstamp {
|
|||
__u32 tv_nsec; /* nanoseconds */
|
||||
__u64 tv_sec; /* seconds */
|
||||
__u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH];
|
||||
} __packed;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct snd_rawmidi_params {
|
||||
int stream;
|
||||
|
|
@ -807,7 +810,7 @@ struct snd_ump_endpoint_info {
|
|||
unsigned char name[128]; /* endpoint name string */
|
||||
unsigned char product_id[128]; /* unique product id string */
|
||||
unsigned char reserved[32];
|
||||
} __packed;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* UMP direction */
|
||||
#define SNDRV_UMP_DIR_INPUT 0x01
|
||||
|
|
@ -843,7 +846,7 @@ struct snd_ump_block_info {
|
|||
unsigned int flags; /* various info flags */
|
||||
unsigned char name[128]; /* block name string */
|
||||
unsigned char reserved[32];
|
||||
} __packed;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
|
||||
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
|
||||
|
|
@ -860,7 +863,7 @@ struct snd_ump_block_info {
|
|||
* Timer section - /dev/snd/timer
|
||||
*/
|
||||
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
|
||||
|
||||
enum {
|
||||
SNDRV_TIMER_CLASS_NONE = -1,
|
||||
|
|
@ -885,6 +888,7 @@ enum {
|
|||
#define SNDRV_TIMER_GLOBAL_RTC 1 /* unused */
|
||||
#define SNDRV_TIMER_GLOBAL_HPET 2
|
||||
#define SNDRV_TIMER_GLOBAL_HRTIMER 3
|
||||
#define SNDRV_TIMER_GLOBAL_UDRIVEN 4
|
||||
|
||||
/* info flags */
|
||||
#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */
|
||||
|
|
@ -963,6 +967,18 @@ struct snd_timer_status {
|
|||
unsigned char reserved[64]; /* reserved */
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure describes the userspace-driven timer. Such timers are purely virtual,
|
||||
* and can only be triggered from software (for instance, by userspace application).
|
||||
*/
|
||||
struct snd_timer_uinfo {
|
||||
/* To pretend being a normal timer, we need to know the resolution in ns. */
|
||||
__u64 resolution;
|
||||
int fd;
|
||||
unsigned int id;
|
||||
unsigned char reserved[16];
|
||||
};
|
||||
|
||||
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
|
||||
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
|
||||
#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int)
|
||||
|
|
@ -979,6 +995,8 @@ struct snd_timer_status {
|
|||
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
|
||||
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
|
||||
#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int)
|
||||
#define SNDRV_TIMER_IOCTL_CREATE _IOWR('T', 0xa5, struct snd_timer_uinfo)
|
||||
#define SNDRV_TIMER_IOCTL_TRIGGER _IO('T', 0xa6)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD
|
||||
|
|
@ -1064,7 +1082,7 @@ typedef int __bitwise snd_ctl_elem_iface_t;
|
|||
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
|
||||
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
|
||||
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
|
||||
// (1 << 3) is unused.
|
||||
/* (1 << 3) is unused. */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
|
||||
|
|
@ -1161,7 +1179,7 @@ struct snd_ctl_elem_value {
|
|||
struct snd_ctl_tlv {
|
||||
unsigned int numid; /* control element numeric identification */
|
||||
unsigned int length; /* in bytes aligned to 4 */
|
||||
unsigned int tlv[0]; /* first TLV */
|
||||
unsigned int tlv[]; /* first TLV */
|
||||
};
|
||||
|
||||
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/timer.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_TIMER_H
|
||||
#define __ALSA_TIMER_H
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
* API library for ALSA rawmidi/UMP interface
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/ump.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_UMP_H
|
||||
#define __ALSA_UMP_H
|
||||
|
||||
|
|
@ -13,6 +19,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup RawMidi RawMidi Interface
|
||||
* The RawMidi Interface. See \ref rawmidi page for more details.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/** UMP (Endpoint) RawMIDI device */
|
||||
typedef struct _snd_ump snd_ump_t;
|
||||
/** UMP Endpoint information container */
|
||||
|
|
@ -69,6 +81,9 @@ enum _snd_ump_direction {
|
|||
/** Bit flag for JRTS in Receive */
|
||||
#define SND_UMP_EP_INFO_PROTO_JRTS_RX 0x0002
|
||||
|
||||
/** Default version passed to UMP Endpoint info */
|
||||
#define SND_UMP_EP_INFO_DEFAULT_VERSION 0x0101
|
||||
|
||||
size_t snd_ump_endpoint_info_sizeof(void);
|
||||
/** \hideinitializer
|
||||
* \brief allocate an invalid #snd_ump_endpoint_info_t using standard alloca
|
||||
|
|
@ -77,6 +92,7 @@ size_t snd_ump_endpoint_info_sizeof(void);
|
|||
#define snd_ump_endpoint_info_alloca(ptr) __snd_alloca(ptr, snd_ump_endpoint_info)
|
||||
int snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info);
|
||||
void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info);
|
||||
void snd_ump_endpoint_info_clear(snd_ump_endpoint_info_t *info);
|
||||
void snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst, const snd_ump_endpoint_info_t *src);
|
||||
int snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info);
|
||||
int snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info);
|
||||
|
|
@ -93,6 +109,20 @@ const char *snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info);
|
|||
const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info);
|
||||
int snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info);
|
||||
|
||||
void snd_ump_endpoint_info_set_card(snd_ump_endpoint_info_t *info, unsigned int card);
|
||||
void snd_ump_endpoint_info_set_device(snd_ump_endpoint_info_t *info, unsigned int device);
|
||||
void snd_ump_endpoint_info_set_flags(snd_ump_endpoint_info_t *info, unsigned int flags);
|
||||
void snd_ump_endpoint_info_set_protocol_caps(snd_ump_endpoint_info_t *info, unsigned int caps);
|
||||
void snd_ump_endpoint_info_set_protocol(snd_ump_endpoint_info_t *info, unsigned int protocols);
|
||||
void snd_ump_endpoint_info_set_num_blocks(snd_ump_endpoint_info_t *info, unsigned int num_blocks);
|
||||
void snd_ump_endpoint_info_set_version(snd_ump_endpoint_info_t *info, unsigned int version);
|
||||
void snd_ump_endpoint_info_set_manufacturer_id(snd_ump_endpoint_info_t *info, unsigned int id);
|
||||
void snd_ump_endpoint_info_set_family_id(snd_ump_endpoint_info_t *info, unsigned int id);
|
||||
void snd_ump_endpoint_info_set_model_id(snd_ump_endpoint_info_t *info, unsigned int id);
|
||||
void snd_ump_endpoint_info_set_sw_revision(snd_ump_endpoint_info_t *info, const unsigned char *id);
|
||||
void snd_ump_endpoint_info_set_name(snd_ump_endpoint_info_t *info, const char *name);
|
||||
void snd_ump_endpoint_info_set_product_id(snd_ump_endpoint_info_t *info, const char *id);
|
||||
|
||||
/** Bit flag for MIDI 1.0 port w/o restrict in UMP Block info flags */
|
||||
#define SND_UMP_BLOCK_IS_MIDI1 (1U << 0)
|
||||
/** Bit flag for 31.25Kbps B/W MIDI1 port in UMP Block info flags */
|
||||
|
|
@ -110,6 +140,9 @@ enum _snd_ump_block_ui_hint {
|
|||
SND_UMP_BLOCK_UI_HINT_BOTH = 0x03,
|
||||
};
|
||||
|
||||
/** Default MIDI CI version passed to UMP Block info */
|
||||
#define SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION 0x01
|
||||
|
||||
size_t snd_ump_block_info_sizeof(void);
|
||||
/** \hideinitializer
|
||||
* \brief allocate an invalid #snd_ump_block_info_t using standard alloca
|
||||
|
|
@ -118,11 +151,11 @@ size_t snd_ump_block_info_sizeof(void);
|
|||
#define snd_ump_block_info_alloca(ptr) __snd_alloca(ptr, snd_ump_block_info)
|
||||
int snd_ump_block_info_malloc(snd_ump_block_info_t **info);
|
||||
void snd_ump_block_info_free(snd_ump_block_info_t *info);
|
||||
void snd_ump_block_info_clear(snd_ump_block_info_t *info);
|
||||
void snd_ump_block_info_copy(snd_ump_block_info_t *dst, const snd_ump_block_info_t *src);
|
||||
int snd_ump_block_info_get_card(const snd_ump_block_info_t *info);
|
||||
int snd_ump_block_info_get_device(const snd_ump_block_info_t *info);
|
||||
unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info);
|
||||
void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id);
|
||||
unsigned int snd_ump_block_info_get_active(const snd_ump_block_info_t *info);
|
||||
unsigned int snd_ump_block_info_get_flags(const snd_ump_block_info_t *info);
|
||||
unsigned int snd_ump_block_info_get_direction(const snd_ump_block_info_t *info);
|
||||
|
|
@ -134,6 +167,21 @@ unsigned int snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info);
|
|||
const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info);
|
||||
int snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info);
|
||||
|
||||
void snd_ump_block_info_set_card(snd_ump_block_info_t *info, unsigned int card);
|
||||
void snd_ump_block_info_set_device(snd_ump_block_info_t *info, unsigned int device);
|
||||
void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id);
|
||||
void snd_ump_block_info_set_active(snd_ump_block_info_t *info, unsigned int active);
|
||||
void snd_ump_block_info_set_flags(snd_ump_block_info_t *info, unsigned int flags);
|
||||
void snd_ump_block_info_set_direction(snd_ump_block_info_t *info, unsigned int direction);
|
||||
void snd_ump_block_info_set_first_group(snd_ump_block_info_t *info, unsigned int first_group);
|
||||
void snd_ump_block_info_set_num_groups(snd_ump_block_info_t *info, unsigned int num_groups);
|
||||
void snd_ump_block_info_set_midi_ci_version(snd_ump_block_info_t *info, unsigned int version);
|
||||
void snd_ump_block_info_set_sysex8_streams(snd_ump_block_info_t *info, unsigned int streams);
|
||||
void snd_ump_block_info_set_ui_hint(snd_ump_block_info_t *info, unsigned int hint);
|
||||
void snd_ump_block_info_set_name(snd_ump_block_info_t *info, const char *name);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,18 +6,26 @@
|
|||
* API library for ALSA rawmidi/UMP interface
|
||||
*/
|
||||
|
||||
#if !defined(__ASOUNDLIB_H) && !defined(ALSA_LIBRARY_BUILD)
|
||||
/* don't use ALSA_LIBRARY_BUILD define in sources outside alsa-lib */
|
||||
#warning "use #include <alsa/asoundlib.h>, <alsa/ump_msg.h> should not be used directly"
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ALSA_UMP_MSG_H
|
||||
#define __ALSA_UMP_MSG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN
|
||||
#error "Endianness check failed!"
|
||||
#endif
|
||||
|
||||
/** general UMP packet header in 32bit word */
|
||||
typedef struct _snd_ump_msg_hdr {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -36,7 +44,7 @@ typedef struct _snd_ump_msg_hdr {
|
|||
|
||||
/** MIDI 1.0 Note Off / Note On (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_note {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -55,16 +63,16 @@ typedef struct _snd_ump_msg_midi1_note {
|
|||
|
||||
/** MIDI 1.0 Poly Pressure (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_paf {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t note; /** Note (7bit) */
|
||||
uint8_t data; /** Pressure (7bit) */
|
||||
uint8_t note; /**< Note (7bit) */
|
||||
uint8_t data; /**< Pressure (7bit) */
|
||||
#else
|
||||
uint8_t data; /** Pressure (7bit) */
|
||||
uint8_t note; /** Note (7bit) */
|
||||
uint8_t data; /**< Pressure (7bit) */
|
||||
uint8_t note; /**< Note (7bit) */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
|
|
@ -74,16 +82,16 @@ typedef struct _snd_ump_msg_midi1_paf {
|
|||
|
||||
/** MIDI 1.0 Control Change (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_cc {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t index; /** Control index (7bit) */
|
||||
uint8_t data; /** Control data (7bit) */
|
||||
uint8_t index; /**< Control index (7bit) */
|
||||
uint8_t data; /**< Control data (7bit) */
|
||||
#else
|
||||
uint8_t data; /** Control data (7bit) */
|
||||
uint8_t index; /** Control index (7bit) */
|
||||
uint8_t data; /**< Control data (7bit) */
|
||||
uint8_t index; /**< Control index (7bit) */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
|
|
@ -93,7 +101,7 @@ typedef struct _snd_ump_msg_midi1_cc {
|
|||
|
||||
/** MIDI 1.0 Program Change (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_program {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -112,7 +120,7 @@ typedef struct _snd_ump_msg_midi1_program {
|
|||
|
||||
/** MIDI 1.0 Channel Pressure (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_caf {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -131,7 +139,7 @@ typedef struct _snd_ump_msg_midi1_caf {
|
|||
|
||||
/** MIDI 1.0 Pitch Bend (32bit) */
|
||||
typedef struct _snd_ump_msg_midi1_pitchbend {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -150,15 +158,15 @@ typedef struct _snd_ump_msg_midi1_pitchbend {
|
|||
|
||||
/** System Common and Real Time messages (32bit); no channel field */
|
||||
typedef struct snd_ump_msg_system {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t parm1; /**< First parameter */
|
||||
uint8_t parm2; /**< Second parameter */
|
||||
#else
|
||||
uint8_t parm1; /**< First parameter */
|
||||
uint8_t parm2; /**< Second parameter */
|
||||
uint8_t parm1; /**< First parameter */
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
|
@ -167,16 +175,16 @@ typedef struct snd_ump_msg_system {
|
|||
|
||||
/** MIDI 1.0 UMP CVM (32bit) */
|
||||
typedef union _snd_ump_msg_midi1 {
|
||||
snd_ump_msg_midi1_note_t note_on;
|
||||
snd_ump_msg_midi1_note_t note_off;
|
||||
snd_ump_msg_midi1_paf_t poly_pressure;
|
||||
snd_ump_msg_midi1_cc_t control_change;
|
||||
snd_ump_msg_midi1_program_t program_change;
|
||||
snd_ump_msg_midi1_caf_t channel_pressure;
|
||||
snd_ump_msg_midi1_pitchbend_t pitchbend;
|
||||
snd_ump_msg_system_t system;
|
||||
snd_ump_msg_hdr_t hdr;
|
||||
uint32_t raw;
|
||||
snd_ump_msg_midi1_note_t note_on; /**< MIDI1 note-on message */
|
||||
snd_ump_msg_midi1_note_t note_off; /**< MIDI1 note-off message */
|
||||
snd_ump_msg_midi1_paf_t poly_pressure; /**< MIDI1 poly-pressure message */
|
||||
snd_ump_msg_midi1_cc_t control_change; /**< MIDI1 control-change message */
|
||||
snd_ump_msg_midi1_program_t program_change; /**< MIDI1 program-change message */
|
||||
snd_ump_msg_midi1_caf_t channel_pressure; /**< MIDI1 channel-pressure message */
|
||||
snd_ump_msg_midi1_pitchbend_t pitchbend; /**< MIDI1 pitch-bend message */
|
||||
snd_ump_msg_system_t system; /**< system message */
|
||||
snd_ump_msg_hdr_t hdr; /**< UMP header */
|
||||
uint32_t raw; /**< raw UMP packet */
|
||||
} snd_ump_msg_midi1_t;
|
||||
|
||||
/** MIDI 2.0 Note-on/off attribute type */
|
||||
|
|
@ -187,9 +195,9 @@ enum {
|
|||
SND_UMP_MIDI2_NOTE_ATTR_PITCH79 = 0x03, /**< Pitch 7.9 */
|
||||
};
|
||||
|
||||
/* MIDI 2.0 Note Off / Note On (64bit) */
|
||||
/** MIDI 2.0 Note Off / Note On (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_note {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -214,7 +222,7 @@ typedef struct _snd_ump_msg_midi2_note {
|
|||
|
||||
/** MIDI 2.0 Poly Pressure (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_paf {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -237,7 +245,7 @@ typedef struct _snd_ump_msg_midi2_paf {
|
|||
|
||||
/** MIDI 2.0 Per-Note Controller (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_per_note_cc {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -266,7 +274,7 @@ enum {
|
|||
|
||||
/** MIDI 2.0 Per-Note Management (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_per_note_mgmt {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -289,7 +297,7 @@ typedef struct _snd_ump_msg_midi2_per_note_mgmt {
|
|||
|
||||
/** MIDI 2.0 Control Change (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_cc {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -312,7 +320,7 @@ typedef struct _snd_ump_msg_midi2_cc {
|
|||
|
||||
/** MIDI 2.0 Registered Controller (RPN) / Assignable Controller (NRPN) (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_rpn {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -335,7 +343,7 @@ typedef struct _snd_ump_msg_midi2_rpn {
|
|||
|
||||
/** MIDI 2.0 Program Change (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_program {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
|
|
@ -364,14 +372,14 @@ typedef struct _snd_ump_msg_midi2_program {
|
|||
|
||||
/** MIDI 2.0 Channel Pressure (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_caf {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint16_t reserved; /**< Unused */
|
||||
|
||||
uint32_t data; /** Data (32bit) */
|
||||
uint32_t data; /**< Data (32bit) */
|
||||
#else
|
||||
uint16_t reserved; /**< Unused */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
|
|
@ -379,20 +387,20 @@ typedef struct _snd_ump_msg_midi2_caf {
|
|||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint32_t data; /** Data (32bit) */
|
||||
uint32_t data; /**< Data (32bit) */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_midi2_caf_t;
|
||||
|
||||
/* MIDI 2.0 Pitch Bend (64bit) */
|
||||
/** MIDI 2.0 Pitch Bend (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_pitchbend {
|
||||
#ifdef SNDRV_BIG_ENDIAN_BITFIELD
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint16_t reserved; /**< Unused */
|
||||
|
||||
uint32_t data; /** Data (32bit) */
|
||||
uint32_t data; /**< Data (32bit) */
|
||||
#else
|
||||
uint16_t reserved; /**< Unused */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
|
|
@ -400,11 +408,11 @@ typedef struct _snd_ump_msg_midi2_pitchbend {
|
|||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint32_t data; /** Data (32bit) */
|
||||
uint32_t data; /**< Data (32bit) */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_midi2_pitchbend_t;
|
||||
|
||||
/* MIDI 2.0 Per-Note Pitch Bend (64bit) */
|
||||
/** MIDI 2.0 Per-Note Pitch Bend (64bit) */
|
||||
typedef struct _snd_ump_msg_midi2_per_note_pitchbend {
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
|
@ -416,7 +424,6 @@ typedef struct _snd_ump_msg_midi2_per_note_pitchbend {
|
|||
|
||||
uint32_t data; /**< Data (32bit) */
|
||||
#else
|
||||
/* 0 */
|
||||
uint8_t reserved; /**< Unused */
|
||||
uint8_t note; /**< Note (7bit) */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
|
|
@ -428,27 +435,417 @@ typedef struct _snd_ump_msg_midi2_per_note_pitchbend {
|
|||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_midi2_per_note_pitchbend_t;
|
||||
|
||||
/** MIDI2 UMP packet (64bit little-endian) */
|
||||
/** MIDI2 UMP packet (64bit) */
|
||||
typedef union _snd_ump_msg_midi2 {
|
||||
snd_ump_msg_midi2_note_t note_on;
|
||||
snd_ump_msg_midi2_note_t note_off;
|
||||
snd_ump_msg_midi2_paf_t poly_pressure;
|
||||
snd_ump_msg_midi2_per_note_cc_t per_note_acc;
|
||||
snd_ump_msg_midi2_per_note_cc_t per_note_rcc;
|
||||
snd_ump_msg_midi2_per_note_mgmt_t per_note_mgmt;
|
||||
snd_ump_msg_midi2_cc_t control_change;
|
||||
snd_ump_msg_midi2_rpn_t rpn;
|
||||
snd_ump_msg_midi2_rpn_t nrpn;
|
||||
snd_ump_msg_midi2_rpn_t relative_rpn;
|
||||
snd_ump_msg_midi2_rpn_t relative_nrpn;
|
||||
snd_ump_msg_midi2_program_t program_change;
|
||||
snd_ump_msg_midi2_caf_t channel_pressure;
|
||||
snd_ump_msg_midi2_pitchbend_t pitchbend;
|
||||
snd_ump_msg_midi2_per_note_pitchbend_t per_note_pitchbend;
|
||||
snd_ump_msg_hdr_t hdr;
|
||||
uint32_t raw[2];
|
||||
snd_ump_msg_midi2_note_t note_on; /**< MIDI2 note-on message */
|
||||
snd_ump_msg_midi2_note_t note_off; /**< MIDI2 note-off message */
|
||||
snd_ump_msg_midi2_paf_t poly_pressure; /**< MIDI2 poly-pressure message */
|
||||
snd_ump_msg_midi2_per_note_cc_t per_note_acc; /**< MIDI2 per-note ACC message */
|
||||
snd_ump_msg_midi2_per_note_cc_t per_note_rcc; /**< MIDI2 per-note RCC message */
|
||||
snd_ump_msg_midi2_per_note_mgmt_t per_note_mgmt; /**< MIDI2 per-note management message */
|
||||
snd_ump_msg_midi2_cc_t control_change; /**< MIDI2 control-change message */
|
||||
snd_ump_msg_midi2_rpn_t rpn; /**< MIDI2 RPN message */
|
||||
snd_ump_msg_midi2_rpn_t nrpn; /**< MIDI2 NRPN message */
|
||||
snd_ump_msg_midi2_rpn_t relative_rpn; /**< MIDI2 relative-RPN message */
|
||||
snd_ump_msg_midi2_rpn_t relative_nrpn; /**< MIDI2 relative-NRPN message */
|
||||
snd_ump_msg_midi2_program_t program_change; /**< MIDI2 program-change message */
|
||||
snd_ump_msg_midi2_caf_t channel_pressure; /**< MIDI2 channel-pressure message */
|
||||
snd_ump_msg_midi2_pitchbend_t pitchbend; /**< MIDI2 pitch-bend message */
|
||||
snd_ump_msg_midi2_per_note_pitchbend_t per_note_pitchbend; /**< MIDI2 per-note pitch-bend message */
|
||||
snd_ump_msg_hdr_t hdr; /**< UMP header */
|
||||
uint32_t raw[2]; /**< raw UMP packet */
|
||||
} snd_ump_msg_midi2_t;
|
||||
|
||||
/** Stream Message (generic) (128bit) */
|
||||
typedef struct _snd_ump_msg_stream_gen {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t type:4; /**< UMP packet type */
|
||||
uint16_t format:2; /**< Format */
|
||||
uint16_t status:10; /**< Status */
|
||||
uint16_t data1; /**< Data */
|
||||
uint32_t data2; /**< Data */
|
||||
uint32_t data3; /**< Data */
|
||||
uint32_t data4; /**< Data */
|
||||
#else
|
||||
uint16_t data1; /**< Data */
|
||||
uint16_t status:10; /**< Status */
|
||||
uint16_t format:2; /**< Format */
|
||||
uint16_t type:4; /**< UMP packet type */
|
||||
uint32_t data2; /**< Data */
|
||||
uint32_t data3; /**< Data */
|
||||
uint32_t data4; /**< Data */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_stream_gen_t;
|
||||
|
||||
/** Stream Message (128bit) */
|
||||
typedef union _snd_ump_msg_stream {
|
||||
snd_ump_msg_stream_gen_t gen; /**< Generic Stream message */
|
||||
snd_ump_msg_hdr_t hdr; /**< UMP header */
|
||||
uint32_t raw[4]; /**< raw UMP packet */
|
||||
} snd_ump_msg_stream_t;
|
||||
|
||||
/** Metadata / Text Message (128bit) */
|
||||
typedef struct _snd_ump_msg_flex_data_meta {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
uint32_t data[3]; /**< Data (96 bits) */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint32_t data[3]; /**< Data (96 bits) */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_flex_data_meta_t;
|
||||
|
||||
/** Set Tempo Message (128bit) */
|
||||
typedef struct _snd_ump_msg_set_tempo {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
|
||||
uint32_t tempo; /**< Number of 10nsec units per quarter note */
|
||||
|
||||
uint32_t reserved[2]; /**< Unused */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint32_t tempo; /**< Number of 10nsec units per quarter note */
|
||||
|
||||
uint32_t reserved[2]; /**< Unused */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_set_tempo_t;
|
||||
|
||||
/** Set Time Signature Message (128bit) */
|
||||
typedef struct _snd_ump_msg_set_time_sig {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
|
||||
uint8_t numerator; /**< Numerator */
|
||||
uint8_t denominator; /**< Denominator */
|
||||
uint8_t num_notes; /**< Number of 1/32 notes */
|
||||
uint8_t reserved1; /**< Unused */
|
||||
|
||||
uint32_t reserved[2]; /**< Unused */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint8_t reserved1; /**< Unused */
|
||||
uint8_t num_notes; /**< Number of 1/32 notes */
|
||||
uint8_t denominator; /**< Denominator */
|
||||
uint8_t numerator; /**< Numerator */
|
||||
|
||||
uint32_t reserved[2]; /**< Unused */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_set_time_sig_t;
|
||||
|
||||
/** Set Metronome Message (128bit) */
|
||||
typedef struct _snd_ump_msg_set_metronome {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
|
||||
uint8_t clocks_primary; /**< Num clocks per primary clock */
|
||||
uint8_t bar_accent_1; /**< Bar accent part 1 */
|
||||
uint8_t bar_accent_2; /**< Bar accent part 2 */
|
||||
uint8_t bar_accent_3; /**< Bar accent part 3 */
|
||||
|
||||
uint8_t subdivision_1; /**< Num subdivision clicks 1 */
|
||||
uint8_t subdivision_2; /**< Num subdivision clicks 1 */
|
||||
uint16_t reserved1; /**< Unused */
|
||||
|
||||
uint32_t reserved2; /**< Unused */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint8_t bar_accent_3; /**< Bar accent part 3 */
|
||||
uint8_t bar_accent_2; /**< Bar accent part 2 */
|
||||
uint8_t bar_accent_1; /**< Bar accent part 1 */
|
||||
uint8_t clocks_primary; /**< Num clocks per primary clock */
|
||||
|
||||
uint16_t reserved1; /**< Unused */
|
||||
uint8_t subdivision_2; /**< Num subdivision clicks 1 */
|
||||
uint8_t subdivision_1; /**< Num subdivision clicks 1 */
|
||||
|
||||
uint32_t reserved2; /**< Unused */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_set_metronome_t;
|
||||
|
||||
/** Set Key Signature Message (128bit) */
|
||||
typedef struct _snd_ump_msg_set_key_sig {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
|
||||
uint8_t sharps_flats:4; /**< Sharps/Flats */
|
||||
uint8_t tonic_note:4; /**< Tonic Note 1 */
|
||||
uint8_t reserved1[3]; /**< Unused */
|
||||
|
||||
uint32_t reserved2[2]; /**< Unused */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint8_t reserved1[3]; /**< Unused */
|
||||
uint8_t tonic_note:4; /**< Tonic Note */
|
||||
uint8_t sharps_flats:4; /**< Sharps/Flats */
|
||||
|
||||
uint32_t reserved2[2]; /**< Unused */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_set_key_sig_t;
|
||||
|
||||
/** Set Chord Name Message (128bit) */
|
||||
typedef struct _snd_ump_msg_set_chord_name {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t status; /**< Status */
|
||||
|
||||
uint8_t tonic_sharp:4; /**< Tonic Sharps/Flats */
|
||||
uint8_t chord_tonic:4; /**< Chord Tonic Note */
|
||||
uint8_t chord_type; /**< Chord Type */
|
||||
uint8_t alter1_type:4; /**< Alteration 1 Type */
|
||||
uint8_t alter1_degree:4; /**< Alteration 1 Degree */
|
||||
uint8_t alter2_type:4; /**< Alteration 2 Type */
|
||||
uint8_t alter2_degree:4; /**< Alteration 2 Degree */
|
||||
|
||||
uint8_t alter3_type:4; /**< Alteration 3 Type */
|
||||
uint8_t alter3_degree:4; /**< Alteration 3 Degree */
|
||||
uint8_t alter4_type:4; /**< Alteration 4 Type */
|
||||
uint8_t alter4_degree:4; /**< Alteration 4 Degree */
|
||||
uint16_t reserved; /**< Unused */
|
||||
|
||||
uint8_t bass_sharp:4; /**< Bass Sharps/Flats */
|
||||
uint8_t bass_note:4; /**< Bass Note */
|
||||
uint8_t bass_type; /**< Bass Chord Type */
|
||||
uint8_t bass_alter1_type:4; /**< Bass Alteration 1 Type */
|
||||
uint8_t bass_alter1_degree:4; /**< Bass Alteration 1 Degree */
|
||||
uint8_t bass_alter2_type:4; /**< Bass Alteration 2 Type */
|
||||
uint8_t bass_alter2_degree:4; /**< Bass Alteration 2 Degree */
|
||||
#else
|
||||
uint8_t status; /**< Status */
|
||||
uint8_t status_bank; /**< Status Bank */
|
||||
uint8_t channel:4; /**< Channel */
|
||||
uint8_t addrs:2; /**< Address */
|
||||
uint8_t format:2; /**< Format */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint8_t alter2_degree:4; /**< Alteration 2 Degree */
|
||||
uint8_t alter2_type:4; /**< Alteration 2 Type */
|
||||
uint8_t alter1_degree:4; /**< Alteration 1 Degree */
|
||||
uint8_t alter1_type:4; /**< Alteration 1 Type */
|
||||
uint8_t chord_type; /**< Chord Type */
|
||||
uint8_t chord_tonic:4; /**< Chord Tonic Note */
|
||||
uint8_t tonic_sharp:4; /**< Tonic Sharps/Flats */
|
||||
|
||||
uint16_t reserved; /**< Unused */
|
||||
uint8_t alter4_degree:4; /**< Alteration 4 Degree */
|
||||
uint8_t alter4_type:4; /**< Alteration 4 Type */
|
||||
uint8_t alter3_degree:4; /**< Alteration 3 Degree */
|
||||
uint8_t alter3_type:4; /**< Alteration 3 Type */
|
||||
|
||||
uint8_t bass_alter2_degree:4; /**< Bass Alteration 2 Degree */
|
||||
uint8_t bass_alter2_type:4; /**< Bass Alteration 2 Type */
|
||||
uint8_t bass_alter1_degree:4; /**< Bass Alteration 1 Degree */
|
||||
uint8_t bass_alter1_type:4; /**< Bass Alteration 1 Type */
|
||||
uint8_t bass_type; /**< Bass Chord Type */
|
||||
uint8_t bass_note:4; /**< Bass Note */
|
||||
uint8_t bass_sharp:4; /**< Bass Sharps/Flats */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_set_chord_name_t;
|
||||
|
||||
/** Flex Data Message (128bit) */
|
||||
typedef union _snd_ump_msg_flex_data {
|
||||
snd_ump_msg_flex_data_meta_t meta; /**< Metadata */
|
||||
snd_ump_msg_flex_data_meta_t text; /**< Text data */
|
||||
snd_ump_msg_set_tempo_t set_tempo; /**< Set Tempo */
|
||||
snd_ump_msg_set_time_sig_t set_time_sig; /**< Set Time Signature */
|
||||
snd_ump_msg_set_metronome_t set_metronome; /**< Set Metronome */
|
||||
snd_ump_msg_set_key_sig_t set_key_sig; /**< Set Key Signature */
|
||||
snd_ump_msg_set_chord_name_t set_chord_name; /**< Set Chord Name */
|
||||
snd_ump_msg_hdr_t hdr; /**< UMP header */
|
||||
uint32_t raw[4]; /**< raw UMP packet */
|
||||
} snd_ump_msg_flex_data_t;
|
||||
|
||||
/** Mixed Data Set Chunk Header Message (128bit) */
|
||||
typedef struct _snd_ump_msg_mixed_data_header {
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t mds_id:4; /**< Mixed Data Set ID */
|
||||
uint16_t bytes; /**< Number of valid bytes in this chunk */
|
||||
|
||||
uint16_t chunks; /**< Number of chunks in mixed data set */
|
||||
uint16_t chunk; /**< Number of this chunk */
|
||||
|
||||
uint16_t manufacturer; /**< Manufacturer ID */
|
||||
uint16_t device; /**< Device ID */
|
||||
|
||||
uint16_t sub_id_1; /**< Sub ID \# 1 */
|
||||
uint16_t sub_id_2; /**< Sub ID \# 2 */
|
||||
#else
|
||||
uint16_t bytes; /**< Number of valid bytes in this chunk */
|
||||
uint8_t mds_id:4; /**< Mixed Data Set ID */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint16_t chunk; /**< Number of this chunk */
|
||||
uint16_t chunks; /**< Number of chunks in mixed data set */
|
||||
|
||||
uint16_t device; /**< Device ID */
|
||||
uint16_t manufacturer; /**< Manufacturer ID */
|
||||
|
||||
uint16_t sub_id_2; /**< Sub ID \# 2 */
|
||||
uint16_t sub_id_1; /**< Sub ID \# 1 */
|
||||
#endif
|
||||
} snd_ump_msg_mixed_data_header_t;
|
||||
|
||||
/** Mixed Data Set Chunk Payload Message (128bit) */
|
||||
typedef struct _snd_ump_msg_mixed_data_payload {
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t mds_id:4; /**< Mixed Data Set ID */
|
||||
uint16_t payload1; /**< Payload */
|
||||
|
||||
uint32_t payloads[3]; /**< Payload */
|
||||
#else
|
||||
uint16_t payload1; /**< Payload */
|
||||
uint8_t mds_id:4; /**< Mixed Data Set ID */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
|
||||
uint32_t payloads[3]; /**< Payload */
|
||||
#endif
|
||||
} snd_ump_msg_mixed_data_payload_t;
|
||||
|
||||
/** Mixed Data Set Chunk Message (128bit) */
|
||||
typedef union _snd_ump_msg_mixed_data {
|
||||
snd_ump_msg_mixed_data_header_t header; /**< Header */
|
||||
snd_ump_msg_mixed_data_payload_t payload; /**< Payload */
|
||||
uint32_t raw[4]; /**< raw UMP packet */
|
||||
} snd_ump_msg_mixed_data_t;
|
||||
|
||||
/** Jitter Reduction Clock / Timestamp Message (32bit) */
|
||||
typedef struct _snd_ump_msg_jr_clock {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t reserved:4; /**< Unused */
|
||||
uint16_t time; /**< clock time / timestamp */
|
||||
#else
|
||||
uint16_t time; /**< clock time / timestamp */
|
||||
uint8_t reserved:4; /**< Unused */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_jr_clock_t;
|
||||
|
||||
/** Delta Clockstamp Ticks Per Quarter Note (DCTPQ) (32bit) */
|
||||
typedef struct _snd_ump_msg_dctpq {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t reserved:4; /**< Unused */
|
||||
uint16_t ticks; /**< number of ticks per quarter note */
|
||||
#else
|
||||
uint16_t ticks; /**< number of ticks per quarter note */
|
||||
uint8_t reserved:4; /**< Unused */
|
||||
uint8_t status:4; /**< Status */
|
||||
uint8_t group:4; /**< UMP Group */
|
||||
uint8_t type:4; /**< UMP packet type */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_dctpq_t;
|
||||
|
||||
/** Delta Clockstamp (DC) (32bit) */
|
||||
typedef struct _snd_ump_msg_dc {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint32_t type:4; /**< UMP packet type */
|
||||
uint32_t group:4; /**< UMP Group */
|
||||
uint32_t status:4; /**< Status */
|
||||
uint32_t ticks:20; /**< number of ticks since last event */
|
||||
#else
|
||||
uint32_t ticks:20; /**< number of ticks since last event */
|
||||
uint32_t status:4; /**< Status */
|
||||
uint32_t group:4; /**< UMP Group */
|
||||
uint32_t type:4; /**< UMP packet type */
|
||||
#endif
|
||||
} __attribute((packed)) snd_ump_msg_dc_t;
|
||||
|
||||
/** Utility Message (32bit) */
|
||||
typedef union _snd_ump_msg_utility {
|
||||
snd_ump_msg_jr_clock_t jr_clock; /**< JR Clock messages */
|
||||
snd_ump_msg_dctpq_t dctpq; /**< DCTPQ message */
|
||||
snd_ump_msg_dc_t dc; /**< DC message */
|
||||
snd_ump_msg_hdr_t hdr; /**< UMP header */
|
||||
uint32_t raw; /**< raw UMP packet */
|
||||
} snd_ump_msg_utility_t;
|
||||
|
||||
/**
|
||||
* UMP message type
|
||||
*/
|
||||
|
|
@ -511,6 +908,12 @@ enum {
|
|||
SND_UMP_SYSEX_STATUS_END = 3,
|
||||
};
|
||||
|
||||
/** MIDI 2.0 Mixed Data Set Status */
|
||||
enum {
|
||||
SND_UMP_MIXED_DATA_SET_STATUS_HEADER = 8,
|
||||
SND_UMP_MIXED_DATA_SET_STATUS_PAYLOAD = 9,
|
||||
};
|
||||
|
||||
/** UMP Utility Type Status (type 0x0) **/
|
||||
enum {
|
||||
SND_UMP_UTILITY_MSG_STATUS_NOOP = 0x00,
|
||||
|
|
@ -567,6 +970,60 @@ enum {
|
|||
SND_UMP_STREAM_MSG_FORMAT_END = 3,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Format bits */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_FORMAT_SINGLE = 0,
|
||||
SND_UMP_FLEX_DATA_MSG_FORMAT_START = 1,
|
||||
SND_UMP_FLEX_DATA_MSG_FORMAT_CONTINUE = 2,
|
||||
SND_UMP_FLEX_DATA_MSG_FORMAT_END = 3,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Address bits */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_ADDR_CHANNEL = 0,
|
||||
SND_UMP_FLEX_DATA_MSG_ADDR_GROUP = 1,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Status Bank bits */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_BANK_SETUP = 0,
|
||||
SND_UMP_FLEX_DATA_MSG_BANK_METADATA = 1,
|
||||
SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT = 2,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Status bits for Setup (Status Bank = 0) */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SET_TEMPO = 0x00,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SET_TIME_SIGNATURE = 0x01,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SET_METRONOME = 0x02,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SET_KEY_SIGNATURE = 0x05,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SET_CHORD_NAME = 0x06,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Status bits for Metadata (Status Bank = 1) */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_PROJECT_NAME = 0x01,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_SONG_NAME = 0x02,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_MIDI_CLIP_NAME = 0x03,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_COPYRIGHT_NOTICE = 0x04,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_COMPOSER_NAME = 0x05,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_LYRICIST_NAME = 0x06,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_ARRANGER_NAME = 0x07,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_PUBLISHER_NAME = 0x08,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_PRIMARY_PERFORMER = 0x09,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_ACCOMPANY_PERFORMAER = 0x0a,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_RECORDING_DATE = 0x0b,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_RECORDING_LOCATION = 0x0c,
|
||||
};
|
||||
|
||||
/** UMP Flex Data Status bits for Performance Text Events (Status Bank = 2) */
|
||||
enum {
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_LYRICS = 0x01,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_LYRICS_LANGUAGE = 0x02,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_RUBY = 0x03,
|
||||
SND_UMP_FLEX_DATA_MSG_STATUS_RUBY_LANGUAGE = 0x04,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief get UMP status (4bit) from 32bit UMP message header
|
||||
*/
|
||||
|
|
@ -655,8 +1112,21 @@ static inline uint8_t snd_ump_sysex_msg_length(const uint32_t *ump)
|
|||
return (*ump >> 16) & 0xf;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief extract one byte from a UMP packet
|
||||
*/
|
||||
static inline uint8_t snd_ump_get_byte(const uint32_t *ump, unsigned int offset)
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
return ((const uint8_t *)ump)[offset];
|
||||
#else
|
||||
return ((const uint8_t *)ump)[(offset & ~3) | (3 - (offset & 3))];
|
||||
#endif
|
||||
}
|
||||
|
||||
int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen,
|
||||
size_t *filled);
|
||||
int snd_ump_packet_length(unsigned int type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ endif
|
|||
if BUILD_RAWMIDI
|
||||
SUBDIRS += rawmidi
|
||||
libasound_la_LIBADD += rawmidi/librawmidi.la
|
||||
VERSION_CPPFLAGS += -DHAVE_RAWMIDI_SYMS
|
||||
endif
|
||||
if BUILD_HWDEP
|
||||
SUBDIRS += hwdep
|
||||
|
|
@ -44,18 +45,12 @@ endif
|
|||
if BUILD_SEQ
|
||||
SUBDIRS += seq
|
||||
libasound_la_LIBADD += seq/libseq.la
|
||||
VERSION_CPPFLAGS += -DHAVE_SEQ_SYMS
|
||||
endif
|
||||
if BUILD_UCM
|
||||
SUBDIRS += ucm
|
||||
libasound_la_LIBADD += ucm/libucm.la
|
||||
endif
|
||||
if BUILD_ALISP
|
||||
if VERSIONED_SYMBOLS
|
||||
VERSION_CPPFLAGS += -DHAVE_ALISP_SYMS
|
||||
endif
|
||||
SUBDIRS += alisp
|
||||
libasound_la_LIBADD += alisp/libalisp.la
|
||||
endif
|
||||
SUBDIRS += conf
|
||||
libasound_la_LIBADD += @ALSA_DEPLIBS@
|
||||
|
||||
|
|
@ -100,7 +95,4 @@ topology/libtopology.la:
|
|||
instr/libinstr.la:
|
||||
$(MAKE) -C instr libinstr.la
|
||||
|
||||
alisp/libalisp.la:
|
||||
$(MAKE) -C alisp libalisp.la
|
||||
|
||||
AM_CPPFLAGS=-I$(top_srcdir)/include
|
||||
|
|
|
|||
|
|
@ -129,19 +129,9 @@ ALSA_0.9.3 {
|
|||
} ALSA_0.9.0;
|
||||
|
||||
ALSA_0.9.5 {
|
||||
#ifdef HAVE_ALISP_SYMS
|
||||
global:
|
||||
|
||||
@SYMBOL_PREFIX@alsa_lisp;
|
||||
#endif
|
||||
} ALSA_0.9.3;
|
||||
|
||||
ALSA_0.9.7 {
|
||||
#ifdef HAVE_ALISP_SYMS
|
||||
global:
|
||||
|
||||
@SYMBOL_PREFIX@alsa_lisp_*;
|
||||
#endif
|
||||
} ALSA_0.9.5;
|
||||
|
||||
ALSA_1.1.6 {
|
||||
|
|
@ -169,10 +159,13 @@ ALSA_1.2.9 {
|
|||
ALSA_1.2.10 {
|
||||
global:
|
||||
|
||||
#ifdef HAVE_RAWMIDI_SYMS
|
||||
@SYMBOL_PREFIX@snd_ump_*;
|
||||
#endif
|
||||
@SYMBOL_PREFIX@snd_ctl_ump_next_device;
|
||||
@SYMBOL_PREFIX@snd_ctl_ump_endpoint_info;
|
||||
@SYMBOL_PREFIX@snd_ctl_ump_block_info;
|
||||
#ifdef HAVE_SEQ_SYMS
|
||||
@SYMBOL_PREFIX@snd_seq_ump_*;
|
||||
@SYMBOL_PREFIX@snd_seq_client_info_get_midi_version;
|
||||
@SYMBOL_PREFIX@snd_seq_client_info_get_ump_group_enabled;
|
||||
|
|
@ -192,4 +185,32 @@ ALSA_1.2.10 {
|
|||
@SYMBOL_PREFIX@snd_seq_port_info_set_ump_group;
|
||||
@SYMBOL_PREFIX@snd_seq_set_client_midi_version;
|
||||
@SYMBOL_PREFIX@snd_seq_set_client_ump_conversion;
|
||||
#endif
|
||||
} ALSA_1.2.9;
|
||||
|
||||
ALSA_1.2.13 {
|
||||
#if defined(HAVE_PCM_SYMS) || defined(HAVE_SEQ_SYMS) || defined(HAVE_RAWMIDI_SYMS)
|
||||
global:
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PCM_SYMS
|
||||
@SYMBOL_PREFIX@snd_pcm_hw_params_get_sync;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SEQ_SYMS
|
||||
@SYMBOL_PREFIX@snd_seq_create_ump_endpoint;
|
||||
@SYMBOL_PREFIX@snd_seq_create_ump_block;
|
||||
@SYMBOL_PREFIX@snd_seq_queue_tempo_get_tempo_base;
|
||||
@SYMBOL_PREFIX@snd_seq_queue_tempo_set_tempo_base;
|
||||
@SYMBOL_PREFIX@snd_seq_has_queue_tempo_base;
|
||||
@SYMBOL_PREFIX@snd_seq_port_info_get_ump_is_midi1;
|
||||
@SYMBOL_PREFIX@snd_seq_port_info_set_ump_is_midi1;
|
||||
#endif
|
||||
#ifdef HAVE_RAWMIDI_SYMS
|
||||
@SYMBOL_PREFIX@snd_ump_endpoint_info_clear;
|
||||
@SYMBOL_PREFIX@snd_ump_endpoint_info_set_*;
|
||||
@SYMBOL_PREFIX@snd_ump_block_info_clear;
|
||||
@SYMBOL_PREFIX@snd_ump_block_info_set_*;
|
||||
@SYMBOL_PREFIX@snd_ump_packet_length;
|
||||
#endif
|
||||
} ALSA_1.2.10;
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
EXTRA_LTLIBRARIES = libalisp.la
|
||||
|
||||
EXTRA_DIST = alisp_snd.c
|
||||
|
||||
libalisp_la_SOURCES = alisp.c
|
||||
|
||||
noinst_HEADERS = alisp_local.h
|
||||
|
||||
all: libalisp.la
|
||||
|
||||
AM_CPPFLAGS=-I$(top_srcdir)/include
|
||||
3495
src/alisp/alisp.c
3495
src/alisp/alisp.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* ALSA lisp implementation
|
||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
* Based on work of Sandro Sigala (slisp-1.2)
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
enum alisp_tokens {
|
||||
ALISP_IDENTIFIER,
|
||||
ALISP_INTEGER,
|
||||
ALISP_FLOAT,
|
||||
ALISP_FLOATE,
|
||||
ALISP_STRING
|
||||
};
|
||||
|
||||
enum alisp_objects {
|
||||
ALISP_OBJ_INTEGER,
|
||||
ALISP_OBJ_FLOAT,
|
||||
ALISP_OBJ_IDENTIFIER,
|
||||
ALISP_OBJ_STRING,
|
||||
ALISP_OBJ_POINTER,
|
||||
ALISP_OBJ_CONS,
|
||||
ALISP_OBJ_LAST_SEARCH = ALISP_OBJ_CONS,
|
||||
ALISP_OBJ_NIL,
|
||||
ALISP_OBJ_T,
|
||||
};
|
||||
|
||||
struct alisp_object;
|
||||
|
||||
#define ALISP_TYPE_MASK 0xf0000000
|
||||
#define ALISP_TYPE_SHIFT 28
|
||||
#define ALISP_REFS_MASK 0x0fffffff
|
||||
#define ALISP_REFS_SHIFT 0
|
||||
#define ALISP_MAX_REFS (ALISP_REFS_MASK>>ALISP_REFS_SHIFT)
|
||||
#define ALISP_MAX_REFS_LIMIT ((ALISP_MAX_REFS + 1) / 2)
|
||||
|
||||
struct alisp_object {
|
||||
struct list_head list;
|
||||
unsigned int type_refs; /* type and count of references */
|
||||
union {
|
||||
char *s;
|
||||
long i;
|
||||
double f;
|
||||
const void *ptr;
|
||||
struct {
|
||||
struct alisp_object *car;
|
||||
struct alisp_object *cdr;
|
||||
} c;
|
||||
} value;
|
||||
};
|
||||
|
||||
static inline enum alisp_objects alisp_get_type(struct alisp_object *p)
|
||||
{
|
||||
return (p->type_refs >> ALISP_TYPE_SHIFT);
|
||||
}
|
||||
|
||||
static inline void alisp_set_type(struct alisp_object *p, enum alisp_objects type)
|
||||
{
|
||||
p->type_refs &= ~ALISP_TYPE_MASK;
|
||||
p->type_refs |= (unsigned int)type << ALISP_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
static inline int alisp_compare_type(struct alisp_object *p, enum alisp_objects type)
|
||||
{
|
||||
return ((unsigned int)type << ALISP_TYPE_SHIFT) ==
|
||||
(p->type_refs & ALISP_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline void alisp_set_refs(struct alisp_object *p, unsigned int refs)
|
||||
{
|
||||
p->type_refs &= ~ALISP_REFS_MASK;
|
||||
p->type_refs |= refs & ALISP_REFS_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int alisp_get_refs(struct alisp_object *p)
|
||||
{
|
||||
return p->type_refs & ALISP_REFS_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int alisp_inc_refs(struct alisp_object *p)
|
||||
{
|
||||
unsigned r = alisp_get_refs(p) + 1;
|
||||
alisp_set_refs(p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline unsigned int alisp_dec_refs(struct alisp_object *p)
|
||||
{
|
||||
unsigned r = alisp_get_refs(p) - 1;
|
||||
alisp_set_refs(p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct alisp_object_pair {
|
||||
struct list_head list;
|
||||
const char *name;
|
||||
struct alisp_object *value;
|
||||
};
|
||||
|
||||
#define ALISP_LEX_BUF_MAX 16
|
||||
#define ALISP_OBJ_PAIR_HASH_SHIFT 4
|
||||
#define ALISP_OBJ_PAIR_HASH_SIZE (1<<ALISP_OBJ_PAIR_HASH_SHIFT)
|
||||
#define ALISP_OBJ_PAIR_HASH_MASK (ALISP_OBJ_PAIR_HASH_SIZE-1)
|
||||
#define ALISP_FREE_OBJ_POOL 512 /* free objects above this pool */
|
||||
|
||||
struct alisp_instance {
|
||||
int verbose: 1,
|
||||
warning: 1,
|
||||
debug: 1;
|
||||
/* i/o */
|
||||
snd_input_t *in;
|
||||
snd_output_t *out;
|
||||
snd_output_t *eout; /* error output */
|
||||
snd_output_t *vout; /* verbose output */
|
||||
snd_output_t *wout; /* warning output */
|
||||
snd_output_t *dout; /* debug output */
|
||||
/* lexer */
|
||||
int charno;
|
||||
int lineno;
|
||||
int lex_buf[ALISP_LEX_BUF_MAX];
|
||||
int *lex_bufp;
|
||||
char *token_buffer;
|
||||
int token_buffer_max;
|
||||
int thistoken;
|
||||
/* object allocator / storage */
|
||||
long free_objs;
|
||||
long used_objs;
|
||||
long max_objs;
|
||||
struct list_head free_objs_list;
|
||||
struct list_head used_objs_list[ALISP_OBJ_PAIR_HASH_SIZE][ALISP_OBJ_LAST_SEARCH + 1];
|
||||
/* set object */
|
||||
struct list_head setobjs_list[ALISP_OBJ_PAIR_HASH_SIZE];
|
||||
};
|
||||
|
|
@ -1,936 +0,0 @@
|
|||
/*
|
||||
* ALSA lisp implementation - sound related commands
|
||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@perex.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../control/control_local.h"
|
||||
|
||||
struct acall_table {
|
||||
const char *name;
|
||||
struct alisp_object * (*func) (struct alisp_instance *instance, struct acall_table * item, struct alisp_object * args);
|
||||
void * xfunc;
|
||||
const char *prefix;
|
||||
};
|
||||
|
||||
/*
|
||||
* helper functions
|
||||
*/
|
||||
|
||||
static inline int get_integer(struct alisp_object * obj)
|
||||
{
|
||||
if (alisp_compare_type(obj, ALISP_OBJ_INTEGER))
|
||||
return obj->value.i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const void *get_pointer(struct alisp_object * obj)
|
||||
{
|
||||
if (alisp_compare_type(obj, ALISP_OBJ_POINTER))
|
||||
return obj->value.ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_string(struct alisp_object * obj, const char * deflt)
|
||||
{
|
||||
if (obj == &alsa_lisp_t)
|
||||
return "true";
|
||||
if (alisp_compare_type(obj, ALISP_OBJ_STRING) ||
|
||||
alisp_compare_type(obj, ALISP_OBJ_IDENTIFIER))
|
||||
return obj->value.s;
|
||||
return deflt;
|
||||
}
|
||||
|
||||
struct flags {
|
||||
const char *key;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
static unsigned int get_flags(struct alisp_instance * instance,
|
||||
struct alisp_object * obj,
|
||||
const struct flags * flags,
|
||||
unsigned int deflt)
|
||||
{
|
||||
const char *key;
|
||||
int invert;
|
||||
unsigned int result;
|
||||
const struct flags *ptr;
|
||||
struct alisp_object *n;
|
||||
|
||||
if (obj == &alsa_lisp_nil)
|
||||
return deflt;
|
||||
result = deflt;
|
||||
do {
|
||||
key = get_string(obj, NULL);
|
||||
if (key) {
|
||||
invert = key[0] == '!';
|
||||
key += invert;
|
||||
ptr = flags;
|
||||
while (ptr->key) {
|
||||
if (!strcmp(ptr->key, key)) {
|
||||
if (invert)
|
||||
result &= ~ptr->mask;
|
||||
else
|
||||
result |= ptr->mask;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
delete_tree(instance, car(obj));
|
||||
obj = cdr(n = obj);
|
||||
delete_object(instance, n);
|
||||
} while (obj != &alsa_lisp_nil);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const void *get_ptr(struct alisp_instance * instance,
|
||||
struct alisp_object * obj,
|
||||
const char *_ptr_id)
|
||||
{
|
||||
const char *ptr_id;
|
||||
const void *ptr;
|
||||
|
||||
ptr_id = get_string(car(obj), NULL);
|
||||
if (ptr_id == NULL) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(ptr_id, _ptr_id)) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
ptr = get_pointer(cdr(obj));
|
||||
delete_tree(instance, obj);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static struct alisp_object * new_lexpr(struct alisp_instance * instance, int err)
|
||||
{
|
||||
struct alisp_object * lexpr;
|
||||
|
||||
lexpr = new_object(instance, ALISP_OBJ_CONS);
|
||||
if (lexpr == NULL)
|
||||
return NULL;
|
||||
lexpr->value.c.car = new_integer(instance, err);
|
||||
if (lexpr->value.c.car == NULL) {
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS);
|
||||
if (lexpr->value.c.cdr == NULL) {
|
||||
delete_object(instance, lexpr->value.c.car);
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * add_cons(struct alisp_instance * instance,
|
||||
struct alisp_object *lexpr,
|
||||
int cdr, const char *id,
|
||||
struct alisp_object *obj)
|
||||
{
|
||||
struct alisp_object * p1, * p2;
|
||||
|
||||
if (lexpr == NULL || obj == NULL) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
if (cdr) {
|
||||
p1 = lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS);
|
||||
} else {
|
||||
p1 = lexpr->value.c.car = new_object(instance, ALISP_OBJ_CONS);
|
||||
}
|
||||
lexpr = p1;
|
||||
if (p1 == NULL) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
p1->value.c.car = new_object(instance, ALISP_OBJ_CONS);
|
||||
if ((p2 = p1->value.c.car) == NULL)
|
||||
goto __err;
|
||||
p2->value.c.car = new_string(instance, id);
|
||||
if (p2->value.c.car == NULL) {
|
||||
__err:
|
||||
if (cdr)
|
||||
lexpr->value.c.cdr = NULL;
|
||||
else
|
||||
lexpr->value.c.car = NULL;
|
||||
delete_tree(instance, p1);
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
p2->value.c.cdr = obj;
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * add_cons2(struct alisp_instance * instance,
|
||||
struct alisp_object *lexpr,
|
||||
int cdr, struct alisp_object *obj)
|
||||
{
|
||||
struct alisp_object * p1;
|
||||
|
||||
if (lexpr == NULL || obj == NULL) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
if (cdr) {
|
||||
p1 = lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS);
|
||||
} else {
|
||||
p1 = lexpr->value.c.car = new_object(instance, ALISP_OBJ_CONS);
|
||||
}
|
||||
lexpr = p1;
|
||||
if (p1 == NULL) {
|
||||
delete_tree(instance, obj);
|
||||
return NULL;
|
||||
}
|
||||
p1->value.c.car = obj;
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * new_result1(struct alisp_instance * instance,
|
||||
int err, const char *ptr_id, void *ptr)
|
||||
{
|
||||
struct alisp_object * lexpr, * p1;
|
||||
|
||||
if (err < 0)
|
||||
ptr = NULL;
|
||||
lexpr = new_object(instance, ALISP_OBJ_CONS);
|
||||
if (lexpr == NULL)
|
||||
return NULL;
|
||||
lexpr->value.c.car = new_integer(instance, err);
|
||||
if (lexpr->value.c.car == NULL) {
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
p1 = add_cons(instance, lexpr, 1, ptr_id, new_pointer(instance, ptr));
|
||||
if (p1 == NULL) {
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * new_result2(struct alisp_instance * instance,
|
||||
int err, int val)
|
||||
{
|
||||
struct alisp_object * lexpr, * p1;
|
||||
|
||||
if (err < 0)
|
||||
val = 0;
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (lexpr == NULL)
|
||||
return NULL;
|
||||
p1 = lexpr->value.c.cdr;
|
||||
p1->value.c.car = new_integer(instance, val);
|
||||
if (p1->value.c.car == NULL) {
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * new_result3(struct alisp_instance * instance,
|
||||
int err, const char *str)
|
||||
{
|
||||
struct alisp_object * lexpr, * p1;
|
||||
|
||||
if (err < 0)
|
||||
str = "";
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (lexpr == NULL)
|
||||
return NULL;
|
||||
p1 = lexpr->value.c.cdr;
|
||||
p1->value.c.car = new_string(instance, str);
|
||||
if (p1->value.c.car == NULL) {
|
||||
delete_object(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
/*
|
||||
* macros
|
||||
*/
|
||||
|
||||
/*
|
||||
* HCTL functions
|
||||
*/
|
||||
|
||||
typedef int (*snd_int_pp_strp_int_t)(void **rctl, const char *name, int mode);
|
||||
typedef int (*snd_int_pp_p_t)(void **rctl, void *handle);
|
||||
typedef int (*snd_int_p_t)(void *rctl);
|
||||
typedef char * (*snd_str_p_t)(void *rctl);
|
||||
typedef int (*snd_int_intp_t)(int *val);
|
||||
typedef int (*snd_int_str_t)(const char *str);
|
||||
typedef int (*snd_int_int_strp_t)(int val, char **str);
|
||||
typedef void *(*snd_p_p_t)(void *handle);
|
||||
|
||||
static struct alisp_object * FA_int_pp_strp_int(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
const char *name;
|
||||
int err, mode;
|
||||
void *handle;
|
||||
struct alisp_object *p1, *p2;
|
||||
static const struct flags flags[] = {
|
||||
{ "nonblock", SND_CTL_NONBLOCK },
|
||||
{ "async", SND_CTL_ASYNC },
|
||||
{ "readonly", SND_CTL_READONLY },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
name = get_string(p1 = eval(instance, car(args)), NULL);
|
||||
if (name == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
mode = get_flags(instance, p2 = eval(instance, car(cdr(args))), flags, 0);
|
||||
delete_tree(instance, cdr(cdr(args)));
|
||||
delete_object(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
delete_tree(instance, p2);
|
||||
err = ((snd_int_pp_strp_int_t)item->xfunc)(&handle, name, mode);
|
||||
delete_tree(instance, p1);
|
||||
return new_result1(instance, err, item->prefix, handle);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_int_pp_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
int err;
|
||||
void *handle;
|
||||
const char *prefix1;
|
||||
struct alisp_object *p1;
|
||||
|
||||
if (item->xfunc == &snd_hctl_open_ctl)
|
||||
prefix1 = "ctl";
|
||||
else {
|
||||
delete_tree(instance, args);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (void *)get_ptr(instance, p1, prefix1);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
err = ((snd_int_pp_p_t)item->xfunc)(&handle, handle);
|
||||
return new_result1(instance, err, item->prefix, handle);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_p_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
void *handle;
|
||||
const char *prefix1;
|
||||
struct alisp_object * p1;
|
||||
|
||||
if (item->xfunc == &snd_hctl_first_elem ||
|
||||
item->xfunc == &snd_hctl_last_elem ||
|
||||
item->xfunc == &snd_hctl_elem_next ||
|
||||
item->xfunc == &snd_hctl_elem_prev)
|
||||
prefix1 = "hctl_elem";
|
||||
else if (item->xfunc == &snd_hctl_ctl)
|
||||
prefix1 = "ctl";
|
||||
else {
|
||||
delete_tree(instance, args);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (void *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
handle = ((snd_p_p_t)item->xfunc)(handle);
|
||||
return new_cons_pointer(instance, prefix1, handle);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_int_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
void *handle;
|
||||
struct alisp_object * p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (void *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
return new_integer(instance, ((snd_int_p_t)item->xfunc)(handle));
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_str_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
void *handle;
|
||||
struct alisp_object * p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (void *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
return new_string(instance, ((snd_str_p_t)item->xfunc)(handle));
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_int_intp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
int val, err;
|
||||
struct alisp_object * p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
if (!alisp_compare_type(p1, ALISP_OBJ_INTEGER)) {
|
||||
delete_tree(instance, p1);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
val = p1->value.i;
|
||||
delete_tree(instance, p1);
|
||||
err = ((snd_int_intp_t)item->xfunc)(&val);
|
||||
return new_result2(instance, err, val);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_int_str(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
int err;
|
||||
struct alisp_object * p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
if (!alisp_compare_type(p1, ALISP_OBJ_STRING) &&
|
||||
!alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER)) {
|
||||
delete_tree(instance, p1);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
err = ((snd_int_str_t)item->xfunc)(p1->value.s);
|
||||
delete_tree(instance, p1);
|
||||
return new_integer(instance, err);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_int_int_strp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
int err;
|
||||
char *str;
|
||||
long val;
|
||||
struct alisp_object * p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
if (!alisp_compare_type(p1, ALISP_OBJ_INTEGER)) {
|
||||
delete_tree(instance, p1);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
val = p1->value.i;
|
||||
delete_tree(instance, p1);
|
||||
err = ((snd_int_int_strp_t)item->xfunc)(val, &str);
|
||||
return new_result3(instance, err, str);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_card_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_ctl_t *handle;
|
||||
struct alisp_object * lexpr, * p1;
|
||||
snd_ctl_card_info_t info = {0};
|
||||
int err;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (snd_ctl_t *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
err = snd_ctl_card_info(handle, &info);
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (err < 0)
|
||||
return lexpr;
|
||||
p1 = add_cons(instance, lexpr->value.c.cdr, 0, "id", new_string(instance, snd_ctl_card_info_get_id(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "driver", new_string(instance, snd_ctl_card_info_get_driver(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "name", new_string(instance, snd_ctl_card_info_get_name(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "longname", new_string(instance, snd_ctl_card_info_get_longname(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "mixername", new_string(instance, snd_ctl_card_info_get_mixername(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "components", new_string(instance, snd_ctl_card_info_get_components(&info)));
|
||||
if (p1 == NULL) {
|
||||
delete_tree(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * create_ctl_elem_id(struct alisp_instance * instance, snd_ctl_elem_id_t * id, struct alisp_object * cons)
|
||||
{
|
||||
cons = add_cons(instance, cons, 0, "numid", new_integer(instance, snd_ctl_elem_id_get_numid(id)));
|
||||
cons = add_cons(instance, cons, 1, "iface", new_string(instance, snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id))));
|
||||
cons = add_cons(instance, cons, 1, "dev", new_integer(instance, snd_ctl_elem_id_get_device(id)));
|
||||
cons = add_cons(instance, cons, 1, "subdev", new_integer(instance, snd_ctl_elem_id_get_subdevice(id)));
|
||||
cons = add_cons(instance, cons, 1, "name", new_string(instance, snd_ctl_elem_id_get_name(id)));
|
||||
cons = add_cons(instance, cons, 1, "index", new_integer(instance, snd_ctl_elem_id_get_index(id)));
|
||||
return cons;
|
||||
}
|
||||
|
||||
static int parse_ctl_elem_id(struct alisp_instance * instance,
|
||||
struct alisp_object * cons,
|
||||
snd_ctl_elem_id_t * id)
|
||||
{
|
||||
struct alisp_object *p1;
|
||||
const char *xid;
|
||||
|
||||
if (cons == NULL)
|
||||
return -ENOMEM;
|
||||
snd_ctl_elem_id_clear(id);
|
||||
id->numid = 0;
|
||||
do {
|
||||
p1 = car(cons);
|
||||
if (alisp_compare_type(p1, ALISP_OBJ_CONS)) {
|
||||
xid = get_string(p1->value.c.car, NULL);
|
||||
if (xid == NULL) {
|
||||
/* noop */
|
||||
} else if (!strcmp(xid, "numid")) {
|
||||
snd_ctl_elem_id_set_numid(id, get_integer(p1->value.c.cdr));
|
||||
} else if (!strcmp(xid, "iface")) {
|
||||
snd_ctl_elem_id_set_interface(id, snd_config_get_ctl_iface_ascii(get_string(p1->value.c.cdr, "0")));
|
||||
} else if (!strcmp(xid, "dev")) {
|
||||
snd_ctl_elem_id_set_device(id, get_integer(p1->value.c.cdr));
|
||||
} else if (!strcmp(xid, "subdev")) {
|
||||
snd_ctl_elem_id_set_subdevice(id, get_integer(p1->value.c.cdr));
|
||||
} else if (!strcmp(xid, "name")) {
|
||||
snd_ctl_elem_id_set_name(id, get_string(p1->value.c.cdr, "?"));
|
||||
} else if (!strcmp(xid, "index")) {
|
||||
snd_ctl_elem_id_set_index(id, get_integer(p1->value.c.cdr));
|
||||
}
|
||||
}
|
||||
delete_tree(instance, p1);
|
||||
cons = cdr(p1 = cons);
|
||||
delete_object(instance, p1);
|
||||
} while (cons != &alsa_lisp_nil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_hctl_find_elem(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_hctl_t *handle;
|
||||
snd_ctl_elem_id_t id = {0};
|
||||
struct alisp_object *p1;
|
||||
|
||||
handle = (snd_hctl_t *)get_ptr(instance, car(args), item->prefix);
|
||||
if (handle == NULL) {
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
p1 = car(cdr(args));
|
||||
delete_tree(instance, cdr(cdr(args)));
|
||||
delete_object(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
if (parse_ctl_elem_id(instance, eval(instance, p1), &id) < 0)
|
||||
return &alsa_lisp_nil;
|
||||
return new_cons_pointer(instance, "hctl_elem", snd_hctl_find_elem(handle, &id));
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_hctl_elem_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_hctl_elem_t *handle;
|
||||
struct alisp_object * lexpr, * p1, * p2;
|
||||
snd_ctl_elem_info_t info = {0};
|
||||
snd_ctl_elem_id_t id = {0};
|
||||
snd_ctl_elem_type_t type;
|
||||
int err;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (snd_hctl_elem_t *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
err = snd_hctl_elem_info(handle, &info);
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (err < 0)
|
||||
return lexpr;
|
||||
type = snd_ctl_elem_info_get_type(&info);
|
||||
p1 = add_cons(instance, lexpr->value.c.cdr, 0, "id", p2 = new_object(instance, ALISP_OBJ_CONS));
|
||||
snd_ctl_elem_info_get_id(&info, &id);
|
||||
if (create_ctl_elem_id(instance, &id, p2) == NULL) {
|
||||
delete_tree(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
p1 = add_cons(instance, p1, 1, "type", new_string(instance, snd_ctl_elem_type_name(type)));
|
||||
p1 = add_cons(instance, p1, 1, "readable", new_integer(instance, snd_ctl_elem_info_is_readable(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "writable", new_integer(instance, snd_ctl_elem_info_is_writable(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "volatile", new_integer(instance, snd_ctl_elem_info_is_volatile(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "inactive", new_integer(instance, snd_ctl_elem_info_is_inactive(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "locked", new_integer(instance, snd_ctl_elem_info_is_locked(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "isowner", new_integer(instance, snd_ctl_elem_info_is_owner(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "owner", new_integer(instance, snd_ctl_elem_info_get_owner(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "count", new_integer(instance, snd_ctl_elem_info_get_count(&info)));
|
||||
err = INTERNAL(snd_ctl_elem_info_get_dimensions)(&info);
|
||||
if (err > 0) {
|
||||
int idx;
|
||||
p1 = add_cons(instance, p1, 1, "dimensions", p2 = new_object(instance, ALISP_OBJ_CONS));
|
||||
for (idx = 0; idx < err; idx++)
|
||||
p2 = add_cons2(instance, p2, idx > 0, new_integer(instance, INTERNAL(snd_ctl_elem_info_get_dimension)(&info, idx)));
|
||||
}
|
||||
switch (type) {
|
||||
case SND_CTL_ELEM_TYPE_ENUMERATED: {
|
||||
unsigned int items, item;
|
||||
items = snd_ctl_elem_info_get_items(&info);
|
||||
p1 = add_cons(instance, p1, 1, "items", p2 = new_object(instance, ALISP_OBJ_CONS));
|
||||
for (item = 0; item < items; item++) {
|
||||
snd_ctl_elem_info_set_item(&info, item);
|
||||
err = snd_hctl_elem_info(handle, &info);
|
||||
if (err < 0) {
|
||||
p2 = add_cons2(instance, p2, item, &alsa_lisp_nil);
|
||||
} else {
|
||||
p2 = add_cons2(instance, p2, item, new_string(instance, snd_ctl_elem_info_get_item_name(&info)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SND_CTL_ELEM_TYPE_INTEGER:
|
||||
p1 = add_cons(instance, p1, 1, "min", new_integer(instance, snd_ctl_elem_info_get_min(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "max", new_integer(instance, snd_ctl_elem_info_get_max(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "step", new_integer(instance, snd_ctl_elem_info_get_step(&info)));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER64:
|
||||
p1 = add_cons(instance, p1, 1, "min64", new_float(instance, snd_ctl_elem_info_get_min64(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "max64", new_float(instance, snd_ctl_elem_info_get_max64(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "step64", new_float(instance, snd_ctl_elem_info_get_step64(&info)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (p1 == NULL) {
|
||||
delete_tree(instance, lexpr);
|
||||
return NULL;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_hctl_elem_read(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_hctl_elem_t *handle;
|
||||
struct alisp_object * lexpr, * p1 = NULL, * obj;
|
||||
snd_ctl_elem_info_t info = {0};
|
||||
snd_ctl_elem_value_t value = {0};
|
||||
snd_ctl_elem_type_t type;
|
||||
unsigned int idx, count;
|
||||
int err;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (snd_hctl_elem_t *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
err = snd_hctl_elem_info(handle, &info);
|
||||
if (err >= 0)
|
||||
err = snd_hctl_elem_read(handle, &value);
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (err < 0)
|
||||
return lexpr;
|
||||
type = snd_ctl_elem_info_get_type(&info);
|
||||
count = snd_ctl_elem_info_get_count(&info);
|
||||
if (type == SND_CTL_ELEM_TYPE_IEC958) {
|
||||
count = sizeof(snd_aes_iec958_t);
|
||||
type = SND_CTL_ELEM_TYPE_BYTES;
|
||||
}
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
switch (type) {
|
||||
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
||||
obj = new_integer(instance, snd_ctl_elem_value_get_boolean(&value, idx));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER:
|
||||
obj = new_integer(instance, snd_ctl_elem_value_get_integer(&value, idx));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER64:
|
||||
obj = new_integer(instance, snd_ctl_elem_value_get_integer64(&value, idx));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
||||
obj = new_integer(instance, snd_ctl_elem_value_get_enumerated(&value, idx));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_BYTES:
|
||||
obj = new_integer(instance, snd_ctl_elem_value_get_byte(&value, idx));
|
||||
break;
|
||||
default:
|
||||
obj = NULL;
|
||||
break;
|
||||
}
|
||||
if (idx == 0) {
|
||||
p1 = add_cons2(instance, lexpr->value.c.cdr, 0, obj);
|
||||
} else {
|
||||
p1 = add_cons2(instance, p1, 1, obj);
|
||||
}
|
||||
}
|
||||
if (p1 == NULL) {
|
||||
delete_tree(instance, lexpr);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_hctl_elem_write(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_hctl_elem_t *handle;
|
||||
struct alisp_object * p1 = NULL, * obj;
|
||||
snd_ctl_elem_info_t info = {0};
|
||||
snd_ctl_elem_value_t value = {0};
|
||||
snd_ctl_elem_type_t type;
|
||||
unsigned int idx, count;
|
||||
int err;
|
||||
|
||||
p1 = car(cdr(args));
|
||||
obj = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(cdr(args)));
|
||||
delete_object(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (snd_hctl_elem_t *)get_ptr(instance, obj, item->prefix);
|
||||
if (handle == NULL) {
|
||||
delete_tree(instance, p1);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
err = snd_hctl_elem_info(handle, &info);
|
||||
if (err < 0) {
|
||||
delete_tree(instance, p1);
|
||||
return new_integer(instance, err);
|
||||
}
|
||||
type = snd_ctl_elem_info_get_type(&info);
|
||||
count = snd_ctl_elem_info_get_count(&info);
|
||||
if (type == SND_CTL_ELEM_TYPE_IEC958) {
|
||||
count = sizeof(snd_aes_iec958_t);
|
||||
type = SND_CTL_ELEM_TYPE_BYTES;
|
||||
}
|
||||
idx = -1;
|
||||
do {
|
||||
if (++idx >= count) {
|
||||
delete_tree(instance, p1);
|
||||
break;
|
||||
}
|
||||
obj = car(p1);
|
||||
switch (type) {
|
||||
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
||||
snd_ctl_elem_value_set_boolean(&value, idx, get_integer(obj));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER:
|
||||
snd_ctl_elem_value_set_integer(&value, idx, get_integer(obj));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER64:
|
||||
snd_ctl_elem_value_set_integer64(&value, idx, get_integer(obj));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
||||
snd_ctl_elem_value_set_enumerated(&value, idx, get_integer(obj));
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_BYTES:
|
||||
snd_ctl_elem_value_set_byte(&value, idx, get_integer(obj));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delete_tree(instance, obj);
|
||||
p1 = cdr(obj = p1);
|
||||
delete_object(instance, obj);
|
||||
} while (p1 != &alsa_lisp_nil);
|
||||
err = snd_hctl_elem_write(handle, &value);
|
||||
return new_integer(instance, err);
|
||||
}
|
||||
|
||||
static struct alisp_object * FA_pcm_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
|
||||
{
|
||||
snd_pcm_t *handle;
|
||||
struct alisp_object * lexpr, * p1;
|
||||
snd_pcm_info_t info = {0};
|
||||
int err;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
handle = (snd_pcm_t *)get_ptr(instance, p1, item->prefix);
|
||||
if (handle == NULL)
|
||||
return &alsa_lisp_nil;
|
||||
err = snd_pcm_info(handle, &info);
|
||||
lexpr = new_lexpr(instance, err);
|
||||
if (err < 0)
|
||||
return lexpr;
|
||||
p1 = add_cons(instance, lexpr->value.c.cdr, 0, "card", new_integer(instance, snd_pcm_info_get_card(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "device", new_integer(instance, snd_pcm_info_get_device(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "subdevice", new_integer(instance, snd_pcm_info_get_subdevice(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "id", new_string(instance, snd_pcm_info_get_id(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "name", new_string(instance, snd_pcm_info_get_name(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "subdevice_name", new_string(instance, snd_pcm_info_get_subdevice_name(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "class", new_integer(instance, snd_pcm_info_get_class(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "subclass", new_integer(instance, snd_pcm_info_get_subclass(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "subdevices_count", new_integer(instance, snd_pcm_info_get_subdevices_count(&info)));
|
||||
p1 = add_cons(instance, p1, 1, "subdevices_avail", new_integer(instance, snd_pcm_info_get_subdevices_avail(&info)));
|
||||
//p1 = add_cons(instance, p1, 1, "sync", new_string(instance, snd_pcm_info_get_sync(&info)));
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
/*
|
||||
* main code
|
||||
*/
|
||||
|
||||
static const struct acall_table acall_table[] = {
|
||||
{ "card_get_index", &FA_int_str, (void *)snd_card_get_index, NULL },
|
||||
{ "card_get_longname", &FA_int_int_strp, (void *)snd_card_get_longname, NULL },
|
||||
{ "card_get_name", &FA_int_int_strp, (void *)snd_card_get_name, NULL },
|
||||
{ "card_next", &FA_int_intp, (void *)&snd_card_next, NULL },
|
||||
{ "ctl_card_info", &FA_card_info, NULL, "ctl" },
|
||||
{ "ctl_close", &FA_int_p, (void *)&snd_ctl_close, "ctl" },
|
||||
{ "ctl_open", &FA_int_pp_strp_int, (void *)&snd_ctl_open, "ctl" },
|
||||
{ "hctl_close", &FA_int_p, (void *)&snd_hctl_close, "hctl" },
|
||||
{ "hctl_ctl", &FA_p_p, (void *)&snd_hctl_ctl, "hctl" },
|
||||
{ "hctl_elem_info", &FA_hctl_elem_info, (void *)&snd_hctl_elem_info, "hctl_elem" },
|
||||
{ "hctl_elem_next", &FA_p_p, (void *)&snd_hctl_elem_next, "hctl_elem" },
|
||||
{ "hctl_elem_prev", &FA_p_p, (void *)&snd_hctl_elem_prev, "hctl_elem" },
|
||||
{ "hctl_elem_read", &FA_hctl_elem_read, (void *)&snd_hctl_elem_read, "hctl_elem" },
|
||||
{ "hctl_elem_write", &FA_hctl_elem_write, (void *)&snd_hctl_elem_write, "hctl_elem" },
|
||||
{ "hctl_find_elem", &FA_hctl_find_elem, (void *)&snd_hctl_find_elem, "hctl" },
|
||||
{ "hctl_first_elem", &FA_p_p, (void *)&snd_hctl_first_elem, "hctl" },
|
||||
{ "hctl_free", &FA_int_p, (void *)&snd_hctl_free, "hctl" },
|
||||
{ "hctl_last_elem", &FA_p_p, (void *)&snd_hctl_last_elem, "hctl" },
|
||||
{ "hctl_load", &FA_int_p, (void *)&snd_hctl_load, "hctl" },
|
||||
{ "hctl_open", &FA_int_pp_strp_int, (void *)&snd_hctl_open, "hctl" },
|
||||
{ "hctl_open_ctl", &FA_int_pp_p, (void *)&snd_hctl_open_ctl, "hctl" },
|
||||
{ "pcm_info", &FA_pcm_info, NULL, "pcm" },
|
||||
{ "pcm_name", &FA_str_p, (void *)&snd_pcm_name, "pcm" },
|
||||
};
|
||||
|
||||
static int acall_compar(const void *p1, const void *p2)
|
||||
{
|
||||
return strcmp(((struct acall_table *)p1)->name,
|
||||
((struct acall_table *)p2)->name);
|
||||
}
|
||||
|
||||
static struct alisp_object * F_acall(struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
struct alisp_object * p1, *p2;
|
||||
struct acall_table key, *item;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
p2 = cdr(args);
|
||||
delete_object(instance, args);
|
||||
if (!alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER) &&
|
||||
!alisp_compare_type(p1, ALISP_OBJ_STRING)) {
|
||||
delete_tree(instance, p2);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
key.name = p1->value.s;
|
||||
if ((item = bsearch(&key, acall_table,
|
||||
sizeof acall_table / sizeof acall_table[0],
|
||||
sizeof acall_table[0], acall_compar)) != NULL) {
|
||||
delete_tree(instance, p1);
|
||||
return item->func(instance, item, p2);
|
||||
}
|
||||
delete_tree(instance, p1);
|
||||
delete_tree(instance, p2);
|
||||
lisp_warn(instance, "acall function %s' is undefined", p1->value.s);
|
||||
return &alsa_lisp_nil;
|
||||
}
|
||||
|
||||
static struct alisp_object * F_ahandle(struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
struct alisp_object *p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
args = car(cdr(p1));
|
||||
delete_tree(instance, cdr(cdr(p1)));
|
||||
delete_object(instance, cdr(p1));
|
||||
delete_tree(instance, car(p1));
|
||||
delete_object(instance, p1);
|
||||
return args;
|
||||
}
|
||||
|
||||
static struct alisp_object * F_aerror(struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
struct alisp_object *p1;
|
||||
|
||||
p1 = eval(instance, car(args));
|
||||
delete_tree(instance, cdr(args));
|
||||
delete_object(instance, args);
|
||||
args = car(p1);
|
||||
if (args == &alsa_lisp_nil) {
|
||||
delete_tree(instance, p1);
|
||||
return new_integer(instance, SND_ERROR_ALISP_NIL);
|
||||
} else {
|
||||
delete_tree(instance, cdr(p1));
|
||||
delete_object(instance, p1);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
static int common_error(snd_output_t **rout, struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
struct alisp_object * p = args, * p1;
|
||||
snd_output_t *out;
|
||||
int err;
|
||||
|
||||
err = snd_output_buffer_open(&out);
|
||||
if (err < 0) {
|
||||
delete_tree(instance, args);
|
||||
return err;
|
||||
}
|
||||
|
||||
do {
|
||||
p1 = eval(instance, car(p));
|
||||
if (alisp_compare_type(p1, ALISP_OBJ_STRING))
|
||||
snd_output_printf(out, "%s", p1->value.s);
|
||||
else
|
||||
princ_object(out, p1);
|
||||
delete_tree(instance, p1);
|
||||
p = cdr(p1 = p);
|
||||
delete_object(instance, p1);
|
||||
} while (p != &alsa_lisp_nil);
|
||||
|
||||
*rout = out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct alisp_object * F_snderr(struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
snd_output_t *out;
|
||||
char *str;
|
||||
|
||||
if (common_error(&out, instance, args) < 0)
|
||||
return &alsa_lisp_nil;
|
||||
snd_output_buffer_string(out, &str);
|
||||
SNDERR(str);
|
||||
snd_output_close(out);
|
||||
return &alsa_lisp_t;
|
||||
}
|
||||
|
||||
static struct alisp_object * F_syserr(struct alisp_instance *instance, struct alisp_object * args)
|
||||
{
|
||||
snd_output_t *out;
|
||||
char *str;
|
||||
|
||||
if (common_error(&out, instance, args) < 0)
|
||||
return &alsa_lisp_nil;
|
||||
snd_output_buffer_string(out, &str);
|
||||
SYSERR(str);
|
||||
snd_output_close(out);
|
||||
return &alsa_lisp_t;
|
||||
}
|
||||
|
||||
static const struct intrinsic snd_intrinsics[] = {
|
||||
{ "Acall", F_acall },
|
||||
{ "Aerror", F_aerror },
|
||||
{ "Ahandle", F_ahandle },
|
||||
{ "Aresult", F_ahandle },
|
||||
{ "Asnderr", F_snderr },
|
||||
{ "Asyserr", F_syserr }
|
||||
};
|
||||
17
src/async.c
17
src/async.c
|
|
@ -153,9 +153,22 @@ int snd_async_del_handler(snd_async_handler_t *handler)
|
|||
int was_empty;
|
||||
assert(handler);
|
||||
if (handler->type != SND_ASYNC_HANDLER_GENERIC) {
|
||||
if (!list_empty(&handler->hlist))
|
||||
struct list_head *alist;
|
||||
switch (handler->type) {
|
||||
#ifdef BUILD_PCM
|
||||
case SND_ASYNC_HANDLER_PCM:
|
||||
alist = &handler->u.pcm->async_handlers;
|
||||
break;
|
||||
#endif
|
||||
case SND_ASYNC_HANDLER_CTL:
|
||||
alist = &handler->u.ctl->async_handlers;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!list_empty(alist))
|
||||
list_del(&handler->hlist);
|
||||
if (!list_empty(&handler->hlist))
|
||||
if (!list_empty(alist))
|
||||
goto _glist;
|
||||
switch (handler->type) {
|
||||
#ifdef BUILD_PCM
|
||||
|
|
|
|||
18
src/conf.c
18
src/conf.c
|
|
@ -1268,13 +1268,13 @@ static int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int s
|
|||
snd_config_t *n = NULL;
|
||||
|
||||
if (!skip) {
|
||||
snd_config_t *g;
|
||||
char static_id[12];
|
||||
while (1) {
|
||||
snprintf(static_id, sizeof(static_id), "%i", *idx);
|
||||
if (_snd_config_search(parent, static_id, -1, &g) == 0) {
|
||||
if (_snd_config_search(parent, static_id, -1, &n) == 0) {
|
||||
if (override) {
|
||||
snd_config_delete(n);
|
||||
n = NULL;
|
||||
} else {
|
||||
/* merge */
|
||||
(*idx)++;
|
||||
|
|
@ -1729,7 +1729,7 @@ static int _snd_config_save_children(snd_config_t *config, snd_output_t *out,
|
|||
*/
|
||||
int snd_config_substitute(snd_config_t *dst, snd_config_t *src)
|
||||
{
|
||||
assert(dst && src);
|
||||
assert(dst && src && src != dst);
|
||||
if (dst->type == SND_CONFIG_TYPE_COMPOUND) {
|
||||
int err = snd_config_delete_compound_members(dst);
|
||||
if (err < 0)
|
||||
|
|
@ -1748,6 +1748,8 @@ int snd_config_substitute(snd_config_t *dst, snd_config_t *src)
|
|||
free(dst->id);
|
||||
if (dst->type == SND_CONFIG_TYPE_STRING)
|
||||
free(dst->u.string);
|
||||
if (src->parent) /* like snd_config_remove */
|
||||
list_del(&src->list);
|
||||
dst->id = src->id;
|
||||
dst->type = src->type;
|
||||
dst->u = src->u;
|
||||
|
|
@ -2310,7 +2312,6 @@ int snd_config_merge(snd_config_t *dst, snd_config_t *src, int override)
|
|||
if (override ||
|
||||
sn->type != SND_CONFIG_TYPE_COMPOUND ||
|
||||
dn->type != SND_CONFIG_TYPE_COMPOUND) {
|
||||
snd_config_remove(sn);
|
||||
err = snd_config_substitute(dn, sn);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -4139,7 +4140,14 @@ static int config_file_load(snd_config_t *root, const char *fn, int errors)
|
|||
if (!S_ISDIR(st.st_mode))
|
||||
return config_file_open(root, fn);
|
||||
#ifndef DOC_HIDDEN
|
||||
#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__)
|
||||
#if defined(_GNU_SOURCE) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__FreeBSD__) && \
|
||||
!defined(__OpenBSD__) && \
|
||||
!defined(__DragonFly__) && \
|
||||
!defined(__sun) && \
|
||||
!defined(__ANDROID__) && \
|
||||
!defined(__OHOS__)
|
||||
#define SORTFUNC versionsort64
|
||||
#else
|
||||
#define SORTFUNC alphasort64
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
SUBDIRS=cards ctl pcm
|
||||
|
||||
cfg_files = alsa.conf
|
||||
if BUILD_ALISP
|
||||
cfg_files += sndo-mixer.alisp
|
||||
endif
|
||||
if BUILD_MODULES
|
||||
if BUILD_MIXER_MODULES
|
||||
cfg_files += smixer.conf
|
||||
|
|
|
|||
|
|
@ -60,22 +60,6 @@ cfg_files = aliases.conf \
|
|||
VXPocket.conf \
|
||||
VXPocket440.conf
|
||||
|
||||
if BUILD_ALISP
|
||||
cfg_files += aliases.alisp
|
||||
endif
|
||||
|
||||
alsa_DATA = $(cfg_files)
|
||||
|
||||
if BUILD_ALISP
|
||||
SI7018dir = $(alsaconfigdir)/cards/SI7018
|
||||
SI7018_files = \
|
||||
SI7018/sndoc-mixer.alisp \
|
||||
SI7018/sndop-mixer.alisp
|
||||
SI7018_DATA = $(SI7018_files)
|
||||
else
|
||||
SI7018_files=
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(cfg_files) \
|
||||
$(SI7018_files)
|
||||
EXTRA_DIST = $(cfg_files)
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
;
|
||||
; SiS SI7018 mixer abstract layer
|
||||
;
|
||||
; Copyright (c) 2003 Jaroslav Kysela <perex@perex.cz>
|
||||
; License: GPL v2 (http://www.gnu.org/licenses/gpl.html)
|
||||
;
|
||||
|
||||
(defun sndoc_mixer_open (hctl pcm)
|
||||
(princ "sndoc_mixer_open: hctl=" hctl " pcm=" pcm "\n")
|
||||
0
|
||||
)
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
;
|
||||
; SiS SI7018 mixer abstract layer
|
||||
;
|
||||
; Copyright (c) 2003 Jaroslav Kysela <perex@perex.cz>
|
||||
; License: GPL v2 (http://www.gnu.org/licenses/gpl.html)
|
||||
;
|
||||
|
||||
(defun sndop_mixer_open (hctl pcm)
|
||||
(princ "sndop_mixer_open: hctl=" hctl " pcm=" pcm "\n")
|
||||
0
|
||||
)
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
(setq snd_card_aliases_array
|
||||
(
|
||||
("YMF724" . "YMF744")
|
||||
("YMF724F" . "YMF744")
|
||||
("YMF740" . "YMF744")
|
||||
("YMF740C" . "YMF744")
|
||||
("YMF754" . "YMF744")
|
||||
("CMIPCI" . "CMI8338")
|
||||
("CMI8738" . "CMI8338")
|
||||
("CMI8738-MC4" . "CMI8738-MC6")
|
||||
("E-mu APS" . "EMU10K1")
|
||||
("GUS Max" . "GUS")
|
||||
("GUS ACE" . "GUS")
|
||||
("GUS Extreme" . "GUS")
|
||||
("AMD InterWave" . "GUS")
|
||||
("Dynasonic 3-D" . "GUS")
|
||||
("InterWave STB" . "GUS")
|
||||
)
|
||||
)
|
||||
|
||||
(defun snd_card_alias (cardname)
|
||||
(setq r (assq cardname snd_card_aliases_array))
|
||||
(setq r (if (null r) cardname r))
|
||||
(unsetq r)
|
||||
)
|
||||
|
||||
(defun snd_card_alias_unset ()
|
||||
(unsetq snd_card_aliases_array snd_card_alias)
|
||||
)
|
||||
|
|
@ -57,6 +57,7 @@ CMI8786 cards.CMI8788
|
|||
CMI8787 cards.CMI8788
|
||||
pistachio cards.pistachio-card
|
||||
VC4-HDMI cards.vc4-hdmi
|
||||
hda-acpi cards.HDA-Intel
|
||||
|
||||
<confdir:ctl/default.conf>
|
||||
<confdir:pcm/default.conf>
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
;
|
||||
; Toplevel configuration for the ALSA Ordinary Mixer Interface
|
||||
;
|
||||
; Copyright (c) 2003 Jaroslav Kysela <perex@perex.cz>
|
||||
; License: GPL v2 (http://www.gnu.org/licenses/gpl.html)
|
||||
;
|
||||
|
||||
(defun sndo_include (hctl stream)
|
||||
(setq info (Acall "ctl_card_info" (Acall "hctl_ctl" hctl)))
|
||||
(if (= (Aerror info) 0)
|
||||
(progn
|
||||
(setq info (Aresult info))
|
||||
(setq driver (cdr (assq "driver" (unsetq info))))
|
||||
(setq file (concat (path "data") "/alsa/cards/" (snd_card_alias driver) "/sndo" stream "-mixer.alisp"))
|
||||
(setq r (include file))
|
||||
(when (= r -2) (Asyserr "unable to find file " file))
|
||||
)
|
||||
(setq r (Aerror info))
|
||||
)
|
||||
(unsetq info driver file r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open_fcn (hctl stream pcm)
|
||||
(setq fcn (concat "sndo" stream "_mixer_open"))
|
||||
(setq r (if (exfun fcn) (funcall fcn hctl pcm) 0))
|
||||
(when (= r 0)
|
||||
(setq hctls (if hctls (cons hctls (cons hctl)) hctl))
|
||||
)
|
||||
(unsetq fcn r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open_hctl (name stream pcm)
|
||||
(setq hctl (Acall "hctl_open" name nil))
|
||||
(setq r (Aerror hctl))
|
||||
(when (= r 0)
|
||||
(setq hctl (Aresult hctl))
|
||||
(setq r (sndo_include hctl stream))
|
||||
(if (= r 0)
|
||||
(setq r (sndo_mixer_open_fcn hctl stream pcm))
|
||||
(Acall "hctl_close" hctl)
|
||||
)
|
||||
)
|
||||
(unsetq hctl r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open_virtual (name stream pcm)
|
||||
(setq file (concat (path "data") "/alsa/virtual/" name "/sndo" stream "-mixer.alisp"))
|
||||
(setq r (include file))
|
||||
(when (= r -2) (Asyserr "unable to find file " file))
|
||||
(when (= r 0) (setq r (sndo_mixer_open_fcn nil stream pcm)))
|
||||
(unsetq file r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open1 (name stream)
|
||||
(if (compare-strings name 0 2 "hw:" 0 2)
|
||||
(sndo_mixer_open_hctl name stream nil)
|
||||
(sndo_mixer_open_virtual name stream nil)
|
||||
)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open (pname cname)
|
||||
(setq r (sndo_mixer_open1 pname "p"))
|
||||
(when (= r 0) (setq r (sndo_mixer_open1 cname "c")))
|
||||
(when (!= r 0) (sndo_mixer_close))
|
||||
(unsetq sndo_mixer_open
|
||||
sndo_mixer_open_pcm sndo_mixer_open_pcm1
|
||||
sndo_mixer_open_virtual sndo_mixer_open_fcn
|
||||
sndo_include r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open_pcm1 (pcm stream)
|
||||
(setq info (Acall "pcm_info" pcm))
|
||||
(setq r (Aerror info))
|
||||
(when (= r 0)
|
||||
(setq info (Aresult info))
|
||||
(setq card (cdr (assq "card" info)))
|
||||
(setq r
|
||||
(if (< card 0)
|
||||
(sndo_mixer_open_virtual (Acall "pcm_name" pcm) stream pcm)
|
||||
(sndo_mixer_open_hctl (format "hw:%i" card) stream pcm)
|
||||
)
|
||||
)
|
||||
)
|
||||
(unsetq info card r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_open_pcm (ppcm cpcm)
|
||||
(setq r (sndo_mixer_open_pcm1 ppcm "p"))
|
||||
(when (= r 0) (setq r (sndo_mixer_open_pcm1 cpcm "c")))
|
||||
(when (!= r 0) (sndo_mixer_close))
|
||||
(unsetq sndo_mixer_open
|
||||
sndo_mixer_open_pcm sndo_mixer_open_pcm1
|
||||
sndo_mixer_open_virtual sndo_mixer_open_fcn
|
||||
sndo_include r)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_close1 (hctl stream)
|
||||
(when hctl
|
||||
(progn
|
||||
(setq fcn (concat "sndo" stream "_mixer_close"))
|
||||
(when (exfun fcn) (funcall fcn hctl))
|
||||
(unsetq fcn)
|
||||
(Acall "hctl_close" hctl)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun sndo_mixer_close nil
|
||||
(sndo_mixer_close1 (nth 1 hctls) "c")
|
||||
(sndo_mixer_close1 (nth 0 hctls) "p")
|
||||
(snd_card_alias_unset)
|
||||
(unsetq hctls)
|
||||
)
|
||||
|
||||
(include (concat (path "data") "/alsa/cards/aliases.alisp"))
|
||||
|
|
@ -1293,7 +1293,10 @@ int snd_ctl_ump_next_device(snd_ctl_t *ctl, int *device)
|
|||
int snd_ctl_ump_endpoint_info(snd_ctl_t *ctl, snd_ump_endpoint_info_t *info)
|
||||
{
|
||||
assert(ctl && info);
|
||||
return ctl->ops->ump_endpoint_info(ctl, info);
|
||||
fprintf(stderr, "%s:%d\n", __func__, __LINE__);
|
||||
if (ctl->ops->ump_endpoint_info)
|
||||
return ctl->ops->ump_endpoint_info(ctl, info);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1305,7 +1308,9 @@ int snd_ctl_ump_endpoint_info(snd_ctl_t *ctl, snd_ump_endpoint_info_t *info)
|
|||
int snd_ctl_ump_block_info(snd_ctl_t *ctl, snd_ump_block_info_t *info)
|
||||
{
|
||||
assert(ctl && info);
|
||||
return ctl->ops->ump_block_info(ctl, info);
|
||||
if (ctl->ops->ump_block_info)
|
||||
return ctl->ops->ump_block_info(ctl, info);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
* \file control/control_remap.c
|
||||
* \brief CTL Remap Plugin Interface
|
||||
* \author Jaroslav Kysela <perex@perex.cz>
|
||||
* \date 2021
|
||||
* \date 2021-2025
|
||||
*/
|
||||
/*
|
||||
* Control - Remap Controls
|
||||
* Copyright (c) 2021 by Jaroslav Kysela <perex@perex.cz>
|
||||
* Copyright (c) 2021-2025 by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
|
@ -76,28 +77,51 @@ typedef struct {
|
|||
snd_ctl_elem_id_t id_child;
|
||||
size_t channel_map_items;
|
||||
size_t channel_map_alloc;
|
||||
unsigned int src_channels;
|
||||
long *channel_map;
|
||||
} *controls;
|
||||
unsigned int event_mask;
|
||||
} snd_ctl_map_t;
|
||||
|
||||
typedef struct {
|
||||
snd_ctl_elem_id_t *id;
|
||||
unsigned int numid_app;
|
||||
unsigned int event_mask;
|
||||
} snd_ctl_map_event_t;
|
||||
|
||||
typedef struct {
|
||||
size_t control_items;
|
||||
snd_ctl_elem_id_t *control_ids;
|
||||
snd_ctl_elem_id_t switch_id;
|
||||
bool switch_state;
|
||||
} snd_ctl_sync_t;
|
||||
|
||||
typedef struct {
|
||||
snd_ctl_t *child;
|
||||
int numid_remap_active;
|
||||
unsigned int numid_app_last;
|
||||
|
||||
size_t numid_items;
|
||||
size_t numid_alloc;
|
||||
snd_ctl_numid_t *numid;
|
||||
snd_ctl_numid_t numid_temp;
|
||||
|
||||
size_t remap_items;
|
||||
size_t remap_alloc;
|
||||
snd_ctl_remap_id_t *remap;
|
||||
|
||||
size_t map_items;
|
||||
size_t map_alloc;
|
||||
snd_ctl_map_t *map;
|
||||
size_t map_read_queue_head;
|
||||
size_t map_read_queue_tail;
|
||||
snd_ctl_map_t **map_read_queue;
|
||||
|
||||
size_t sync_items;
|
||||
size_t sync_alloc;
|
||||
snd_ctl_sync_t *sync;
|
||||
size_t sync_switch_items;
|
||||
|
||||
size_t event_items;
|
||||
size_t event_queue_head;
|
||||
size_t event_queue_tail;
|
||||
snd_ctl_map_event_t *event_queue;
|
||||
} snd_ctl_remap_t;
|
||||
#endif
|
||||
|
||||
|
|
@ -172,6 +196,23 @@ static snd_ctl_numid_t *remap_find_numid_child(snd_ctl_remap_t *priv, unsigned i
|
|||
return remap_numid_child_new(priv, numid_child);
|
||||
}
|
||||
|
||||
static void remap_forget_numid_child(snd_ctl_remap_t *priv, unsigned int numid_child)
|
||||
{
|
||||
snd_ctl_numid_t *numid;
|
||||
size_t index;
|
||||
|
||||
if (!priv->numid_remap_active)
|
||||
return;
|
||||
numid = priv->numid;
|
||||
for (index = 0; index < priv->numid_items; index++) {
|
||||
if (numid[index].numid_child != numid_child)
|
||||
continue;
|
||||
memcpy(&priv->numid[index], &priv->numid[index + 1],
|
||||
(priv->numid_items - 1 - index) * sizeof(*numid));
|
||||
priv->numid_items++;
|
||||
}
|
||||
}
|
||||
|
||||
static snd_ctl_remap_id_t *remap_find_id_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
|
||||
{
|
||||
size_t count;
|
||||
|
|
@ -291,18 +332,102 @@ static int remap_id_to_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl
|
|||
return err;
|
||||
}
|
||||
|
||||
static snd_ctl_sync_t *remap_find_sync_numid(snd_ctl_remap_t *priv, unsigned int numid)
|
||||
{
|
||||
size_t count, index2;
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (numid == 0)
|
||||
return NULL;
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++)
|
||||
for (index2 = 0; index2 < sync->control_items; index2++)
|
||||
if (numid == sync->control_ids[index2].numid)
|
||||
return sync;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static snd_ctl_sync_t *remap_find_sync_id(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
|
||||
{
|
||||
size_t count, index2;
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (id->numid > 0)
|
||||
return remap_find_sync_numid(priv, id->numid);
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++)
|
||||
for (index2 = 0; index2 < sync->control_items; index2++)
|
||||
if (snd_ctl_elem_id_compare_set(id, &sync->control_ids[index2]) == 0)
|
||||
return sync;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void remap_update_sync_id(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
|
||||
{
|
||||
size_t count, index2;
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (id->numid == 0)
|
||||
return;
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++)
|
||||
for (index2 = 0; index2 < sync->control_items; index2++) {
|
||||
if (snd_ctl_elem_id_compare_set(id, &sync->control_ids[index2]) == 0) {
|
||||
sync->control_ids[index2].numid = id->numid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static snd_ctl_sync_t *remap_find_sync_switch_numid(snd_ctl_remap_t *priv, unsigned int numid)
|
||||
{
|
||||
size_t count;
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (numid == 0)
|
||||
return NULL;
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++)
|
||||
if (numid == sync->switch_id.numid)
|
||||
return sync;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static snd_ctl_sync_t *remap_find_sync_switch_id(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
|
||||
{
|
||||
size_t count;
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (id->numid > 0)
|
||||
return remap_find_sync_switch_numid(priv, id->numid);
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++) {
|
||||
if (sync->switch_id.numid == 0)
|
||||
continue;
|
||||
if (snd_ctl_elem_id_compare_set(id, &sync->switch_id) == 0)
|
||||
return sync;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void remap_free(snd_ctl_remap_t *priv)
|
||||
{
|
||||
size_t idx1, idx2;
|
||||
snd_ctl_sync_t *sync;
|
||||
snd_ctl_map_t *map;
|
||||
|
||||
for (idx1 = 0; idx1 < priv->sync_items; idx1++) {
|
||||
sync = &priv->sync[idx1];
|
||||
free(sync->control_ids);
|
||||
}
|
||||
for (idx1 = 0; idx1 < priv->map_items; idx1++) {
|
||||
map = &priv->map[idx1];
|
||||
for (idx2 = 0; idx2 < map->controls_items; idx2++)
|
||||
free(map->controls[idx2].channel_map);
|
||||
free(map->controls);
|
||||
}
|
||||
free(priv->map_read_queue);
|
||||
free(priv->event_queue);
|
||||
free(priv->sync);
|
||||
free(priv->map);
|
||||
free(priv->remap);
|
||||
free(priv->numid);
|
||||
|
|
@ -347,7 +472,6 @@ static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)
|
|||
snd_ctl_elem_id_t *id;
|
||||
snd_ctl_remap_id_t *rid;
|
||||
snd_ctl_numid_t *numid;
|
||||
snd_ctl_map_t *map;
|
||||
unsigned int index;
|
||||
size_t index2;
|
||||
int err;
|
||||
|
|
@ -367,18 +491,25 @@ static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)
|
|||
return -EIO;
|
||||
id->numid = numid->numid_app;
|
||||
}
|
||||
if (list->offset >= list->count + priv->map_items)
|
||||
if (list->offset >= list->count + priv->map_items + priv->sync_switch_items)
|
||||
return 0;
|
||||
index2 = 0;
|
||||
if (list->offset > list->count)
|
||||
index2 = list->offset - list->count;
|
||||
for ( ; index < list->space && index2 < priv->map_items; index2++, index++) {
|
||||
id = &list->pids[index];
|
||||
map = &priv->map[index2];
|
||||
*id = map->map_id;
|
||||
snd_ctl_map_t *map = &priv->map[index2];
|
||||
list->pids[index] = map->map_id;
|
||||
list->used++;
|
||||
}
|
||||
list->count += priv->map_items;
|
||||
if (index2 >= priv->map_items) {
|
||||
index2 -= priv->map_items;
|
||||
for ( ; index < list->space && index2 < priv->sync_switch_items; index2++, index++) {
|
||||
snd_ctl_sync_t *sync = &priv->sync[index2];
|
||||
list->pids[index] = sync->switch_id;
|
||||
list->used++;
|
||||
}
|
||||
}
|
||||
list->count += priv->map_items + priv->sync_switch_items;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -459,6 +590,21 @@ static int remap_map_elem_info(snd_ctl_remap_t *priv, snd_ctl_elem_info_t *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int remap_sync_elem_info(snd_ctl_remap_t *priv, snd_ctl_elem_info_t *info)
|
||||
{
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
sync = remap_find_sync_switch_id(priv, &info->id);
|
||||
if (!sync)
|
||||
return -EREMAPNOTFOUND;
|
||||
snd_ctl_elem_info_clear(info);
|
||||
info->id = sync->switch_id;
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
info->access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE;
|
||||
info->count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_remap_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
|
||||
{
|
||||
snd_ctl_remap_t *priv = ctl->private_data;
|
||||
|
|
@ -467,12 +613,17 @@ static int snd_ctl_remap_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
|
|||
|
||||
debug_id(&info->id, "%s\n", __func__);
|
||||
err = remap_map_elem_info(priv, info);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_sync_elem_info(priv, info);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_id_to_child(priv, &info->id, &rid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_elem_info(priv->child, info);
|
||||
if (err >= 0 && priv->sync_items > 0)
|
||||
remap_update_sync_id(priv, &info->id);
|
||||
return remap_id_to_app(priv, &info->id, rid, err);
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +632,7 @@ static int remap_map_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *cont
|
|||
snd_ctl_map_t *map;
|
||||
struct snd_ctl_map_ctl *mctl;
|
||||
snd_ctl_elem_value_t control2;
|
||||
size_t item, index;
|
||||
size_t item, index, src_index;
|
||||
int err;
|
||||
|
||||
map = remap_find_map_id(priv, &control->id);
|
||||
|
|
@ -501,19 +652,36 @@ static int remap_map_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *cont
|
|||
if (map->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
|
||||
map->type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long src = mctl->channel_map[index];
|
||||
long base_idx = mctl->src_channels * index;
|
||||
long src = mctl->channel_map[base_idx];
|
||||
if ((unsigned long)src < ARRAY_SIZE(control->value.integer.value))
|
||||
control->value.integer.value[index] = control2.value.integer.value[src];
|
||||
for (src_index = 1; src_index < mctl->src_channels; src_index++) {
|
||||
src = mctl->channel_map[base_idx + src_index];
|
||||
if ((unsigned long)src < ARRAY_SIZE(control->value.integer.value))
|
||||
if (control2.value.integer.value[src] < control->value.integer.value[index])
|
||||
control->value.integer.value[index] = control2.value.integer.value[src];
|
||||
}
|
||||
}
|
||||
} else if (map->type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long src = mctl->channel_map[index];
|
||||
long base_idx = mctl->src_channels * index;
|
||||
long src = mctl->channel_map[base_idx];
|
||||
if ((unsigned long)src < ARRAY_SIZE(control->value.integer64.value))
|
||||
control->value.integer64.value[index] = control2.value.integer64.value[src];
|
||||
for (src_index = 1; src_index < mctl->src_channels; src_index++) {
|
||||
src = mctl->channel_map[base_idx + src_index];
|
||||
if ((unsigned long)src < ARRAY_SIZE(control->value.integer64.value))
|
||||
if (control2.value.integer64.value[src] < control->value.integer64.value[index])
|
||||
control->value.integer64.value[index] = control2.value.integer64.value[src];
|
||||
}
|
||||
}
|
||||
} else if (map->type == SNDRV_CTL_ELEM_TYPE_BYTES) {
|
||||
/* does it make sense to merge bytes? */
|
||||
if (mctl->src_channels > 1)
|
||||
return -EINVAL;
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long src = mctl->channel_map[index];
|
||||
long src = mctl->channel_map[mctl->src_channels];
|
||||
if ((unsigned long)src < ARRAY_SIZE(control->value.bytes.data))
|
||||
control->value.bytes.data[index] = control2.value.bytes.data[src];
|
||||
}
|
||||
|
|
@ -522,6 +690,17 @@ static int remap_map_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *cont
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int remap_sync_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)
|
||||
{
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
sync = remap_find_sync_switch_id(priv, &control->id);
|
||||
if (!sync)
|
||||
return -EREMAPNOTFOUND;
|
||||
control->value.integer.value[0] = sync->switch_state ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_remap_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
|
||||
{
|
||||
snd_ctl_remap_t *priv = ctl->private_data;
|
||||
|
|
@ -530,6 +709,9 @@ static int snd_ctl_remap_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control
|
|||
|
||||
debug_id(&control->id, "%s\n", __func__);
|
||||
err = remap_map_elem_read(priv, control);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_sync_elem_read(priv, control);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_id_to_child(priv, &control->id, &rid);
|
||||
|
|
@ -544,7 +726,7 @@ static int remap_map_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *con
|
|||
snd_ctl_map_t *map;
|
||||
struct snd_ctl_map_ctl *mctl;
|
||||
snd_ctl_elem_value_t control2;
|
||||
size_t item, index;
|
||||
size_t item, index, src_index;
|
||||
int err, changes;
|
||||
|
||||
map = remap_find_map_id(priv, &control->id);
|
||||
|
|
@ -564,21 +746,40 @@ static int remap_map_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *con
|
|||
if (map->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
|
||||
map->type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long dst = mctl->channel_map[index];
|
||||
long base_idx = mctl->src_channels * index;
|
||||
long dst = mctl->channel_map[base_idx];
|
||||
if ((unsigned long)dst < ARRAY_SIZE(control->value.integer.value)) {
|
||||
changes |= control2.value.integer.value[dst] != control->value.integer.value[index];
|
||||
control2.value.integer.value[dst] = control->value.integer.value[index];
|
||||
}
|
||||
for (src_index = 1; src_index < mctl->src_channels; src_index++) {
|
||||
dst = mctl->channel_map[base_idx + src_index];
|
||||
if ((unsigned long)dst < ARRAY_SIZE(control->value.integer.value)) {
|
||||
changes |= control2.value.integer.value[dst] != control->value.integer.value[index];
|
||||
control2.value.integer.value[dst] = control->value.integer.value[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (map->type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long dst = mctl->channel_map[index];
|
||||
long base_idx = mctl->src_channels * index;
|
||||
long dst = mctl->channel_map[base_idx];
|
||||
if ((unsigned long)dst < ARRAY_SIZE(control->value.integer64.value)) {
|
||||
changes |= control2.value.integer64.value[dst] != control->value.integer64.value[index];
|
||||
control2.value.integer64.value[dst] = control->value.integer64.value[index];
|
||||
}
|
||||
for (src_index = 1; src_index < mctl->src_channels; src_index++) {
|
||||
dst = mctl->channel_map[base_idx + src_index];
|
||||
if ((unsigned long)dst < ARRAY_SIZE(control->value.integer.value)) {
|
||||
changes |= control2.value.integer64.value[dst] != control->value.integer64.value[index];
|
||||
control2.value.integer64.value[dst] = control->value.integer64.value[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (map->type == SNDRV_CTL_ELEM_TYPE_BYTES) {
|
||||
/* does it make sense to merge bytes? */
|
||||
if (mctl->src_channels > 1)
|
||||
return -EINVAL;
|
||||
for (index = 0; index < mctl->channel_map_items; index++) {
|
||||
long dst = mctl->channel_map[index];
|
||||
if ((unsigned long)dst < ARRAY_SIZE(control->value.bytes.data)) {
|
||||
|
|
@ -597,6 +798,37 @@ static int remap_map_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *con
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int remap_sync_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)
|
||||
{
|
||||
snd_ctl_sync_t *sync;
|
||||
snd_ctl_elem_value_t control2;
|
||||
size_t item;
|
||||
int err;
|
||||
|
||||
sync = remap_find_sync_switch_id(priv, &control->id);
|
||||
if (sync) {
|
||||
err = sync->switch_state != control->value.integer.value[0];
|
||||
sync->switch_state = control->value.integer.value[0] != 0;
|
||||
return err;
|
||||
}
|
||||
sync = remap_find_sync_id(priv, &control->id);
|
||||
if (sync == NULL)
|
||||
return -EREMAPNOTFOUND;
|
||||
if (sync->switch_state == false)
|
||||
return -EREMAPNOTFOUND;
|
||||
debug_id(&control->id, "%s\n", __func__);
|
||||
control2 = *control;
|
||||
for (item = 0; item < sync->control_items; item++) {
|
||||
control2.id = sync->control_ids[item];
|
||||
debug_id(&control2.id, "%s sync[%zd]\n", __func__, item);
|
||||
/* TODO: it's a blind write - no checks if the values are in range for all controls */
|
||||
err = snd_ctl_elem_write(priv->child, &control2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return remap_id_to_app(priv, &control->id, NULL, 0);
|
||||
}
|
||||
|
||||
static int snd_ctl_remap_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
|
||||
{
|
||||
snd_ctl_remap_t *priv = ctl->private_data;
|
||||
|
|
@ -605,6 +837,9 @@ static int snd_ctl_remap_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *contro
|
|||
|
||||
debug_id(&control->id, "%s\n", __func__);
|
||||
err = remap_map_elem_write(priv, control);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_sync_elem_write(priv, control);
|
||||
if (err != -EREMAPNOTFOUND)
|
||||
return err;
|
||||
err = remap_id_to_child(priv, &control->id, &rid);
|
||||
|
|
@ -794,19 +1029,45 @@ static void _next_ptr(size_t *ptr, size_t count)
|
|||
*ptr = (*ptr + 1) % count;
|
||||
}
|
||||
|
||||
static void event_add(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id,
|
||||
unsigned int numid_app, unsigned int event_mask)
|
||||
{
|
||||
snd_ctl_map_event_t *map_event;
|
||||
int found = 0;
|
||||
size_t head;
|
||||
|
||||
for (head = priv->event_queue_head;
|
||||
head != priv->event_queue_tail;
|
||||
_next_ptr(&head, priv->event_items))
|
||||
if (priv->event_queue[head].numid_app == numid_app) {
|
||||
found = 1;
|
||||
priv->event_queue[head].event_mask |= event_mask;
|
||||
break;
|
||||
}
|
||||
debug_id(id, "%s marking for read (already %d)\n", __func__, found);
|
||||
if (found)
|
||||
return;
|
||||
map_event = &priv->event_queue[priv->event_queue_tail];
|
||||
map_event->id = id;
|
||||
map_event->numid_app = numid_app;
|
||||
map_event->event_mask = event_mask;
|
||||
_next_ptr(&priv->event_queue_tail, priv->event_items);
|
||||
}
|
||||
|
||||
static void remap_event_for_all_map_controls(snd_ctl_remap_t *priv,
|
||||
snd_ctl_elem_id_t *id,
|
||||
unsigned int event_mask)
|
||||
{
|
||||
size_t count, index, head;
|
||||
size_t count, index;
|
||||
snd_ctl_map_t *map;
|
||||
struct snd_ctl_map_ctl *mctl;
|
||||
int found;
|
||||
int changed = 0;
|
||||
|
||||
if (event_mask == SNDRV_CTL_EVENT_MASK_REMOVE)
|
||||
event_mask = SNDRV_CTL_EVENT_MASK_INFO;
|
||||
map = priv->map;
|
||||
for (count = priv->map_items; count > 0; count--, map++) {
|
||||
changed = 0;
|
||||
for (index = 0; index < map->controls_items; index++) {
|
||||
mctl = &map->controls[index];
|
||||
if (mctl->id_child.numid == 0) {
|
||||
|
|
@ -817,20 +1078,51 @@ static void remap_event_for_all_map_controls(snd_ctl_remap_t *priv,
|
|||
if (id->numid != mctl->id_child.numid)
|
||||
continue;
|
||||
debug_id(&map->map_id, "%s found (all)\n", __func__);
|
||||
map->event_mask |= event_mask;
|
||||
found = 0;
|
||||
for (head = priv->map_read_queue_head;
|
||||
head != priv->map_read_queue_tail;
|
||||
_next_ptr(&head, priv->map_items))
|
||||
if (priv->map_read_queue[head] == map) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
changed = 1;
|
||||
}
|
||||
if (changed)
|
||||
event_add(priv, &map->map_id, map->map_id.numid, event_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void remap_event_for_all_sync_controls(snd_ctl_remap_t *priv,
|
||||
snd_ctl_elem_id_t *id,
|
||||
unsigned int event_mask)
|
||||
{
|
||||
size_t count, index;
|
||||
snd_ctl_sync_t *sync;
|
||||
snd_ctl_numid_t *numid;
|
||||
snd_ctl_elem_id_t *sid;
|
||||
int changed = 0;
|
||||
|
||||
if (event_mask == SNDRV_CTL_EVENT_MASK_REMOVE)
|
||||
return;
|
||||
sync = priv->sync;
|
||||
for (count = priv->sync_items; count > 0; count--, sync++) {
|
||||
changed = 0;
|
||||
for (index = 0; index < sync->control_items; index++) {
|
||||
sid = &sync->control_ids[index];
|
||||
if (sid->numid == 0) {
|
||||
if (snd_ctl_elem_id_compare_set(id, sid))
|
||||
continue;
|
||||
sid->numid = id->numid;
|
||||
}
|
||||
if (id->numid != sid->numid)
|
||||
continue;
|
||||
debug_id(&map->map_id, "%s marking for read\n", __func__);
|
||||
priv->map_read_queue[priv->map_read_queue_tail] = map;
|
||||
_next_ptr(&priv->map_read_queue_tail, priv->map_items);
|
||||
debug_id(sid, "%s found (all)\n", __func__);
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
if (!changed)
|
||||
continue;
|
||||
for (index = 0; index < sync->control_items; index++) {
|
||||
sid = &sync->control_ids[index];
|
||||
/* skip double updates */
|
||||
if (sid->numid == id->numid)
|
||||
continue;
|
||||
numid = remap_find_numid_child(priv, sid->numid);
|
||||
if (numid)
|
||||
event_add(priv, sid, numid->numid_app, event_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -840,18 +1132,19 @@ static int snd_ctl_remap_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
|
|||
snd_ctl_remap_t *priv = ctl->private_data;
|
||||
snd_ctl_remap_id_t *rid;
|
||||
snd_ctl_numid_t *numid;
|
||||
snd_ctl_map_t *map;
|
||||
snd_ctl_map_event_t *map_event;
|
||||
unsigned int numid_child;
|
||||
int err;
|
||||
|
||||
if (priv->map_read_queue_head != priv->map_read_queue_tail) {
|
||||
map = priv->map_read_queue[priv->map_read_queue_head];
|
||||
_next_ptr(&priv->map_read_queue_head, priv->map_items);
|
||||
if (priv->event_queue_head != priv->event_queue_tail) {
|
||||
map_event = &priv->event_queue[priv->event_queue_head];
|
||||
_next_ptr(&priv->event_queue_head, priv->event_items);
|
||||
memset(event, 0, sizeof(*event));
|
||||
event->type = SNDRV_CTL_EVENT_ELEM;
|
||||
event->data.elem.mask = map->event_mask;
|
||||
event->data.elem.id = map->map_id;
|
||||
map->event_mask = 0;
|
||||
debug_id(&map->map_id, "%s queue read\n", __func__);
|
||||
event->data.elem.mask = map_event->event_mask;
|
||||
event->data.elem.id = *map_event->id;
|
||||
event->data.elem.id.numid = map_event->numid_app;
|
||||
debug_id(&event->data.elem.id, "%s queue read\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
err = snd_ctl_read(priv->child, event);
|
||||
|
|
@ -861,11 +1154,13 @@ static int snd_ctl_remap_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
|
|||
(event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO |
|
||||
SNDRV_CTL_EVENT_MASK_ADD | SNDRV_CTL_EVENT_MASK_TLV)) != 0) {
|
||||
debug_id(&event->data.elem.id, "%s event mask 0x%x\n", __func__, event->data.elem.mask);
|
||||
numid_child = event->data.elem.id.numid;
|
||||
remap_event_for_all_map_controls(priv, &event->data.elem.id, event->data.elem.mask);
|
||||
remap_event_for_all_sync_controls(priv, &event->data.elem.id, event->data.elem.mask);
|
||||
rid = remap_find_id_child(priv, &event->data.elem.id);
|
||||
if (rid) {
|
||||
if (rid->id_child.numid == 0) {
|
||||
numid = remap_find_numid_child(priv, event->data.elem.id.numid);
|
||||
numid = remap_find_numid_child(priv, numid_child);
|
||||
if (numid == NULL)
|
||||
return -EIO;
|
||||
rid->id_child.numid = numid->numid_child;
|
||||
|
|
@ -873,11 +1168,13 @@ static int snd_ctl_remap_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
|
|||
}
|
||||
event->data.elem.id = rid->id_app;
|
||||
} else {
|
||||
numid = remap_find_numid_child(priv, event->data.elem.id.numid);
|
||||
numid = remap_find_numid_child(priv, numid_child);
|
||||
if (numid == NULL)
|
||||
return -EIO;
|
||||
event->data.elem.id.numid = numid->numid_app;
|
||||
}
|
||||
if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE)
|
||||
remap_forget_numid_child(priv, numid_child);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -914,6 +1211,7 @@ static int add_to_remap(snd_ctl_remap_t *priv,
|
|||
{
|
||||
snd_ctl_remap_id_t *rid;
|
||||
|
||||
|
||||
if (priv->remap_alloc == priv->remap_items) {
|
||||
rid = realloc(priv->remap, (priv->remap_alloc + 16) * sizeof(*rid));
|
||||
if (rid == NULL)
|
||||
|
|
@ -1017,43 +1315,79 @@ static int add_ctl_to_map(snd_ctl_map_t *map, struct snd_ctl_map_ctl **_mctl, sn
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_chn_to_map(struct snd_ctl_map_ctl *mctl, long idx, long val)
|
||||
static int add_chn_to_map(struct snd_ctl_map_ctl *mctl, long idx, long src_idx, long val)
|
||||
{
|
||||
size_t off;
|
||||
long *map;
|
||||
|
||||
if (src_idx >= mctl->src_channels) {
|
||||
SNDERR("Wrong channel mapping (extra source channel?)");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mctl->channel_map_alloc <= (size_t)idx) {
|
||||
map = realloc(mctl->channel_map, (idx + 4) * sizeof(*map));
|
||||
map = realloc(mctl->channel_map, mctl->src_channels * (idx + 4) * sizeof(*map));
|
||||
if (map == NULL)
|
||||
return -ENOMEM;
|
||||
mctl->channel_map = map;
|
||||
off = mctl->channel_map_alloc;
|
||||
mctl->channel_map_alloc = idx + 4;
|
||||
for ( ; off < mctl->channel_map_alloc; off++)
|
||||
for ( ; off < mctl->src_channels * mctl->channel_map_alloc; off++)
|
||||
map[off] = -1;
|
||||
}
|
||||
if ((size_t)idx >= mctl->channel_map_items)
|
||||
mctl->channel_map_items = idx + 1;
|
||||
mctl->channel_map[idx] = val;
|
||||
mctl->channel_map[mctl->src_channels * idx + src_idx] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_chn_to_map_array(struct snd_ctl_map_ctl *mctl, const char *dst_id, snd_config_t *conf)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
long src_idx = 0;
|
||||
int err;
|
||||
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
long idx = -1, chn = -1;
|
||||
if (safe_strtol(dst_id, &idx) || snd_config_get_integer(n, &chn)) {
|
||||
SNDERR("Wrong channel mapping (%ld -> %ld)", idx, chn);
|
||||
return -EINVAL;
|
||||
}
|
||||
err = add_chn_to_map(mctl, idx, src_idx, chn);
|
||||
if (err < 0)
|
||||
return err;
|
||||
src_idx++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_map_vindex(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n;
|
||||
int err;
|
||||
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
n = snd_config_iterator_entry(i);
|
||||
err = snd_config_is_array(n);
|
||||
if (err > 0 && (unsigned int)err > mctl->src_channels)
|
||||
mctl->src_channels = err; /* count of array items */
|
||||
}
|
||||
snd_config_for_each(i, next, conf) {
|
||||
n = snd_config_iterator_entry(i);
|
||||
long idx = -1, chn = -1;
|
||||
const char *id;
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
if (safe_strtol(id, &idx) || snd_config_get_integer(n, &chn)) {
|
||||
SNDERR("Wrong channel mapping (%ld -> %ld)", idx, chn);
|
||||
return -EINVAL;
|
||||
if (snd_config_is_array(n) > 0) {
|
||||
err = add_chn_to_map_array(mctl, id, n);
|
||||
} else {
|
||||
if (safe_strtol(id, &idx) || snd_config_get_integer(n, &chn)) {
|
||||
SNDERR("Wrong channel mapping (%ld -> %ld)", idx, chn);
|
||||
return -EINVAL;
|
||||
}
|
||||
err = add_chn_to_map(mctl, idx, 0, chn);
|
||||
}
|
||||
err = add_chn_to_map(mctl, idx, chn);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1066,6 +1400,7 @@ static int parse_map_config(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)
|
|||
snd_config_iterator_t i, next;
|
||||
int err;
|
||||
|
||||
mctl->src_channels = 1;
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
const char *id;
|
||||
|
|
@ -1140,12 +1475,141 @@ static int parse_map(snd_ctl_remap_t *priv, snd_config_t *conf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_ctl_sync_t *alloc_sync(snd_ctl_remap_t *priv)
|
||||
{
|
||||
snd_ctl_sync_t *sync;
|
||||
|
||||
if (priv->sync_alloc == priv->sync_items) {
|
||||
sync = realloc(priv->sync, (priv->sync_alloc + 16) * sizeof(*sync));
|
||||
if (sync == NULL)
|
||||
return NULL;
|
||||
memset(sync + priv->sync_alloc, 0, sizeof(*sync) * 16);
|
||||
priv->sync_alloc += 16;
|
||||
priv->sync = sync;
|
||||
}
|
||||
return &priv->sync[priv->sync_items++];
|
||||
}
|
||||
|
||||
static int parse_sync1(snd_ctl_remap_t *priv, unsigned int count, snd_config_t *conf)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_ctl_elem_id_t *eid;
|
||||
snd_ctl_sync_t *sync;
|
||||
const char *str;
|
||||
int err, index = 0;
|
||||
|
||||
sync = alloc_sync(priv);
|
||||
if (sync == NULL)
|
||||
return -ENOMEM;
|
||||
sync->switch_state = true;
|
||||
sync->control_ids = calloc(count, sizeof(sync->control_ids[0]));
|
||||
if (sync->control_ids == NULL)
|
||||
return -ENOMEM;
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
if (snd_config_get_string(n, &str) < 0) {
|
||||
SNDERR("strings are expected in sync array");
|
||||
return -EINVAL;
|
||||
}
|
||||
eid = &sync->control_ids[index];
|
||||
snd_ctl_elem_id_clear(eid);
|
||||
err = snd_ctl_ascii_elem_id_parse(eid, str);
|
||||
if (err < 0) {
|
||||
SNDERR("unable to parse control id '%s'!", str);
|
||||
return -EINVAL;
|
||||
}
|
||||
sync->control_items++;
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_sync_compound(snd_ctl_remap_t *priv, snd_config_t *conf)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_ctl_elem_id_t eid;
|
||||
snd_ctl_numid_t *numid;
|
||||
bool eid_found = false;
|
||||
bool controls_found = false;
|
||||
int count, err;
|
||||
|
||||
snd_ctl_elem_id_clear(&eid);
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
const char *id, *str;
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
if (strcmp(id, "switch") == 0) {
|
||||
if (snd_config_get_string(n, &str) < 0) {
|
||||
SNDERR("String is expected for switch");
|
||||
return -EINVAL;
|
||||
}
|
||||
err = snd_ctl_ascii_elem_id_parse(&eid, str);
|
||||
if (err < 0) {
|
||||
SNDERR("unable to parse id '%s'!", str);
|
||||
return -EINVAL;
|
||||
}
|
||||
eid_found = true;
|
||||
}
|
||||
if (strcmp(id, "controls") == 0) {
|
||||
count = snd_config_is_array(n);
|
||||
if (count <= 0) {
|
||||
SNDERR("Array is expected for sync!");
|
||||
return -EINVAL;
|
||||
}
|
||||
err = parse_sync1(priv, count, n);
|
||||
if (err < 0)
|
||||
return err;
|
||||
controls_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!controls_found || !eid_found)
|
||||
return 0;
|
||||
|
||||
numid = remap_numid_new(priv, 0, ++priv->numid_app_last);
|
||||
if (numid == NULL)
|
||||
return -ENOMEM;
|
||||
eid.numid = numid->numid_app;
|
||||
priv->sync[priv->sync_items - 1].switch_id = eid;
|
||||
priv->sync_switch_items++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_sync(snd_ctl_remap_t *priv, snd_config_t *conf)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
int count, err;
|
||||
|
||||
if (conf == NULL)
|
||||
return 0;
|
||||
snd_config_for_each(i, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(i);
|
||||
if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) {
|
||||
err = parse_sync_compound(priv, n);
|
||||
} else {
|
||||
count = snd_config_is_array(n);
|
||||
if (count <= 0) {
|
||||
SNDERR("Array is expected for sync!");
|
||||
return -EINVAL;
|
||||
}
|
||||
err = parse_sync1(priv, count, n);
|
||||
}
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a new remap & map control handle
|
||||
* \brief Creates a new remap/map/sync control handle
|
||||
* \param handlep Returns created control handle
|
||||
* \param name Name of control device
|
||||
* \param remap Remap configuration
|
||||
* \param map Map configuration
|
||||
* \param sync Sync configuration
|
||||
* \param child child configuration root
|
||||
* \param mode Control handle mode
|
||||
* \retval zero on success otherwise a negative error code
|
||||
|
|
@ -1154,14 +1618,15 @@ static int parse_map(snd_ctl_remap_t *priv, snd_config_t *conf)
|
|||
* changed in future.
|
||||
*/
|
||||
int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *remap,
|
||||
snd_config_t *map, snd_ctl_t *child, int mode)
|
||||
snd_config_t *map, snd_config_t *sync, snd_ctl_t *child, int mode)
|
||||
{
|
||||
snd_ctl_remap_t *priv;
|
||||
snd_ctl_t *ctl;
|
||||
size_t index;
|
||||
int result, err;
|
||||
|
||||
/* no-op, remove the plugin */
|
||||
if (!remap && !map)
|
||||
if (!remap && !map && !sync)
|
||||
goto _noop;
|
||||
|
||||
priv = calloc(1, sizeof(*priv));
|
||||
|
|
@ -1180,8 +1645,14 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema
|
|||
goto _err;
|
||||
}
|
||||
|
||||
err = parse_sync(priv, sync);
|
||||
if (err < 0) {
|
||||
result = err;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
/* no-op check, remove the plugin */
|
||||
if (priv->map_items == 0 && priv->remap_items == 0) {
|
||||
if (priv->map_items == 0 && priv->remap_items == 0 && priv->sync_items == 0) {
|
||||
remap_free(priv);
|
||||
_noop:
|
||||
free(child->name);
|
||||
|
|
@ -1192,13 +1663,16 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema
|
|||
return 0;
|
||||
}
|
||||
|
||||
priv->map_read_queue = calloc(priv->map_items, sizeof(priv->map_read_queue[0]));
|
||||
if (priv->map_read_queue == NULL) {
|
||||
priv->event_items = priv->map_items;
|
||||
for (index = 0; index < priv->sync_items; index++)
|
||||
priv->event_items += priv->sync[index].control_items;
|
||||
priv->event_queue = calloc(priv->event_items, sizeof(priv->event_queue[0]));
|
||||
if (priv->event_queue == NULL) {
|
||||
result = -ENOMEM;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
priv->numid_remap_active = priv->map_items > 0;
|
||||
priv->numid_remap_active = priv->map_items > 0 || priv->sync_items;
|
||||
|
||||
priv->child = child;
|
||||
err = snd_ctl_new(&ctl, SND_CTL_TYPE_REMAP, name, mode);
|
||||
|
|
@ -1228,10 +1702,10 @@ child controls to one or split one control to more.
|
|||
|
||||
\code
|
||||
ctl.name {
|
||||
type remap # Route & Volume conversion PCM
|
||||
child STR # Slave name
|
||||
type remap # Remap controls
|
||||
child STR # Child name
|
||||
# or
|
||||
child { # Slave definition
|
||||
child { # Child definition
|
||||
type STR
|
||||
...
|
||||
}
|
||||
|
|
@ -1264,6 +1738,27 @@ ctl.name {
|
|||
vindex.0 1 # stereo to mono (second channel)
|
||||
}
|
||||
}
|
||||
# join two stereo to one stereo (minimum value is returned for read operation)
|
||||
CREATE_ID4_STR {
|
||||
SRC_ID5_STR.vindex.0 [ 0 1 ] # source channels 0+1 to merged channel 0
|
||||
SRC_ID6_STR.vindex.1 [ 0 1 ] # source channels 0+1 to merged channel 1
|
||||
}
|
||||
}
|
||||
sync {
|
||||
# synchronize multiple controls without any translations
|
||||
sample_group_1 [
|
||||
SYNC_ID1_STR
|
||||
SYNC_ID2_STR
|
||||
]
|
||||
# synchronize multiple controls without any translations
|
||||
# add functionality on/off switch
|
||||
sample_group_2 {
|
||||
switch SYNC_SWITCH_ID
|
||||
controls [
|
||||
SYNC_ID3_STR
|
||||
SYNC_ID4_STR
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
|
|
@ -1282,7 +1777,7 @@ ctl.name {
|
|||
* \param handlep Returns created control handle
|
||||
* \param name Name of control
|
||||
* \param root Root configuration node
|
||||
* \param conf Configuration node with Route & Volume PCM description
|
||||
* \param conf Configuration node with control remap description
|
||||
* \param mode Control handle mode
|
||||
* \retval zero on success otherwise a negative error code
|
||||
* \warning Using of this function might be dangerous in the sense
|
||||
|
|
@ -1295,6 +1790,7 @@ int _snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd
|
|||
snd_config_t *child = NULL;
|
||||
snd_config_t *remap = NULL;
|
||||
snd_config_t *map = NULL;
|
||||
snd_config_t *sync = NULL;
|
||||
snd_ctl_t *cctl;
|
||||
int err;
|
||||
|
||||
|
|
@ -1313,6 +1809,10 @@ int _snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd
|
|||
map = n;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(id, "sync") == 0) {
|
||||
sync = n;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(id, "child") == 0) {
|
||||
child = n;
|
||||
continue;
|
||||
|
|
@ -1327,7 +1827,7 @@ int _snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd
|
|||
err = _snd_ctl_open_child(&cctl, root, child, mode, conf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_remap_open(handlep, name, remap, map, cctl, mode);
|
||||
err = snd_ctl_remap_open(handlep, name, remap, map, sync, cctl, mode);
|
||||
if (err < 0)
|
||||
snd_ctl_close(cctl);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int))
|
||||
/* max size of a TLV entry for dB information (including compound one) */
|
||||
#define MAX_TLV_RANGE_SIZE 256
|
||||
/* min length of a TLV stream to contain type and size */
|
||||
#define MIN_TLV_STREAM_LEN ((SNDRV_CTL_TLVO_LEN + 1) * sizeof(int))
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -47,12 +49,12 @@
|
|||
* \param tlv the TLV source
|
||||
* \param tlv_size the byte size of TLV source
|
||||
* \param db_tlvp the pointer stored the dB TLV information
|
||||
* \return the byte size of dB TLV information if found in the given
|
||||
* TLV source, or a negative error code.
|
||||
* \return The byte size of dB TLV information if found in the given TLV
|
||||
* source, -ENOENT if not found, or a negative error code in case of an error.
|
||||
*
|
||||
* This function parses the given TLV source and stores the TLV start
|
||||
* point if the TLV information regarding dB conversion is found.
|
||||
* The stored TLV pointer can be passed to the convesion functions
|
||||
* The stored TLV pointer can be passed to the conversion functions
|
||||
* #snd_tlv_convert_to_dB(), #snd_tlv_convert_from_dB() and
|
||||
* #snd_tlv_get_dB_range().
|
||||
*/
|
||||
|
|
@ -64,6 +66,13 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
|
|||
unsigned int size;
|
||||
int err;
|
||||
|
||||
/* Validate that it is possible to read the type and size
|
||||
* without reading past the end of the buffer. */
|
||||
if (tlv_size < MIN_TLV_STREAM_LEN) {
|
||||
SNDERR("TLV stream too short");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*db_tlvp = NULL;
|
||||
type = tlv[SNDRV_CTL_TLVO_TYPE];
|
||||
size = tlv[SNDRV_CTL_TLVO_LEN];
|
||||
|
|
@ -79,7 +88,7 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
|
|||
while (size > 0) {
|
||||
unsigned int len;
|
||||
err = snd_tlv_parse_dB_info(tlv, size, db_tlvp);
|
||||
if (err < 0)
|
||||
if (err < 0 && err != -ENOENT)
|
||||
return err; /* error */
|
||||
if (err > 0)
|
||||
return err; /* found */
|
||||
|
|
@ -114,7 +123,7 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return -EINVAL; /* not found */
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
41
src/error.c
41
src/error.c
|
|
@ -191,11 +191,38 @@ snd_lib_error_handler_t snd_err_msg = snd_err_msg_default;
|
|||
*/
|
||||
size_t snd_strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t ret = strlen(src);
|
||||
if (size) {
|
||||
size_t len = ret >= size ? size - 1 : ret;
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
size_t ret = strlen(src);
|
||||
if (size) {
|
||||
size_t len = ret >= size ? size - 1 : ret;
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Append a C-string into a sized buffer
|
||||
* \param dst Where to append the string to
|
||||
* \param src Where to copy the string from
|
||||
* \param size Size of destination buffer
|
||||
* \retval The total string length (no trimming)
|
||||
*
|
||||
* The result is always a valid NUL-terminated string that fits
|
||||
* in the buffer (unless, of course, the buffer size is zero).
|
||||
* It does not pad out the result.
|
||||
*/
|
||||
size_t snd_strlcat(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t dst_len = strlen(dst);
|
||||
size_t len = strlen(src);
|
||||
size_t ret = dst_len + len;
|
||||
if (dst_len < size) {
|
||||
dst += dst_len;
|
||||
size -= dst_len;
|
||||
if (len >= size)
|
||||
len = size - 1;
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ int bag_del(bag_t *bag, void *ptr)
|
|||
|
||||
void bag_del_all(bag_t *bag)
|
||||
{
|
||||
while (!list_empty(bag))
|
||||
list_del(bag->next);
|
||||
struct list_head *pos, *npos;
|
||||
|
||||
list_for_each_safe(pos, npos, bag) {
|
||||
bag1_t *b = list_entry(pos, bag1_t, list);
|
||||
list_del(&b->list);
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,8 +494,8 @@ software parameter.
|
|||
There are two functions allowing link multiple streams together. In the
|
||||
case, the linking means that all operations are synchronized. Because the
|
||||
drivers cannot guarantee the synchronization (sample resolution) on hardware
|
||||
lacking this feature, the #snd_pcm_info_get_sync() function
|
||||
returns synchronization ID - #snd_pcm_sync_id_t, which is equal
|
||||
lacking this feature, the #snd_pcm_hw_params_get_sync() function
|
||||
returns 16-byte synchronization ID, which is equal
|
||||
for hardware synchronized streams. When the #snd_pcm_link()
|
||||
function is called, all operations managing the stream state for these two
|
||||
streams are joined. The opposite function is #snd_pcm_unlink().
|
||||
|
|
@ -777,6 +777,10 @@ int snd_pcm_close(snd_pcm_t *pcm)
|
|||
{
|
||||
int res = 0, err;
|
||||
assert(pcm);
|
||||
while (!list_empty(&pcm->async_handlers)) {
|
||||
snd_async_handler_t *h = list_entry(pcm->async_handlers.next, snd_async_handler_t, hlist);
|
||||
snd_async_del_handler(h);
|
||||
}
|
||||
if (pcm->setup && !pcm->donot_close) {
|
||||
snd_pcm_drop(pcm);
|
||||
err = snd_pcm_hw_free(pcm);
|
||||
|
|
@ -785,10 +789,6 @@ int snd_pcm_close(snd_pcm_t *pcm)
|
|||
}
|
||||
if (pcm->mmap_channels)
|
||||
snd_pcm_munmap(pcm);
|
||||
while (!list_empty(&pcm->async_handlers)) {
|
||||
snd_async_handler_t *h = list_entry(pcm->async_handlers.next, snd_async_handler_t, hlist);
|
||||
snd_async_del_handler(h);
|
||||
}
|
||||
if (pcm->ops->close)
|
||||
err = pcm->ops->close(pcm->op_arg);
|
||||
else
|
||||
|
|
@ -3098,7 +3098,7 @@ snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm)
|
|||
* \param delayp Total I/O latency in frames
|
||||
* \return zero on success otherwise a negative error code
|
||||
*
|
||||
* The avail and delay values retuned are in sync.
|
||||
* The avail and delay values returned are in sync.
|
||||
*
|
||||
* The function is thread-safe when built with the proper option.
|
||||
*/
|
||||
|
|
@ -3107,7 +3107,7 @@ int snd_pcm_avail_delay(snd_pcm_t *pcm,
|
|||
snd_pcm_sframes_t *delayp)
|
||||
{
|
||||
snd_pcm_sframes_t sf;
|
||||
int err;
|
||||
int err, ok = 0;
|
||||
|
||||
assert(pcm && availp && delayp);
|
||||
if (CHECK_SANITY(! pcm->setup)) {
|
||||
|
|
@ -3118,15 +3118,25 @@ int snd_pcm_avail_delay(snd_pcm_t *pcm,
|
|||
err = __snd_pcm_hwsync(pcm);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
sf = __snd_pcm_avail_update(pcm);
|
||||
if (sf < 0) {
|
||||
err = (int)sf;
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* Delay value is relative to avail, so we have to
|
||||
* loop to avoid reporting stale delay data.
|
||||
*/
|
||||
while (1) {
|
||||
sf = __snd_pcm_avail_update(pcm);
|
||||
if (sf < 0) {
|
||||
err = (int)sf;
|
||||
goto unlock;
|
||||
}
|
||||
if (ok && sf == *availp)
|
||||
break;
|
||||
*availp = sf;
|
||||
err = __snd_pcm_delay(pcm, delayp);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
ok = 1;
|
||||
}
|
||||
err = __snd_pcm_delay(pcm, delayp);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
*availp = sf;
|
||||
err = 0;
|
||||
unlock:
|
||||
snd_pcm_unlock(pcm->fast_op_arg);
|
||||
|
|
@ -3948,6 +3958,25 @@ int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params)
|
|||
return params->fifo_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get hardware synchronization ID from a PCM info container
|
||||
* \param params Configuration space
|
||||
* \return 16-byte synchronization ID (use #SND_PCM_HW_PARAMS_SYNC_SIZE)
|
||||
*
|
||||
* This synchronization ID determines the similar clocks for the
|
||||
* PCM stream between multiple devices (including different cards).
|
||||
* "All zeros" means "not set". The contents of the ID can be used
|
||||
* only for a comparison with the contents of another ID returned
|
||||
* from this function. Applications should not do a comparison with
|
||||
* hard-coded values, because the implementation generating such
|
||||
* synchronization IDs may be changed in future.
|
||||
*/
|
||||
const unsigned char *snd_pcm_hw_params_get_sync(const snd_pcm_hw_params_t *params)
|
||||
{
|
||||
assert(params);
|
||||
return params->sync;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Fill params with a full configuration space for a PCM
|
||||
* \param pcm PCM handle
|
||||
|
|
@ -7332,7 +7361,7 @@ unsigned int snd_pcm_info_get_subdevices_avail(const snd_pcm_info_t *obj)
|
|||
}
|
||||
|
||||
/**
|
||||
* \brief Get hardware synchronization ID from a PCM info container
|
||||
* \brief (DEPRECATED) Get hardware synchronization ID from a PCM info container
|
||||
* \param obj PCM info container
|
||||
* \return hardware synchronization ID
|
||||
*/
|
||||
|
|
@ -7340,9 +7369,12 @@ snd_pcm_sync_id_t snd_pcm_info_get_sync(const snd_pcm_info_t *obj)
|
|||
{
|
||||
snd_pcm_sync_id_t res;
|
||||
assert(obj);
|
||||
memcpy(&res, &obj->sync, sizeof(res));
|
||||
bzero(&res, sizeof(res));
|
||||
return res;
|
||||
}
|
||||
#ifndef DOC_HIDDEN
|
||||
link_warning(snd_pcm_info_get_sync, "Warning: snd_pcm_info_get_sync is deprecated, consider to use snd_pcm_hw_params_get_sync");
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Set wanted device inside a PCM info container (see #snd_ctl_pcm_info)
|
||||
|
|
@ -8731,7 +8763,7 @@ _snd_pcm_parse_config_chmaps(snd_config_t *conf)
|
|||
* -EPIPE (overrun or underrun) and -ESTRPIPE (stream is suspended)
|
||||
* error codes trying to prepare given stream for next I/O.
|
||||
*
|
||||
* Note that this function returs the original error code when it is not
|
||||
* Note that this function returns the original error code when it is not
|
||||
* handled inside this function (for example -EAGAIN is returned back).
|
||||
*/
|
||||
int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
|
||||
|
|
|
|||
|
|
@ -1018,6 +1018,7 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
|||
}
|
||||
dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max / dshare->slave_period_size;
|
||||
params->info = dshare->shmptr->s.info;
|
||||
params->info &= ~(SND_PCM_INFO_RESUME | SND_PCM_INFO_PAUSE);
|
||||
#ifdef REFINE_DEBUG
|
||||
snd_output_puts(log, "DMIX REFINE (end):\n");
|
||||
snd_pcm_hw_params_dump(params, log);
|
||||
|
|
@ -1031,6 +1032,7 @@ int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
|||
snd_pcm_direct_t *dmix = pcm->private_data;
|
||||
|
||||
params->info = dmix->shmptr->s.info;
|
||||
params->info &= ~(SND_PCM_INFO_RESUME | SND_PCM_INFO_PAUSE);
|
||||
params->rate_num = dmix->shmptr->s.rate;
|
||||
params->rate_den = 1;
|
||||
params->fifo_size = 0;
|
||||
|
|
@ -1154,8 +1156,6 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
|
|||
/* copy the slave setting */
|
||||
static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
|
||||
{
|
||||
spcm->info &= ~SND_PCM_INFO_PAUSE;
|
||||
|
||||
COPY_SLAVE(access);
|
||||
COPY_SLAVE(format);
|
||||
COPY_SLAVE(subformat);
|
||||
|
|
@ -1183,8 +1183,6 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
|
|||
COPY_SLAVE(buffer_time);
|
||||
COPY_SLAVE(sample_bits);
|
||||
COPY_SLAVE(frame_bits);
|
||||
|
||||
dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME;
|
||||
}
|
||||
|
||||
#undef COPY_SLAVE
|
||||
|
|
|
|||
|
|
@ -1669,17 +1669,19 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd,
|
|||
if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) {
|
||||
struct timespec timespec;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) {
|
||||
int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
|
||||
ret = -errno;
|
||||
SNDMSG("TTSTAMP failed");
|
||||
return ret;
|
||||
if (!(mode & SND_PCM_APPEND)) {
|
||||
int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
|
||||
ret = -errno;
|
||||
SNDMSG("TTSTAMP failed");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) {
|
||||
if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver && !(mode & SND_PCM_APPEND)) {
|
||||
int on = 1;
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
|
||||
ret = -errno;
|
||||
|
|
|
|||
|
|
@ -639,6 +639,22 @@ unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *inf
|
|||
return info->subdevices_avail;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get the tied device number for the given rawmidi device
|
||||
* \param info pointer to a snd_rawmidi_info_t structure
|
||||
* \return the device number for the tied device, or -1 if untied / unknown.
|
||||
*
|
||||
* This function is useful for UMP rawmidi devices where each of them may
|
||||
* have the mirroring legacy rawmidi device. Those are shown as "tied".
|
||||
*/
|
||||
int snd_rawmidi_info_get_tied_device(const snd_rawmidi_info_t *info)
|
||||
{
|
||||
assert(info);
|
||||
if (info->tied_device > 0)
|
||||
return info->tied_device - 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set rawmidi device number
|
||||
* \param info pointer to a snd_rawmidi_info_t structure
|
||||
|
|
|
|||
|
|
@ -7,6 +7,29 @@
|
|||
#include "rawmidi_local.h"
|
||||
#include "ump_local.h"
|
||||
|
||||
/*! \page rawmidi RawMidi interface
|
||||
|
||||
\section rawmidi_ump UMP RawMidi Interface
|
||||
|
||||
MIDI 2.0 devices have a different type of interface, communicating with
|
||||
UMP (Universal MIDI Packet). For those devices, ALSA-library provides
|
||||
API functions for accessing the raw UMP packet directly via the existing
|
||||
RawMidi interface.
|
||||
|
||||
#snd_ump_open() is the API function for opening a UMP RawMidi interface.
|
||||
It works just like #snd_rawmidi_open() but for UMP devices. Similarly,
|
||||
#snd_ump_close() is for closing, and there are other equivalent API functions
|
||||
corresponding to the RawMidi ones.
|
||||
|
||||
The new stuff for UMP is UMP Endpoint and UMP Function Blocks. The information
|
||||
from Endpoint and Function Blocks can be obtained via #snd_ump_endpoint_info()
|
||||
and #snd_ump_block_info() API functions.
|
||||
|
||||
The objects #snd_ump_endpoint_info_t and #snd_ump_block_info_t are used for
|
||||
creating a virtual UMP Endpoint and Function Blocks via ALSA sequencer, too.
|
||||
|
||||
*/
|
||||
|
||||
static int get_rawmidi_flags(snd_ump_t *ump)
|
||||
{
|
||||
snd_rawmidi_info_t info;
|
||||
|
|
@ -337,6 +360,17 @@ void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)
|
|||
free(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clears the snd_ump_endpoint_info_t structure
|
||||
* \param info pointer to the snd_ump_endpoint_info_t structure to clear
|
||||
*
|
||||
* Zero-clear the snd_ump_endpoint_info_t object.
|
||||
*/
|
||||
void snd_ump_endpoint_info_clear(snd_ump_endpoint_info_t *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief copy one snd_ump_endpoint_info_t structure to another
|
||||
* \param dst destination snd_ump_endpoint_info_t structure
|
||||
|
|
@ -478,6 +512,149 @@ const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *
|
|||
return (const char *)info->product_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set card number of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param card the card number of the given UMP endpoint
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_card(snd_ump_endpoint_info_t *info,
|
||||
unsigned int card)
|
||||
{
|
||||
info->card = card;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set device number of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param device the device number of the given UMP endpoint
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_device(snd_ump_endpoint_info_t *info,
|
||||
unsigned int device)
|
||||
{
|
||||
info->device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set info flags of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param flags UMP endpoint flag bits
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_flags(snd_ump_endpoint_info_t *info,
|
||||
unsigned int flags)
|
||||
{
|
||||
info->flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set protocol capability bits of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param caps UMP endpoint protocol capability bits
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_protocol_caps(snd_ump_endpoint_info_t *info,
|
||||
unsigned int caps)
|
||||
{
|
||||
info->protocol_caps = caps;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the current protocol of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param protocol the UMP endpoint protocol bits
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_protocol(snd_ump_endpoint_info_t *info,
|
||||
unsigned int protocol)
|
||||
{
|
||||
info->protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the number of UMP blocks of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param blocks the number of UMP blocks
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_num_blocks(snd_ump_endpoint_info_t *info,
|
||||
unsigned int blocks)
|
||||
{
|
||||
info->num_blocks = blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the UMP version number of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param version the UMP version number
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_version(snd_ump_endpoint_info_t *info,
|
||||
unsigned int version)
|
||||
{
|
||||
info->version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the UMP manufacturer ID of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param id UMP manufacturer ID
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_manufacturer_id(snd_ump_endpoint_info_t *info,
|
||||
unsigned int id)
|
||||
{
|
||||
info->manufacturer_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the UMP family ID of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param id UMP family ID
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_family_id(snd_ump_endpoint_info_t *info,
|
||||
unsigned int id)
|
||||
{
|
||||
info->family_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the UMP model ID of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param id UMP model ID
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_model_id(snd_ump_endpoint_info_t *info,
|
||||
unsigned int id)
|
||||
{
|
||||
info->model_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the UMP software revision of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param id UMP software revision in 4 bytes array
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_sw_revision(snd_ump_endpoint_info_t *info,
|
||||
const unsigned char *id)
|
||||
{
|
||||
memcpy(info->sw_revision, id, sizeof(info->sw_revision));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the name of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param name UMP endpoint name string
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_name(snd_ump_endpoint_info_t *info,
|
||||
const char *name)
|
||||
{
|
||||
snd_strlcpy((char *)info->name, name, sizeof(info->name));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the product ID string of UMP endpoint
|
||||
* \param info pointer to a snd_ump_endpoint_info_t structure
|
||||
* \param id UMP endpoint product ID string
|
||||
*/
|
||||
void snd_ump_endpoint_info_set_product_id(snd_ump_endpoint_info_t *info,
|
||||
const char *id)
|
||||
{
|
||||
snd_strlcpy((char *)info->product_id, id, sizeof(info->product_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get endpoint information about UMP handle
|
||||
* \param ump UMP handle
|
||||
|
|
@ -526,6 +703,17 @@ void snd_ump_block_info_free(snd_ump_block_info_t *info)
|
|||
free(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clears the snd_ump_block_info_t structure
|
||||
* \param info pointer to the snd_ump_block_info_t structure to clear
|
||||
*
|
||||
* Zero-clear the snd_ump_block_info_t object.
|
||||
*/
|
||||
void snd_ump_block_info_clear(snd_ump_block_info_t *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief copy one snd_ump_block_info_t structure to another
|
||||
* \param dst destination snd_ump_block_info_t structure
|
||||
|
|
@ -567,17 +755,6 @@ unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)
|
|||
return info->block_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set UMP block ID for query
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param id the ID number for query
|
||||
*/
|
||||
void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
|
||||
unsigned int id)
|
||||
{
|
||||
info->block_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get UMP block activeness
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
|
|
@ -668,6 +845,152 @@ const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info)
|
|||
return (const char *)info->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set card number to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param card the card number
|
||||
*/
|
||||
void snd_ump_block_info_set_card(snd_ump_block_info_t *info, unsigned int card)
|
||||
{
|
||||
info->card = card;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set device number to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param device the device number
|
||||
*/
|
||||
void snd_ump_block_info_set_device(snd_ump_block_info_t *info, unsigned int device)
|
||||
{
|
||||
info->device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set UMP block ID to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param id the ID number
|
||||
*
|
||||
* This function is mostly used for setting the block ID to query.
|
||||
*/
|
||||
#ifndef DOXYGEN
|
||||
EXPORT_SYMBOL void INTERNAL(snd_ump_block_info_set_block_id)(snd_ump_block_info_t *info,
|
||||
unsigned int id)
|
||||
#else
|
||||
void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
|
||||
unsigned int id)
|
||||
#endif
|
||||
{
|
||||
info->block_id = id;
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
EXPORT_SYMBOL void INTERNAL(snd_ump_block_info_set_block_id_old)
|
||||
(snd_ump_block_info_t *info, unsigned int id)
|
||||
{
|
||||
return INTERNAL(snd_ump_block_info_set_block_id)(info, id);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DOC_HIDDEN
|
||||
use_symbol_version(__snd_ump_block_info_set_block_id_old, snd_ump_block_info_set_block_id, ALSA_1.2.10);
|
||||
use_default_symbol_version(__snd_ump_block_info_set_block_id, snd_ump_block_info_set_block_id, ALSA_1.2.13);
|
||||
#endif /* DOC_HIDDEN */
|
||||
|
||||
/**
|
||||
* \brief set activeness to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param active 1 if the block is active or 0 if inactive
|
||||
*/
|
||||
void snd_ump_block_info_set_active(snd_ump_block_info_t *info, unsigned int active)
|
||||
{
|
||||
info->active = !!active;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set UMP block information flags to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param flags flag bits for the given UMP block
|
||||
*/
|
||||
void snd_ump_block_info_set_flags(snd_ump_block_info_t *info, unsigned int flags)
|
||||
{
|
||||
info->flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set UMP block direction to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param direction direction of UMP block (input,output,bidirectional)
|
||||
*/
|
||||
void snd_ump_block_info_set_direction(snd_ump_block_info_t *info, unsigned int direction)
|
||||
{
|
||||
info->direction = direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set first UMP group to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param first_group the first UMP group ID belonging to the block
|
||||
*/
|
||||
void snd_ump_block_info_set_first_group(snd_ump_block_info_t *info,
|
||||
unsigned int first_group)
|
||||
{
|
||||
info->first_group = first_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set number of UMP groups to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param num_groups the number of UMP groups belonging to the block
|
||||
*/
|
||||
void snd_ump_block_info_set_num_groups(snd_ump_block_info_t *info,
|
||||
unsigned int num_groups)
|
||||
{
|
||||
info->num_groups = num_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set MIDI-CI version number to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param version MIDI-CI version number
|
||||
*/
|
||||
void snd_ump_block_info_set_midi_ci_version(snd_ump_block_info_t *info,
|
||||
unsigned int version)
|
||||
{
|
||||
info->midi_ci_version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set number of supported SysEx8 streams to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param streams number of supported SysEx8 streams
|
||||
*/
|
||||
void snd_ump_block_info_set_sysex8_streams(snd_ump_block_info_t *info,
|
||||
unsigned int streams)
|
||||
{
|
||||
info->sysex8_streams = streams;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set UI Hint to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param hint the hint bits
|
||||
*/
|
||||
void snd_ump_block_info_set_ui_hint(snd_ump_block_info_t *info, unsigned int hint)
|
||||
{
|
||||
info->ui_hint = hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set the name string to snd_ump_block_info_t structure
|
||||
* \param info pointer to a snd_ump_block_info_t structure
|
||||
* \param name the name string of UMP block
|
||||
*/
|
||||
void snd_ump_block_info_set_name(snd_ump_block_info_t *info,
|
||||
const char *name)
|
||||
{
|
||||
snd_strlcpy((char *)info->name, name, sizeof(info->name));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get UMP block information
|
||||
* \param ump UMP handle
|
||||
|
|
@ -767,3 +1090,20 @@ int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen,
|
|||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief return the length of a UMP packet type
|
||||
* \param type UMP packet type
|
||||
* \return the length of the given UMP packet type in 32bit words (from 1 to 4),
|
||||
* or 0 for negative inputs.
|
||||
*/
|
||||
int snd_ump_packet_length(unsigned int type)
|
||||
{
|
||||
static int packet_length[16] = {
|
||||
1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
|
||||
};
|
||||
|
||||
if (type > 16)
|
||||
return 0;
|
||||
return packet_length[type];
|
||||
}
|
||||
|
|
|
|||
158
src/seq/seq.c
158
src/seq/seq.c
|
|
@ -490,6 +490,21 @@ the buffer is flushed by #snd_seq_drain_output() call.
|
|||
You can schedule the event in a certain queue so that the tempo
|
||||
change happens at the scheduled time, too.
|
||||
|
||||
The tempo is set as default in microsecond unit as defined for
|
||||
Standard MIDI Format 1. But since the value in MIDI2 Set Tempo message
|
||||
is based on 10-nanosecand unit, sequencer queue also allows to set up
|
||||
in 10-nanosecond unit. For that, change the tempo-base value in
|
||||
#snd_seq_queue_tempo_t to 10 via #snd_seq_queue_tempo_set_tempo_base()
|
||||
along with the 10-nanobased tempo value. The default tempo base is 1000,
|
||||
i.e. 1 microsecond.
|
||||
Currently the API supports only either 0, 10 or 1000 as the tempo-base
|
||||
(where 0 is treated as 1000).
|
||||
|
||||
The older kernel might not support the different tempo-base, and setting a
|
||||
different value from 1000 would fail. The application may heck the
|
||||
availability of tempo-base change via #snd_seq_has_queue_tempo_base() function
|
||||
beforehand, and re-calculate in microsecond unit as fallback.
|
||||
|
||||
\subsection seq_ev_start Starting and stopping a queue
|
||||
|
||||
To start, stop, or continue a queue, you need to send a queue-control
|
||||
|
|
@ -775,6 +790,67 @@ void event_filter(snd_seq_t *seq, snd_seq_event_t *ev)
|
|||
}
|
||||
\endcode
|
||||
|
||||
\section seq_midi2 MIDI 2.0 and UMP
|
||||
|
||||
\subsection seq_midi2_extension Extension for UMP
|
||||
|
||||
The recent extension of ALSA sequencer is the support for MIDI 2.0 and
|
||||
UMP (Universal MIDI Packet) handling.
|
||||
|
||||
A sequencer client is opened as usual with #snd_seq_open().
|
||||
Then the application can switch to UMP mode via
|
||||
#snd_seq_set_client_midi_version() (or #snd_seq_client_info_set_midi_version()
|
||||
and #snd_seq_set_client_info() combo).
|
||||
For running in UMP MIDI 1.0 protocol, pass #SND_SEQ_CLIENT_UMP_MIDI_1_0,
|
||||
and for UMP MIDI 2.0 protocol, pass #SND_SEQ_CLIENT_UMP_MIDI_2_0, respectively.
|
||||
|
||||
In either UMP mode, we use #snd_seq_ump_event_t for sequencer event records
|
||||
instead of #snd_seq_event_t due to the lack of the data payload size in the
|
||||
latter type. #snd_seq_ump_event_t contains the array of 32bit int as its
|
||||
data payload for UMP, defined as a union of the existing data payload of
|
||||
#snd_seq_event_data_t. Other than the extended data payload, all other fields
|
||||
are identical with #snd_seq_event_t.
|
||||
|
||||
There are corresponding API helpers for #snd_seq_ump_event_t, such as
|
||||
#snd_seq_ump_event_input() and #snd_seq_ump_event_input().
|
||||
Most of macros such as #snd_seq_ev_set_dest() can be used for both
|
||||
#snd_seq_event_t and #snd_seq_ump_event_t types since they are C-macro
|
||||
without explicit type checks.
|
||||
|
||||
When a standard MIDI event (such as note-on or channel control) is sent to a
|
||||
UMP sequencer client, it's automatically translated to a UMP packet embedded
|
||||
in #snd_seq_ump_event_t. Ditto about sending from a UMP sequencer client to
|
||||
a legacy sequencer client; the UMP event is translated to an old-type event
|
||||
like #SND_SEQ_EVENT_NOTEON type automatically, too.
|
||||
The translation between UMP MIDI 1.0 and MIDI 2.0 is done in ALSA core
|
||||
as well. That is, from the application POV, connections are pretty seamless,
|
||||
and applications can keep running just like before, no matter whether the
|
||||
target is UMP or not.
|
||||
|
||||
For encoding and decoding a UMP packet data, there are structs and macros
|
||||
defined in sound/ump_msg.h.
|
||||
|
||||
MIDI 2.0 devices provide extra information as UMP Endpoint and UMP Function
|
||||
Block information. Those information can be obtained via
|
||||
#snd_seq_get_ump_endpoint_info() and #snd_seq_get_ump_block_info() from a
|
||||
sequencer client.
|
||||
|
||||
\subsection seq_midi2_virtual_ump Creation of UMP Virtual Endpoint and Function Blocks
|
||||
|
||||
For making it easier to create a virtual MIDI 2.0 device in user-space,
|
||||
there are a couple of new API functions. For creating a UMP Endpoint in an
|
||||
application, call snd_seq_create_ump_endpoint() with a properly filled
|
||||
#snd_ump_endpoint_info data. Usually it should be called right after
|
||||
#snd_seq_open() call. The call of #snd_seq_create_ump_endpoint() switches
|
||||
to the corresponding MIDI protocol, and you don't need to call
|
||||
#snd_seq_set_client_midi_version(). It will create a sequencer port
|
||||
corresponding to UMP Endpoint (named as "MIDI 2.0") and sequencer ports
|
||||
for the UMP Groups, too.
|
||||
|
||||
For creating a UMP Function Block, call snd_seq_create_ump_block() with a
|
||||
properly filled #snd_ump_block_info data. This will update the corresponding
|
||||
sequencer ports accordingly, too.
|
||||
|
||||
*/
|
||||
|
||||
#include "seq_local.h"
|
||||
|
|
@ -1042,7 +1118,8 @@ int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
|
|||
*/
|
||||
int snd_seq_close(snd_seq_t *seq)
|
||||
{
|
||||
int err;
|
||||
int i, err;
|
||||
|
||||
assert(seq);
|
||||
err = seq->ops->close(seq);
|
||||
if (seq->dl_handle)
|
||||
|
|
@ -1051,6 +1128,9 @@ int snd_seq_close(snd_seq_t *seq)
|
|||
free(seq->ibuf);
|
||||
free(seq->tmpbuf);
|
||||
free(seq->name);
|
||||
free(seq->ump_ep);
|
||||
for (i = 0; i < 16; i++)
|
||||
free(seq->ump_blks[i]);
|
||||
free(seq);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1276,7 +1356,7 @@ int snd_seq_set_input_buffer_size(snd_seq_t *seq, size_t size)
|
|||
if (size != seq->ibufsize) {
|
||||
char *newbuf;
|
||||
/* use ump event size for avoiding reallocation at switching */
|
||||
newbuf = calloc(sizeof(snd_seq_ump_event_t), size);
|
||||
newbuf = calloc(size, sizeof(snd_seq_ump_event_t));
|
||||
if (newbuf == NULL)
|
||||
return -ENOMEM;
|
||||
free(seq->ibuf);
|
||||
|
|
@ -1790,7 +1870,7 @@ int snd_seq_client_info_get_ump_groupless_enabled(const snd_seq_client_info_t *i
|
|||
int snd_seq_client_info_get_ump_conversion(const snd_seq_client_info_t *info)
|
||||
{
|
||||
assert(info);
|
||||
return info->midi_version;
|
||||
return !(info->group_filter & SNDRV_SEQ_FILTER_NO_CONVERT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2351,6 +2431,19 @@ int snd_seq_port_info_get_ump_group(const snd_seq_port_info_t *info)
|
|||
return info->ump_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the status of the optional MIDI 1.0 port in MIDI 2.0 UMP Endpoint
|
||||
* \param info port_info container
|
||||
* \return 1 if it's an optional MIDI 1.0 port in MIDI 2.0 UMP Endpoint
|
||||
*
|
||||
* \sa snd_seq_get_port_info(), snd_seq_port_info_set_ump_is_midi1()
|
||||
*/
|
||||
int snd_seq_port_info_get_ump_is_midi1(const snd_seq_port_info_t *info)
|
||||
{
|
||||
assert(info);
|
||||
return !!(info->flags & SNDRV_SEQ_PORT_FLG_IS_MIDI1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the client id of a port_info container
|
||||
* \param info port_info container
|
||||
|
|
@ -2555,6 +2648,22 @@ void snd_seq_port_info_set_ump_group(snd_seq_port_info_t *info, int ump_group)
|
|||
info->ump_group = ump_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the optional MIDI 1.0 port in MIDI 2.0 UMP Endpoint
|
||||
* \param info port_info container
|
||||
* \param is_midi1 non-zero for MIDI 1.0 port in MIDI 2.0 EP
|
||||
*
|
||||
* \sa snd_seq_get_port_info(), snd_seq_port_info_get_ump_is_midi1()
|
||||
*/
|
||||
void snd_seq_port_info_set_ump_is_midi1(snd_seq_port_info_t *info, int is_midi1)
|
||||
{
|
||||
assert(info);
|
||||
if (is_midi1)
|
||||
info->flags |= SNDRV_SEQ_PORT_FLG_IS_MIDI1;
|
||||
else
|
||||
info->flags &= ~SNDRV_SEQ_PORT_FLG_IS_MIDI1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief create a sequencer port on the current client
|
||||
* \param seq sequencer handle
|
||||
|
|
@ -3813,6 +3922,19 @@ unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info
|
|||
return info->skew_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the tempo base of a queue_status container
|
||||
* \param info queue_status container
|
||||
* \return tempo base time in nsec unit
|
||||
*
|
||||
* \sa snd_seq_get_queue_tempo()
|
||||
*/
|
||||
unsigned int snd_seq_queue_tempo_get_tempo_base(const snd_seq_queue_tempo_t *info)
|
||||
{
|
||||
assert(info);
|
||||
return info->tempo_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the tempo of a queue_status container
|
||||
* \param info queue_status container
|
||||
|
|
@ -3868,6 +3990,21 @@ void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int
|
|||
info->skew_base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the tempo base of a queue_status container
|
||||
* \param info queue_status container
|
||||
* \param tempo_base tempo base time in nsec unit
|
||||
*
|
||||
* \sa snd_seq_get_queue_tempo()
|
||||
*/
|
||||
void snd_seq_queue_tempo_set_tempo_base(snd_seq_queue_tempo_t *info, unsigned int tempo_base)
|
||||
{
|
||||
assert(info);
|
||||
if (!tempo_base)
|
||||
tempo_base = 1000;
|
||||
info->tempo_base = tempo_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief obtain the current tempo of the queue
|
||||
* \param seq sequencer handle
|
||||
|
|
@ -3897,10 +4034,25 @@ int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo
|
|||
int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
|
||||
{
|
||||
assert(seq && tempo);
|
||||
if (!seq->has_queue_tempo_base &&
|
||||
tempo->tempo_base && tempo->tempo_base != 1000)
|
||||
return -EINVAL;
|
||||
tempo->queue = q;
|
||||
return seq->ops->set_queue_tempo(seq, tempo);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief inquiry the support of tempo base change
|
||||
* \param seq sequencer handle
|
||||
* \return 1 if the client supports the tempo base change, 0 if not
|
||||
*
|
||||
* \sa snd_seq_get_queue_tempo()
|
||||
*/
|
||||
int snd_seq_has_queue_tempo_base(snd_seq_t *seq)
|
||||
{
|
||||
assert(seq);
|
||||
return seq->has_queue_tempo_base;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,15 @@ static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * in
|
|||
{
|
||||
snd_seq_hw_t *hw = seq->private_data;
|
||||
|
||||
/* added fields are not checked on older kernels */
|
||||
if (SNDRV_PROTOCOL_VERSION(1, 0, 3) > hw->version) {
|
||||
if (info->midi_version > 0)
|
||||
return -EINVAL;
|
||||
if (info->filter & SNDRV_SEQ_FILTER_NO_CONVERT)
|
||||
return -EINVAL;
|
||||
if (info->group_filter != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
|
||||
/*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/
|
||||
return -errno;
|
||||
|
|
@ -275,12 +284,15 @@ static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * te
|
|||
/*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
|
||||
return -errno;
|
||||
}
|
||||
if (!seq->has_queue_tempo_base)
|
||||
tempo->tempo_base = 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
|
||||
{
|
||||
snd_seq_hw_t *hw = seq->private_data;
|
||||
|
||||
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
|
||||
/*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
|
||||
return -errno;
|
||||
|
|
@ -567,7 +579,7 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
|
|||
}
|
||||
}
|
||||
if (streams & SND_SEQ_OPEN_INPUT) {
|
||||
seq->ibuf = (char *) calloc(sizeof(snd_seq_ump_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
|
||||
seq->ibuf = (char *) calloc(seq->ibufsize = SND_SEQ_IBUF_SIZE, sizeof(snd_seq_ump_event_t));
|
||||
if (!seq->ibuf) {
|
||||
free(seq->obuf);
|
||||
free(hw);
|
||||
|
|
@ -587,6 +599,8 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
|
|||
seq->ops = &snd_seq_hw_ops;
|
||||
seq->private_data = hw;
|
||||
seq->packet_size = sizeof(snd_seq_event_t);
|
||||
seq->has_queue_tempo_base = ver >= SNDRV_PROTOCOL_VERSION(1, 0, 4);
|
||||
|
||||
client = snd_seq_hw_client_id(seq);
|
||||
if (client < 0) {
|
||||
snd_seq_close(seq);
|
||||
|
|
|
|||
|
|
@ -94,6 +94,11 @@ struct _snd_seq {
|
|||
size_t tmpbufsize; /* size of errbuf */
|
||||
size_t packet_size; /* input packet alignment size */
|
||||
int midi_version; /* current protocol version */
|
||||
int has_queue_tempo_base; /* support queue tempo-base? */
|
||||
|
||||
unsigned int num_ump_groups; /* number of UMP groups */
|
||||
snd_ump_endpoint_info_t *ump_ep; /* optional UMP info */
|
||||
snd_ump_block_info_t *ump_blks[16]; /* optional UMP block info */
|
||||
};
|
||||
|
||||
int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode);
|
||||
|
|
|
|||
241
src/seq/seqmid.c
241
src/seq/seqmid.c
|
|
@ -493,3 +493,244 @@ int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief create a UMP Endpoint for the given sequencer client
|
||||
* \param seq sequencer handle
|
||||
* \param info UMP Endpoint information to initialize
|
||||
* \param num_groups max number of groups in the endpoint
|
||||
* \return 0 on success or negative error code
|
||||
*
|
||||
* This function initializes the sequencer client to the corresponding
|
||||
* MIDI 2.0 mode (either MIDI 1.0 or MIDI 2.0 protocol) depending on the
|
||||
* given snd_ump_endpoint_info_t info.
|
||||
*
|
||||
* This function should be called right after opening a sequencer client.
|
||||
* The client name is updated from the UMP Endpoint name, and a primary
|
||||
* MIDI 2.0 UMP port and each UMP Group port are created.
|
||||
* The application should pass each UMP block info via succeeding
|
||||
* snd_seq_create_ump_block() call.
|
||||
*/
|
||||
int snd_seq_create_ump_endpoint(snd_seq_t *seq,
|
||||
const snd_ump_endpoint_info_t *info,
|
||||
unsigned int num_groups)
|
||||
{
|
||||
int err, version;
|
||||
unsigned int i;
|
||||
snd_seq_port_info_t *pinfo;
|
||||
|
||||
if (seq->ump_ep)
|
||||
return -EBUSY;
|
||||
|
||||
if (num_groups < 1 || num_groups > SND_UMP_MAX_GROUPS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(info->protocol_caps & info->protocol)) {
|
||||
SNDERR("Inconsistent UMP protocol_caps and protocol\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI2) {
|
||||
version = SND_SEQ_CLIENT_UMP_MIDI_2_0;
|
||||
} else if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI1) {
|
||||
version = SND_SEQ_CLIENT_UMP_MIDI_1_0;
|
||||
} else {
|
||||
SNDERR("Invalid UMP protocol set 0x%x\n", info->protocol);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = snd_seq_set_client_midi_version(seq, version);
|
||||
if (err < 0) {
|
||||
SNDERR("Failed to set to MIDI protocol 0x%x\n", version);
|
||||
return err;
|
||||
}
|
||||
|
||||
seq->ump_ep = malloc(sizeof(*info));
|
||||
if (!seq->ump_ep)
|
||||
return -ENOMEM;
|
||||
|
||||
*seq->ump_ep = *info;
|
||||
if (!seq->ump_ep->version)
|
||||
seq->ump_ep->version = SND_UMP_EP_INFO_DEFAULT_VERSION;
|
||||
|
||||
if (info->name[0]) {
|
||||
err = snd_seq_set_client_name(seq, (const char *)info->name);
|
||||
if (err < 0)
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
err = snd_seq_set_ump_endpoint_info(seq, seq->ump_ep);
|
||||
if (err < 0) {
|
||||
SNDERR("Failed to set UMP EP info\n");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
snd_seq_port_info_alloca(&pinfo);
|
||||
|
||||
snd_seq_port_info_set_port(pinfo, 0);
|
||||
snd_seq_port_info_set_port_specified(pinfo, 1);
|
||||
snd_seq_port_info_set_name(pinfo, "MIDI 2.0");
|
||||
snd_seq_port_info_set_capability(pinfo,
|
||||
SND_SEQ_PORT_CAP_UMP_ENDPOINT |
|
||||
SND_SEQ_PORT_CAP_READ |
|
||||
SND_SEQ_PORT_CAP_SYNC_READ |
|
||||
SND_SEQ_PORT_CAP_SUBS_READ |
|
||||
SND_SEQ_PORT_CAP_WRITE |
|
||||
SND_SEQ_PORT_CAP_SYNC_WRITE |
|
||||
SND_SEQ_PORT_CAP_SUBS_WRITE |
|
||||
SND_SEQ_PORT_CAP_DUPLEX);
|
||||
snd_seq_port_info_set_type(pinfo,
|
||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
|
||||
SND_SEQ_PORT_TYPE_MIDI_UMP |
|
||||
SND_SEQ_PORT_TYPE_APPLICATION |
|
||||
SND_SEQ_PORT_TYPE_PORT);
|
||||
snd_seq_port_info_set_ump_group(pinfo, 0);
|
||||
err = snd_seq_create_port(seq, pinfo);
|
||||
if (err < 0) {
|
||||
SNDERR("Failed to create MIDI 2.0 port\n");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_groups; i++) {
|
||||
char name[32];
|
||||
|
||||
snd_seq_port_info_set_port(pinfo, i + 1);
|
||||
snd_seq_port_info_set_port_specified(pinfo, 1);
|
||||
sprintf(name, "Group %d", i + 1);
|
||||
snd_seq_port_info_set_capability(pinfo, 0); /* set later */
|
||||
snd_seq_port_info_set_name(pinfo, name);
|
||||
snd_seq_port_info_set_ump_group(pinfo, i + 1);
|
||||
err = snd_seq_create_port(seq, pinfo);
|
||||
if (err < 0) {
|
||||
SNDERR("Failed to create Group port %d\n", i + 1);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
seq->num_ump_groups = num_groups;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* delete all ports including port 0 */
|
||||
for (i = 0; i <= num_groups; i++)
|
||||
snd_seq_delete_port(seq, i);
|
||||
error_free:
|
||||
free(seq->ump_ep);
|
||||
seq->ump_ep = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* update each port name and capability from the block list */
|
||||
static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
|
||||
{
|
||||
unsigned int i, b;
|
||||
snd_seq_port_info_t *pinfo;
|
||||
snd_ump_block_info_t *bp;
|
||||
|
||||
snd_seq_port_info_alloca(&pinfo);
|
||||
|
||||
for (i = 0; i < seq->num_ump_groups; i++) {
|
||||
char blknames[64];
|
||||
char name[64];
|
||||
unsigned int caps = 0;
|
||||
|
||||
blknames[0] = 0;
|
||||
for (b = 0; b < ep->num_blocks; b++) {
|
||||
bp = seq->ump_blks[b];
|
||||
if (!bp)
|
||||
continue;
|
||||
if (i < bp->first_group ||
|
||||
i >= bp->first_group + bp->num_groups)
|
||||
continue;
|
||||
switch (bp->direction) {
|
||||
case SND_UMP_DIR_INPUT: /* sink, receiver */
|
||||
caps |= SND_SEQ_PORT_CAP_WRITE |
|
||||
SND_SEQ_PORT_CAP_SYNC_WRITE |
|
||||
SND_SEQ_PORT_CAP_SUBS_WRITE;
|
||||
break;
|
||||
case SND_UMP_DIR_OUTPUT: /* source, transmitter */
|
||||
caps |= SND_SEQ_PORT_CAP_READ |
|
||||
SND_SEQ_PORT_CAP_SYNC_READ |
|
||||
SND_SEQ_PORT_CAP_SUBS_READ;
|
||||
break;
|
||||
case SND_UMP_DIR_BIDIRECTION:
|
||||
caps |= SND_SEQ_PORT_CAP_READ |
|
||||
SND_SEQ_PORT_CAP_SYNC_READ |
|
||||
SND_SEQ_PORT_CAP_SUBS_READ |
|
||||
SND_SEQ_PORT_CAP_WRITE |
|
||||
SND_SEQ_PORT_CAP_SYNC_WRITE |
|
||||
SND_SEQ_PORT_CAP_SUBS_WRITE |
|
||||
SND_SEQ_PORT_CAP_DUPLEX;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bp->name[0] == '\0')
|
||||
continue;
|
||||
if (blknames[0])
|
||||
snd_strlcat(blknames, ", ", sizeof(blknames));
|
||||
snd_strlcat(blknames, (const char *)bp->name, sizeof(blknames));
|
||||
}
|
||||
|
||||
if (!*blknames)
|
||||
continue;
|
||||
|
||||
snprintf(name, sizeof(name), "Group %d (%s)", i + 1, blknames);
|
||||
if (snd_seq_get_port_info(seq, i + 1, pinfo) < 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(name, snd_seq_port_info_get_name(pinfo)) ||
|
||||
snd_seq_port_info_get_capability(pinfo) != caps) {
|
||||
snd_seq_port_info_set_name(pinfo, name);
|
||||
snd_seq_port_info_set_capability(pinfo, caps);
|
||||
snd_seq_set_port_info(seq, i + 1, pinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief create a UMP block for the given sequencer client
|
||||
* \param seq sequencer handle
|
||||
* \param blkid 0-based block id
|
||||
* \param info UMP block info to initialize
|
||||
* \return 0 on success or negative error code
|
||||
*
|
||||
* This function sets up the UMP block info of the given block id.
|
||||
* The sequencer port name is updated accordingly with the associated
|
||||
* block name automatically.
|
||||
*/
|
||||
int snd_seq_create_ump_block(snd_seq_t *seq, int blkid,
|
||||
const snd_ump_block_info_t *info)
|
||||
{
|
||||
snd_ump_block_info_t *bp;
|
||||
snd_ump_endpoint_info_t *ep = seq->ump_ep;
|
||||
int err;
|
||||
|
||||
if (!ep)
|
||||
return -EINVAL;
|
||||
if (info->first_group >= seq->num_ump_groups ||
|
||||
info->first_group + info->num_groups > seq->num_ump_groups)
|
||||
return -EINVAL;
|
||||
if (blkid < 0 || blkid >= (int)ep->num_blocks)
|
||||
return -EINVAL;
|
||||
|
||||
if (seq->ump_blks[blkid])
|
||||
return -EBUSY;
|
||||
seq->ump_blks[blkid] = bp = malloc(sizeof(*info));
|
||||
if (!bp)
|
||||
return -ENOMEM;
|
||||
*bp = *info;
|
||||
|
||||
if (!bp->midi_ci_version)
|
||||
bp->midi_ci_version = SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION;
|
||||
bp->active = 1;
|
||||
|
||||
err = snd_seq_set_ump_block_info(seq, blkid, bp);
|
||||
if (err < 0) {
|
||||
SNDERR("Failed to set UMP EP info\n");
|
||||
free(bp);
|
||||
seq->ump_blks[blkid] = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
update_group_ports(seq, ep);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2928,7 +2928,14 @@ int uc_mgr_scan_master_configs(const char **_list[])
|
|||
snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d",
|
||||
snd_config_topdir());
|
||||
|
||||
#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__)
|
||||
#if defined(_GNU_SOURCE) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__FreeBSD__) && \
|
||||
!defined(__OpenBSD__) && \
|
||||
!defined(__DragonFly__) && \
|
||||
!defined(__sun) && \
|
||||
!defined(__ANDROID__) && \
|
||||
!defined(__OHOS__)
|
||||
#define SORTFUNC versionsort64
|
||||
#else
|
||||
#define SORTFUNC alphasort64
|
||||
|
|
|
|||
|
|
@ -386,26 +386,58 @@ Evaluation order | Configuration block | Evaluation restart
|
|||
The dynamic tree identifiers and assigned values in the configuration tree are
|
||||
substituted. The substitutes strings are in the table bellow.
|
||||
|
||||
Substituted string | Value
|
||||
---------------------|---------------------
|
||||
${OpenName} | Original UCM card name (passed to snd_use_case_mgr_open())
|
||||
${ConfLibDir} | Library top-level configuration directory (e.g. /usr/share/alsa)
|
||||
${ConfTopDir} | Top-level UCM configuration directory (e.g. /usr/share/alsa/ucm2)
|
||||
${ConfDir} | Card's UCM configuration directory (e.g. /usr/share/alsa/ucm2/conf.d/USB-Audio)
|
||||
${ConfName} | Configuration name (e.g. USB-Audio.conf)
|
||||
${CardNumber} | Real ALSA card number (or empty string for the virtual UCM card)
|
||||
${CardId} | ALSA card identifier (see snd_ctl_card_info_get_id())
|
||||
${CardDriver} | ALSA card driver (see snd_ctl_card_info_get_driver())
|
||||
${CardName} | ALSA card name (see snd_ctl_card_info_get_name())
|
||||
${CardLongName} | ALSA card long name (see snd_ctl_card_info_get_longname())
|
||||
${CardComponents} | ALSA card components (see snd_ctl_card_info_get_components())
|
||||
Substituted string | Value
|
||||
-----------------------|---------------------
|
||||
${LibCaps} | Library capabilities (string like '*a*b*c*') [**Syntax 8**]
|
||||
${OpenName} | Original UCM card name (passed to snd_use_case_mgr_open())
|
||||
${ConfLibDir} | Library top-level configuration directory (e.g. /usr/share/alsa)
|
||||
${ConfTopDir} | Top-level UCM configuration directory (e.g. /usr/share/alsa/ucm2)
|
||||
${ConfDir} | Card's UCM configuration directory (e.g. /usr/share/alsa/ucm2/conf.d/USB-Audio)
|
||||
${ConfName} | Configuration name (e.g. USB-Audio.conf)
|
||||
${CardNumber} | Real ALSA card number (or empty string for the virtual UCM card)
|
||||
${CardId} | ALSA card identifier (see snd_ctl_card_info_get_id())
|
||||
${CardDriver} | ALSA card driver (see snd_ctl_card_info_get_driver())
|
||||
${CardName} | ALSA card name (see snd_ctl_card_info_get_name())
|
||||
${CardLongName} | ALSA card long name (see snd_ctl_card_info_get_longname())
|
||||
${CardComponents} | ALSA card components (see snd_ctl_card_info_get_components())
|
||||
${env:\<str\>} | Environment variable \<str\>
|
||||
${sys:\<str\>} | Contents of sysfs file \<str\>
|
||||
${sys-card:\<str\>} | Contents of sysfs file in /sys/class/sound/card? tree [**Syntax 8**]
|
||||
${var:\<str\>} | UCM parser variable (set using a _Define_ block)
|
||||
${eval:\<str\>} | Evaluate expression like *($var+2)/3* [**Syntax 5**]
|
||||
${find-card:\<str\>} | Find a card - see _Find card substitution_ section
|
||||
${find-device:\<str\>} | Find a device - see _Find device substitution_ section
|
||||
|
||||
General note: If two dollars '$$' instead one dolar '$' are used for the
|
||||
substitution identification, the error is ignored (e.g. file does not
|
||||
exists in sysfs tree).
|
||||
|
||||
Note for *var* substitution: If the first characters is minus ('-') the
|
||||
empty string is substituted when the variable is not defined.
|
||||
|
||||
Note for *sys* and *sys-card* substitutions: since syntax 8, there is
|
||||
also extension to fetch data from given range with the optional conversion
|
||||
to hexadecimal format when the source file has binary contents.
|
||||
|
||||
Example - fetch bytes from positions 0x10..0x15 (6 bytes):
|
||||
|
||||
~~~{.html}
|
||||
Define.Bytes1 "${sys-card:[type=hex,pos=0x10,size=6]device/../descriptors}"
|
||||
~~~
|
||||
|
||||
Example - fetch one byte from position 0x22:
|
||||
|
||||
~~~{.html}
|
||||
Define.Bytes2 "${sys-card:[type=hex,pos=0x22]device/../descriptors}"
|
||||
~~~
|
||||
|
||||
Replace *type=hex* with *type=ascii* or omit this variable settings to work with ASCII characters.
|
||||
|
||||
|
||||
#### Library capabilities
|
||||
|
||||
None at the moment. The list will grow after *Syntax 8* (library 1.2.14).
|
||||
|
||||
#### Special whole string substitution
|
||||
|
||||
Substituted string | Value
|
||||
|
|
|
|||
|
|
@ -254,8 +254,12 @@ int uc_mgr_exec(const char *prog)
|
|||
|
||||
close(f);
|
||||
|
||||
#if defined(_GNU_SOURCE)
|
||||
close_range(3, maxfd, 0);
|
||||
#else
|
||||
for (f = 3; f < maxfd; f++)
|
||||
close(f);
|
||||
#endif
|
||||
|
||||
/* install default handlers for the forked process */
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
#include <pthread.h>
|
||||
#include "use-case.h"
|
||||
|
||||
#define SYNTAX_VERSION_MAX 7
|
||||
#define SYNTAX_VERSION_MAX 8
|
||||
|
||||
#define MAX_CARD_SHORT_NAME 32
|
||||
#define MAX_CARD_LONG_NAME 80
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ int uc_mgr_define_regex(snd_use_case_mgr_t *uc_mgr, const char *name,
|
|||
err = regcomp(&re, s, options);
|
||||
free(s);
|
||||
if (err) {
|
||||
uc_error("Regex '%s' compilation failed (code %d)", err);
|
||||
uc_error("Regex '%s' compilation failed (code %d)", s, err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
* transition sequences, multiple client access and user defined use
|
||||
* cases was kindly sponsored by Wolfson Microelectronics PLC.
|
||||
*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
* Copyright (C) 2019-2025 Red Hat Inc.
|
||||
* Authors: Jaroslav Kysela <perex@perex.cz>
|
||||
*/
|
||||
|
||||
|
|
@ -30,6 +30,19 @@
|
|||
#include <limits.h>
|
||||
#include <regex.h>
|
||||
|
||||
/* capabilities string like "*a*b*c" will be used to check library extensions */
|
||||
/* use Needle like "*a*" or regex expression for a match */
|
||||
#define LIB_CAPS_STRING "*" "*"
|
||||
|
||||
static unsigned char _hex_table[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
static char *rval_lib_caps(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (uc_mgr->conf_format < 8)
|
||||
return NULL;
|
||||
return strdup(LIB_CAPS_STRING);
|
||||
}
|
||||
|
||||
static char *rval_open_name(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
const char *name;
|
||||
|
|
@ -504,20 +517,117 @@ static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *i
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id)
|
||||
#define RANGE_TYPE_ASCII 0
|
||||
#define RANGE_TYPE_HEX 1
|
||||
|
||||
static int parse_position(snd_config_t *config, const char *name, ssize_t *pos, bool optional)
|
||||
{
|
||||
snd_config_t *d;
|
||||
const char *s;
|
||||
long v;
|
||||
|
||||
if (snd_config_search(config, name, &d)) {
|
||||
if (optional) {
|
||||
*pos = -1;
|
||||
return 0;
|
||||
}
|
||||
uc_error("Unable to find field '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
if (!snd_config_get_integer(d, &v))
|
||||
goto fin;
|
||||
if (snd_config_get_string(d, &s))
|
||||
return -1;
|
||||
if (safe_strtol(s, &v)) {
|
||||
uc_error("Unable to parse position '%s'", s);
|
||||
return -1;
|
||||
}
|
||||
fin:
|
||||
*pos = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_range(const char *cfg, int *type, ssize_t *pos, ssize_t *size)
|
||||
{
|
||||
snd_config_t *config, *d;
|
||||
int err, retval = 0;
|
||||
const char *s;
|
||||
|
||||
err = snd_config_load_string(&config, cfg, 0);
|
||||
if (err < 0) {
|
||||
uc_error("The range arguments '%s' are invalid", cfg);
|
||||
return -1;
|
||||
}
|
||||
if (snd_config_search(config, "type", &d)) {
|
||||
*type = RANGE_TYPE_ASCII;
|
||||
} else {
|
||||
if (snd_config_get_string(d, &s))
|
||||
goto null;
|
||||
if (strcasecmp(s, "ascii") == 0) {
|
||||
*type = RANGE_TYPE_ASCII;
|
||||
} else if (strcasecmp(s, "hex") == 0) {
|
||||
*type = RANGE_TYPE_HEX;
|
||||
} else {
|
||||
uc_error("Unknown range type '%s'", s);
|
||||
}
|
||||
}
|
||||
*pos = 0;
|
||||
*size = -1;
|
||||
if (parse_position(config, "pos", pos, false) ||
|
||||
parse_position(config, "size", size, true)) {
|
||||
retval = -1;
|
||||
goto null;
|
||||
}
|
||||
|
||||
if (*size <= 0)
|
||||
*size = 1;
|
||||
if (*pos < 0) {
|
||||
uc_error("Invalid start position");
|
||||
retval = -1;
|
||||
goto null;
|
||||
}
|
||||
|
||||
null:
|
||||
snd_config_delete(config);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static char *rval_sysfs_main(snd_use_case_mgr_t *uc_mgr, const char *top_path, const char *id)
|
||||
{
|
||||
char path[PATH_MAX], link[PATH_MAX + 1];
|
||||
struct stat64 sb;
|
||||
ssize_t len;
|
||||
const char *e;
|
||||
int fd;
|
||||
ssize_t len, range_start = -1, range_size = -1;
|
||||
const char *e, *s;
|
||||
int fd, type = RANGE_TYPE_ASCII;
|
||||
|
||||
e = uc_mgr_sysfs_root();
|
||||
if (e == NULL)
|
||||
return NULL;
|
||||
if (id[0] == '[') {
|
||||
if (uc_mgr->conf_format < 8) {
|
||||
uc_error("Sysfs ranges are supported in v8+ syntax");
|
||||
return NULL;
|
||||
}
|
||||
s = strchr(id, ']');
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
len = s - id - 1;
|
||||
if ((size_t)(len - 1) > sizeof(link) - 1)
|
||||
return NULL;
|
||||
strncpy(link, id + 1, len);
|
||||
link[len] = '\0';
|
||||
if (parse_range(link, &type, &range_start, &range_size)) {
|
||||
uc_error("sysfs: cannot parse hex range '%s'", link);
|
||||
return NULL;
|
||||
}
|
||||
id = s + 1;
|
||||
}
|
||||
if (id[0] == '/')
|
||||
id++;
|
||||
snprintf(path, sizeof(path), "%s/%s", e, id);
|
||||
if (top_path)
|
||||
snprintf(path, sizeof(path), "%s/%s/%s", e, top_path, id);
|
||||
else
|
||||
snprintf(path, sizeof(path), "%s/%s", e, id);
|
||||
if (lstat64(path, &sb) != 0)
|
||||
return NULL;
|
||||
if (S_ISLNK(sb.st_mode)) {
|
||||
|
|
@ -542,18 +652,64 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char
|
|||
uc_error("sysfs open failed for '%s' (%d)", path, errno);
|
||||
return NULL;
|
||||
}
|
||||
len = read(fd, path, sizeof(path)-1);
|
||||
len = sizeof(path) - 1;
|
||||
if (range_start > 0 && lseek(fd, range_start, SEEK_SET) != range_start) {
|
||||
uc_error("sysfs seek failed (%d)", errno);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
if (range_size > 0) {
|
||||
if (range_size > len) {
|
||||
uc_error("sysfs EOB for '%s'", path);
|
||||
close(fd);
|
||||
return NULL;
|
||||
} else {
|
||||
len = range_size;
|
||||
}
|
||||
}
|
||||
len = read(fd, path, len);
|
||||
close(fd);
|
||||
if (len < 0) {
|
||||
uc_error("sysfs unable to read value '%s' (%d)", path, errno);
|
||||
return NULL;
|
||||
}
|
||||
if (type == RANGE_TYPE_HEX && range_start >= 0) {
|
||||
char *m = malloc(len * 2 + 1);
|
||||
ssize_t idx;
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
for (idx = 0; idx < len; idx++) {
|
||||
m[(idx * 2) + 0] = _hex_table[((unsigned char)path[idx]) >> 4];
|
||||
m[(idx * 2) + 1] = _hex_table[((unsigned char)path[idx]) & 0x0f];
|
||||
}
|
||||
m[len * 2] = '\0';
|
||||
return m;
|
||||
}
|
||||
while (len > 0 && path[len-1] == '\n')
|
||||
len--;
|
||||
path[len] = '\0';
|
||||
return strdup(path);
|
||||
}
|
||||
|
||||
static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr, const char *id)
|
||||
{
|
||||
return rval_sysfs_main(uc_mgr, NULL, id);
|
||||
}
|
||||
|
||||
static char *rval_sysfs_card(snd_use_case_mgr_t *uc_mgr, const char *id)
|
||||
{
|
||||
char top_path[32], *s;
|
||||
|
||||
if (uc_mgr->conf_format < 8) {
|
||||
uc_error("sys-card is supported in v8+ syntax");
|
||||
return NULL;
|
||||
}
|
||||
s = get_card_number(uc_mgr_get_master_ctl(uc_mgr));
|
||||
snprintf(top_path, sizeof(top_path), "class/sound/card%s", s);
|
||||
free(s);
|
||||
return rval_sysfs_main(uc_mgr, top_path, id);
|
||||
}
|
||||
|
||||
static char *rval_var(snd_use_case_mgr_t *uc_mgr, const char *id)
|
||||
{
|
||||
const char *v;
|
||||
|
|
@ -738,6 +894,7 @@ __std:
|
|||
goto __std;
|
||||
}
|
||||
fcn2 = NULL;
|
||||
MATCH_VARIABLE(value, "${LibCaps}", rval_lib_caps, false);
|
||||
MATCH_VARIABLE(value, "${OpenName}", rval_open_name, false);
|
||||
MATCH_VARIABLE(value, "${ConfLibDir}", rval_conf_libdir, false);
|
||||
MATCH_VARIABLE(value, "${ConfTopDir}", rval_conf_topdir, false);
|
||||
|
|
@ -751,6 +908,7 @@ __std:
|
|||
MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
|
||||
MATCH_VARIABLE2(value, "${env:", rval_env, false);
|
||||
MATCH_VARIABLE2(value, "${sys:", rval_sysfs, false);
|
||||
MATCH_VARIABLE2(value, "${sys-card:", rval_sysfs_card, false);
|
||||
MATCH_VARIABLE2(value, "${var:", rval_var, true);
|
||||
MATCH_VARIABLE2(value, "${eval:", rval_eval, false);
|
||||
MATCH_VARIABLE2(value, "${find-card:", rval_card_lookup, false);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
SUBDIRS=. lsb
|
||||
|
||||
check_PROGRAMS=control pcm pcm_min latency seq \
|
||||
playmidi1 timer rawmidi midiloop \
|
||||
check_PROGRAMS=control pcm pcm_min latency seq seq-ump-example \
|
||||
playmidi1 timer rawmidi midiloop umpinfo \
|
||||
oldapi queue_timer namehint client_event_filter \
|
||||
chmap audio_time user-ctl-element-set pcm-multi-thread
|
||||
|
||||
|
|
@ -12,10 +12,12 @@ pcm_min_LDADD=../src/libasound.la
|
|||
latency_LDADD=../src/libasound.la
|
||||
latency_LDFLAGS= -lm
|
||||
seq_LDADD=../src/libasound.la
|
||||
seq_ump_example_LDADD=../src/libasound.la
|
||||
playmidi1_LDADD=../src/libasound.la
|
||||
timer_LDADD=../src/libasound.la
|
||||
rawmidi_LDADD=../src/libasound.la
|
||||
midiloop_LDADD=../src/libasound.la
|
||||
umpinfo_LDADD=../src/libasound.la
|
||||
oldapi_LDADD=../src/libasound.la
|
||||
queue_timer_LDADD=../src/libasound.la
|
||||
namehint_LDADD=../src/libasound.la
|
||||
|
|
|
|||
246
test/midifile.c
246
test/midifile.c
|
|
@ -79,34 +79,34 @@
|
|||
/* public stuff */
|
||||
|
||||
/* Functions to be called while processing the MIDI file. */
|
||||
int (*Mf_getc) () = NULLFUNC;
|
||||
void (*Mf_error) () = NULLFUNC;
|
||||
void (*Mf_header) () = NULLFUNC;
|
||||
void (*Mf_trackstart) () = NULLFUNC;
|
||||
void (*Mf_trackend) () = NULLFUNC;
|
||||
void (*Mf_noteon) () = NULLFUNC;
|
||||
void (*Mf_noteoff) () = NULLFUNC;
|
||||
void (*Mf_pressure) () = NULLFUNC;
|
||||
void (*Mf_parameter) () = NULLFUNC;
|
||||
void (*Mf_pitchbend) () = NULLFUNC;
|
||||
void (*Mf_program) () = NULLFUNC;
|
||||
void (*Mf_chanpressure) () = NULLFUNC;
|
||||
void (*Mf_sysex) () = NULLFUNC;
|
||||
void (*Mf_arbitrary) () = NULLFUNC;
|
||||
void (*Mf_metamisc) () = NULLFUNC;
|
||||
void (*Mf_seqnum) () = NULLFUNC;
|
||||
void (*Mf_eot) () = NULLFUNC;
|
||||
void (*Mf_smpte) () = NULLFUNC;
|
||||
void (*Mf_tempo) () = NULLFUNC;
|
||||
void (*Mf_timesig) () = NULLFUNC;
|
||||
void (*Mf_keysig) () = NULLFUNC;
|
||||
void (*Mf_seqspecific) () = NULLFUNC;
|
||||
void (*Mf_text) () = NULLFUNC;
|
||||
int (*Mf_getc) (void) = NULLFUNC;
|
||||
void (*Mf_error) (char *s) = NULLFUNC;
|
||||
void (*Mf_header) (int format, int ntrks, int division) = NULLFUNC;
|
||||
void (*Mf_trackstart) (void) = NULLFUNC;
|
||||
void (*Mf_trackend) (void) = NULLFUNC;
|
||||
void (*Mf_noteon) (int chan, int c1, int c2) = NULLFUNC;
|
||||
void (*Mf_noteoff) (int chan, int c1, int c2) = NULLFUNC;
|
||||
void (*Mf_pressure) (int chan, int c1, int c2) = NULLFUNC;
|
||||
void (*Mf_parameter) (int chan, int c1, int c2) = NULLFUNC;
|
||||
void (*Mf_pitchbend) (int chan, int c1, int c2) = NULLFUNC;
|
||||
void (*Mf_program) (int chan, int c1) = NULLFUNC;
|
||||
void (*Mf_chanpressure) (int chan, int c1) = NULLFUNC;
|
||||
void (*Mf_sysex) (int len, char *msg) = NULLFUNC;
|
||||
void (*Mf_arbitrary) (int len, char *msg) = NULLFUNC;
|
||||
void (*Mf_metamisc) (int type, int len, char *msg) = NULLFUNC;
|
||||
void (*Mf_seqnum) (int num) = NULLFUNC;
|
||||
void (*Mf_eot) (void) = NULLFUNC;
|
||||
void (*Mf_smpte) (char m0, char m1, char m2, char m3, char m4) = NULLFUNC;
|
||||
void (*Mf_tempo) (long tempo) = NULLFUNC;
|
||||
void (*Mf_timesig) (char m0, char m1, char m2, char m3) = NULLFUNC;
|
||||
void (*Mf_keysig) (char m0, char m1) = NULLFUNC;
|
||||
void (*Mf_seqspecific) (int len, char *msg) = NULLFUNC;
|
||||
void (*Mf_text) (int type, int len, char *msg) = NULLFUNC;
|
||||
|
||||
/* Functions to implement in order to write a MIDI file */
|
||||
int (*Mf_putc) () = NULLFUNC;
|
||||
int (*Mf_writetrack) () = NULLFUNC;
|
||||
int (*Mf_writetempotrack) () = NULLFUNC;
|
||||
int (*Mf_putc) (unsigned char c) = NULLFUNC;
|
||||
int (*Mf_writetrack) (int track) = NULLFUNC;
|
||||
int (*Mf_writetempotrack) (void) = NULLFUNC;
|
||||
|
||||
int Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */
|
||||
/* not collapsed. */
|
||||
|
|
@ -132,29 +132,34 @@ static int tempo_history_count = 0;
|
|||
static long Mf_toberead = 0L;
|
||||
static long Mf_numbyteswritten = 0L;
|
||||
|
||||
static long readvarinum ();
|
||||
static long read32bit ();
|
||||
static long to32bit ();
|
||||
static int read16bit ();
|
||||
static int to16bit ();
|
||||
static char *msg ();
|
||||
static void readheader ();
|
||||
static int readtrack ();
|
||||
static void badbyte ();
|
||||
static void metaevent ();
|
||||
static void sysex ();
|
||||
static void chanmessage ();
|
||||
static void msginit ();
|
||||
static int msgleng ();
|
||||
static void msgadd ();
|
||||
static void biggermsg ();
|
||||
static int eputc ();
|
||||
static long readvarinum (void);
|
||||
static long read32bit (void);
|
||||
static long to32bit (int, int, int, int);
|
||||
static int read16bit (void);
|
||||
static int to16bit (int, int);
|
||||
static char *msg (void);
|
||||
static void readheader (void);
|
||||
static int readtrack (void);
|
||||
static void badbyte (int);
|
||||
static void metaevent (int);
|
||||
static void sysex (void);
|
||||
static void chanmessage (int, int, int);
|
||||
static void msginit (void);
|
||||
static int msgleng (void);
|
||||
static void msgadd (int);
|
||||
static void biggermsg (void);
|
||||
static int eputc (unsigned char);
|
||||
|
||||
double mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo);
|
||||
int mf_write_meta_event ();
|
||||
void mf_write_tempo ();
|
||||
void mf_write_seqnum ();
|
||||
void WriteVarLen ();
|
||||
void write32bit (unsigned long data);
|
||||
void write16bit (int data);
|
||||
void mf_write_track_chunk (int which_track, FILE *fp);
|
||||
void mf_write_header_chunk (int format, int ntracks, int division);
|
||||
int mf_write_meta_event (unsigned long delta_time, unsigned char type,
|
||||
unsigned char *data, unsigned long size);
|
||||
void mf_write_tempo (unsigned long delta_time, unsigned long tempo);
|
||||
void mf_write_seqnum (unsigned long delta_time, unsigned int seqnum);
|
||||
void WriteVarLen (unsigned long value);
|
||||
|
||||
#ifdef READ_MODS
|
||||
#include "mp_mod.c"
|
||||
|
|
@ -163,7 +168,7 @@ static int mod_file_flag = 0;
|
|||
static int force_exit;
|
||||
|
||||
void
|
||||
mfread ()
|
||||
mfread (void)
|
||||
{
|
||||
force_exit = 0;
|
||||
if (Mf_getc == NULLFUNC)
|
||||
|
|
@ -181,15 +186,13 @@ mfread ()
|
|||
|
||||
/* for backward compatibility with the original lib */
|
||||
void
|
||||
midifile ()
|
||||
midifile (void)
|
||||
{
|
||||
mfread ();
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
readmt (s) /* read through the "MThd" or "MTrk" header string */
|
||||
char *s;
|
||||
static int
|
||||
readmt (char *s) /* read through the "MThd" or "MTrk" header string */
|
||||
{
|
||||
int n = 0;
|
||||
char *p = s;
|
||||
|
|
@ -211,9 +214,8 @@ readmt (s) /* read through the "MThd" or "MTrk" header string */
|
|||
return (c);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
egetc () /* read a single character and abort on EOF */
|
||||
static int
|
||||
egetc (void) /* read a single character and abort on EOF */
|
||||
{
|
||||
int c = (*Mf_getc) ();
|
||||
|
||||
|
|
@ -225,9 +227,8 @@ egetc () /* read a single character and abort on EOF */
|
|||
return (c);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readheader () /* read a header chunk */
|
||||
static void
|
||||
readheader (void) /* read a header chunk */
|
||||
{
|
||||
int format, ntrks, division;
|
||||
|
||||
|
|
@ -280,9 +281,8 @@ readheader () /* read a header chunk */
|
|||
|
||||
|
||||
/*#define DEBUG_TIMES*/
|
||||
static
|
||||
unsigned long
|
||||
find_tempo()
|
||||
static unsigned long
|
||||
find_tempo(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long old_tempo = Mf_currtempo;
|
||||
|
|
@ -307,9 +307,8 @@ printf("[revised_time %lu, new_tempo %lu]\n", revised_time, new_tempo);
|
|||
return(new_tempo);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
readtrack () /* read a track chunk */
|
||||
static int
|
||||
readtrack (void) /* read a track chunk */
|
||||
{
|
||||
/* This array is indexed by the high half of a status byte. It's */
|
||||
/* value is either the number of bytes needed (1 or 2) for a channel */
|
||||
|
|
@ -499,10 +498,8 @@ old_f_realtime, delta_secs * 1600.0);
|
|||
return (1);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
badbyte (c)
|
||||
int c;
|
||||
static void
|
||||
badbyte (int c)
|
||||
{
|
||||
char buff[32];
|
||||
|
||||
|
|
@ -510,8 +507,7 @@ badbyte (c)
|
|||
mferror (buff);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
static void
|
||||
metaevent (int type)
|
||||
{
|
||||
int leng = msgleng ();
|
||||
|
|
@ -577,19 +573,15 @@ metaevent (int type)
|
|||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sysex ()
|
||||
static void
|
||||
sysex (void)
|
||||
{
|
||||
if (Mf_sysex)
|
||||
(*Mf_sysex) (msgleng (), msg ());
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
chanmessage (status, c1, c2)
|
||||
int status;
|
||||
int c1, c2;
|
||||
static void
|
||||
chanmessage (int status, int c1, int c2)
|
||||
{
|
||||
int chan = status & 0xf;
|
||||
|
||||
|
|
@ -635,7 +627,7 @@ chanmessage (status, c1, c2)
|
|||
/* number of characters it took. */
|
||||
|
||||
static long
|
||||
readvarinum ()
|
||||
readvarinum (void)
|
||||
{
|
||||
long value;
|
||||
int c;
|
||||
|
|
@ -668,14 +660,13 @@ to32bit (int c1, int c2, int c3, int c4)
|
|||
}
|
||||
|
||||
static int
|
||||
to16bit (c1, c2)
|
||||
int c1, c2;
|
||||
to16bit (int c1, int c2)
|
||||
{
|
||||
return ((c1 & 0xff) << 8) + (c2 & 0xff);
|
||||
}
|
||||
|
||||
static long
|
||||
read32bit ()
|
||||
read32bit (void)
|
||||
{
|
||||
int c1, c2, c3, c4;
|
||||
|
||||
|
|
@ -687,7 +678,7 @@ read32bit ()
|
|||
}
|
||||
|
||||
static int
|
||||
read16bit ()
|
||||
read16bit (void)
|
||||
{
|
||||
int c1, c2;
|
||||
c1 = egetc ();
|
||||
|
|
@ -697,8 +688,7 @@ read16bit ()
|
|||
|
||||
/* static */
|
||||
void
|
||||
mferror (s)
|
||||
char *s;
|
||||
mferror (char *s)
|
||||
{
|
||||
if (Mf_error)
|
||||
(*Mf_error) (s);
|
||||
|
|
@ -714,30 +704,26 @@ static char *Msgbuff = NULL; /* message buffer */
|
|||
static int Msgsize = 0; /* Size of currently allocated Msg */
|
||||
static int Msgindex = 0; /* index of next available location in Msg */
|
||||
|
||||
static
|
||||
void
|
||||
msginit ()
|
||||
static void
|
||||
msginit (void)
|
||||
{
|
||||
Msgindex = 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
msg ()
|
||||
msg (void)
|
||||
{
|
||||
return (Msgbuff);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
msgleng ()
|
||||
static int
|
||||
msgleng (void)
|
||||
{
|
||||
return (Msgindex);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
msgadd (c)
|
||||
int c;
|
||||
static void
|
||||
msgadd (int c)
|
||||
{
|
||||
/* If necessary, allocate larger message buffer. */
|
||||
if (Msgindex >= Msgsize)
|
||||
|
|
@ -745,11 +731,9 @@ msgadd (c)
|
|||
Msgbuff[Msgindex++] = c;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
biggermsg ()
|
||||
static void
|
||||
biggermsg (void)
|
||||
{
|
||||
/* char *malloc(); */
|
||||
char *newmess;
|
||||
char *oldmess = Msgbuff;
|
||||
int oldleng = Msgsize;
|
||||
|
|
@ -805,12 +789,9 @@ static int laststatus = 0;
|
|||
* to work with Mf_putc.
|
||||
*/
|
||||
void
|
||||
mfwrite (format, ntracks, division, fp)
|
||||
int format, ntracks, division;
|
||||
FILE *fp;
|
||||
mfwrite (int format, int ntracks, int division, FILE *fp)
|
||||
{
|
||||
int i;
|
||||
void mf_write_track_chunk (), mf_write_header_chunk ();
|
||||
|
||||
if (Mf_putc == NULLFUNC)
|
||||
mferror ("mfmf_write() called without setting Mf_putc");
|
||||
|
|
@ -837,14 +818,10 @@ mfwrite (format, ntracks, division, fp)
|
|||
}
|
||||
|
||||
void
|
||||
mf_write_track_chunk (which_track, fp)
|
||||
int which_track;
|
||||
FILE *fp;
|
||||
mf_write_track_chunk (int which_track, FILE *fp)
|
||||
{
|
||||
unsigned long trkhdr, trklength;
|
||||
long offset, place_marker;
|
||||
void write16bit (), write32bit ();
|
||||
|
||||
|
||||
laststatus = 0;
|
||||
|
||||
|
|
@ -910,11 +887,9 @@ mf_write_track_chunk (which_track, fp)
|
|||
|
||||
|
||||
void
|
||||
mf_write_header_chunk (format, ntracks, division)
|
||||
int format, ntracks, division;
|
||||
mf_write_header_chunk (int format, int ntracks, int division)
|
||||
{
|
||||
unsigned long ident, length;
|
||||
void write16bit (), write32bit ();
|
||||
|
||||
ident = MThd; /* Head chunk identifier */
|
||||
length = 6; /* Chunk length */
|
||||
|
|
@ -948,11 +923,8 @@ mf_write_header_chunk (format, ntracks, division)
|
|||
* size - The length of the meta-event data.
|
||||
*/
|
||||
int
|
||||
mf_write_midi_event (delta_time, type, chan, data, size)
|
||||
unsigned long delta_time;
|
||||
int chan, type;
|
||||
unsigned long size;
|
||||
char *data;
|
||||
mf_write_midi_event (unsigned long delta_time, int type, int chan,
|
||||
char *data, unsigned long size)
|
||||
{
|
||||
int i;
|
||||
unsigned char c;
|
||||
|
|
@ -999,11 +971,9 @@ mf_write_midi_event (delta_time, type, chan, data, size)
|
|||
* data.
|
||||
* size - The length of the meta-event data.
|
||||
*/
|
||||
int
|
||||
mf_write_meta_event (delta_time, type, data, size)
|
||||
unsigned long delta_time;
|
||||
unsigned char *data, type;
|
||||
unsigned long size;
|
||||
int
|
||||
mf_write_meta_event (unsigned long delta_time, unsigned char type,
|
||||
unsigned char *data, unsigned long size)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -1027,9 +997,7 @@ mf_write_meta_event (delta_time, type, data, size)
|
|||
} /* end mf_write_meta_event */
|
||||
|
||||
void
|
||||
mf_write_tempo (delta_time, tempo)
|
||||
unsigned long delta_time;
|
||||
unsigned long tempo;
|
||||
mf_write_tempo (unsigned long delta_time, unsigned long tempo)
|
||||
{
|
||||
/* Write tempo */
|
||||
/* all tempos are written as 120 beats/minute, */
|
||||
|
|
@ -1046,9 +1014,7 @@ mf_write_tempo (delta_time, tempo)
|
|||
}
|
||||
|
||||
void
|
||||
mf_write_seqnum (delta_time, seqnum)
|
||||
unsigned long delta_time;
|
||||
unsigned seqnum;
|
||||
mf_write_seqnum (unsigned long delta_time, unsigned int seqnum)
|
||||
{
|
||||
|
||||
WriteVarLen (delta_time);
|
||||
|
|
@ -1060,10 +1026,7 @@ mf_write_seqnum (delta_time, seqnum)
|
|||
}
|
||||
|
||||
unsigned long
|
||||
mf_sec2ticks (secs, division, tempo)
|
||||
int division;
|
||||
unsigned long tempo;
|
||||
double secs;
|
||||
mf_sec2ticks (double secs, int division, unsigned long tempo)
|
||||
{
|
||||
return (unsigned long) (((secs * 1000.0) / 4.0 * division) / tempo);
|
||||
}
|
||||
|
|
@ -1072,8 +1035,7 @@ mf_sec2ticks (secs, division, tempo)
|
|||
* Write multi-length bytes to MIDI format files
|
||||
*/
|
||||
void
|
||||
WriteVarLen (value)
|
||||
unsigned long value;
|
||||
WriteVarLen (unsigned long value)
|
||||
{
|
||||
unsigned long buffer;
|
||||
|
||||
|
|
@ -1102,10 +1064,7 @@ WriteVarLen (value)
|
|||
*
|
||||
*/
|
||||
double
|
||||
mf_ticks2sec (ticks, division, tempo)
|
||||
int division;
|
||||
unsigned long tempo;
|
||||
unsigned long ticks;
|
||||
mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo)
|
||||
{
|
||||
double smpte_format, smpte_resolution;
|
||||
|
||||
|
|
@ -1133,8 +1092,7 @@ mf_ticks2sec (ticks, division, tempo)
|
|||
*
|
||||
*/
|
||||
void
|
||||
write32bit (data)
|
||||
unsigned long data;
|
||||
write32bit (unsigned long data)
|
||||
{
|
||||
eputc ((unsigned) ((data >> 24) & 0xff));
|
||||
eputc ((unsigned) ((data >> 16) & 0xff));
|
||||
|
|
@ -1143,8 +1101,7 @@ write32bit (data)
|
|||
}
|
||||
|
||||
void
|
||||
write16bit (data)
|
||||
int data;
|
||||
write16bit (int data)
|
||||
{
|
||||
eputc ((unsigned) ((data & 0xff00) >> 8));
|
||||
eputc ((unsigned) (data & 0xff));
|
||||
|
|
@ -1152,8 +1109,7 @@ write16bit (data)
|
|||
|
||||
/* write a single character and abort on error */
|
||||
static int
|
||||
eputc (c)
|
||||
unsigned char c;
|
||||
eputc (unsigned char c)
|
||||
{
|
||||
int return_val;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/* definitions for MIDI file parsing code */
|
||||
extern int (*Mf_getc)();
|
||||
extern void (*Mf_header)();
|
||||
extern void (*Mf_trackstart)();
|
||||
extern void (*Mf_trackend)();
|
||||
extern void (*Mf_noteon)();
|
||||
extern void (*Mf_noteoff)();
|
||||
extern void (*Mf_pressure)();
|
||||
extern void (*Mf_parameter)();
|
||||
extern void (*Mf_pitchbend)();
|
||||
extern void (*Mf_program)();
|
||||
extern void (*Mf_chanpressure)();
|
||||
extern void (*Mf_sysex)();
|
||||
extern void (*Mf_metamisc)();
|
||||
extern void (*Mf_seqspecific)();
|
||||
extern void (*Mf_seqnum)();
|
||||
extern void (*Mf_text)();
|
||||
extern void (*Mf_eot)();
|
||||
extern void (*Mf_timesig)();
|
||||
extern void (*Mf_smpte)();
|
||||
extern void (*Mf_tempo)();
|
||||
extern void (*Mf_keysig)();
|
||||
extern void (*Mf_arbitrary)();
|
||||
extern void (*Mf_error)();
|
||||
extern int (*Mf_getc)(void);
|
||||
extern void (*Mf_error)(char *s);
|
||||
extern void (*Mf_header)(int format, int ntrks, int division);
|
||||
extern void (*Mf_trackstart)(void);
|
||||
extern void (*Mf_trackend)(void);
|
||||
extern void (*Mf_noteon)(int chan, int c1, int c2);
|
||||
extern void (*Mf_noteoff)(int chan, int c1, int c2);
|
||||
extern void (*Mf_pressure)(int chan, int c1, int c2);
|
||||
extern void (*Mf_parameter)(int chan, int c1, int c2);
|
||||
extern void (*Mf_pitchbend)(int chan, int c1, int c2);
|
||||
extern void (*Mf_program)(int chan, int c1);
|
||||
extern void (*Mf_chanpressure)(int chan, int c1);
|
||||
extern void (*Mf_sysex)(int len, char *msg);
|
||||
extern void (*Mf_arbitrary)(int len, char *msg);
|
||||
extern void (*Mf_metamisc)(int type, int len, char *msg);
|
||||
extern void (*Mf_seqnum)(int num);
|
||||
extern void (*Mf_eot)(void);
|
||||
extern void (*Mf_smpte)(char m0, char m1, char m2, char m3, char m4);
|
||||
extern void (*Mf_tempo)(long tempo);
|
||||
extern void (*Mf_timesig)(char m0, char m1, char m2, char m3);
|
||||
extern void (*Mf_keysig)(char m0, char m1);
|
||||
extern void (*Mf_seqspecific)(int len, char *msg);
|
||||
extern void (*Mf_text)(int type, int len, char *msg);
|
||||
extern unsigned long Mf_currtime;
|
||||
extern unsigned long Mf_realtime;
|
||||
extern unsigned long Mf_currtempo;
|
||||
|
|
@ -33,20 +33,23 @@ extern int Mf_file_size;
|
|||
#endif
|
||||
|
||||
/* definitions for MIDI file writing code */
|
||||
extern int (*Mf_putc)();
|
||||
extern int (*Mf_writetrack)();
|
||||
extern int (*Mf_writetempotrack)();
|
||||
extern int (*Mf_putc)(unsigned char c);
|
||||
extern int (*Mf_writetrack)(int track);
|
||||
extern int (*Mf_writetempotrack)(void);
|
||||
|
||||
extern void midifile();
|
||||
extern unsigned long mf_sec2ticks();
|
||||
extern void mfwrite();
|
||||
extern int mf_write_meta_event();
|
||||
extern void midifile(void);
|
||||
extern unsigned long mf_sec2ticks(double secs, int division,
|
||||
unsigned long tempo);
|
||||
extern void mfwrite(int format, int ntracks, int division, FILE *fp);
|
||||
extern int mf_write_meta_event(unsigned long delta_time, unsigned char type,
|
||||
unsigned char *data, unsigned long size);
|
||||
extern int mf_write_midi_event(unsigned long delta_time, int type,
|
||||
int chan, char *data, unsigned long size);
|
||||
extern double mf_ticks2sec(unsigned long ticks,int division,unsigned long tempo);
|
||||
extern void mf_write_tempo();
|
||||
extern void mf_write_seqnum();
|
||||
extern void mfread();
|
||||
extern double mf_ticks2sec(unsigned long ticks, int division,
|
||||
unsigned long tempo);
|
||||
extern void mf_write_tempo(unsigned long delta_time, unsigned long tempo);
|
||||
extern void mf_write_seqnum(unsigned long delta_time, unsigned int seqnum);
|
||||
extern void mfread(void);
|
||||
extern void mferror(char *s);
|
||||
|
||||
#ifndef NO_LC_DEFINES
|
||||
|
|
|
|||
|
|
@ -45,10 +45,11 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../include/asoundlib.h"
|
||||
|
||||
#include "midifile.h" /* SMF library header */
|
||||
#include "midifile.c" /* SMF library code */
|
||||
|
||||
#include "../include/asoundlib.h"
|
||||
|
||||
/* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */
|
||||
static int use_realtime = 0;
|
||||
|
|
@ -242,14 +243,14 @@ static void alsa_stop_timer(void)
|
|||
}
|
||||
|
||||
/* change the tempo */
|
||||
static void do_tempo(int us)
|
||||
static void do_tempo(long us)
|
||||
{
|
||||
snd_seq_event_t ev;
|
||||
|
||||
if (verbose >= VERB_MUCH) {
|
||||
double bpm;
|
||||
bpm = 60.0E6 / (double) us;
|
||||
printf("Tempo %d us/beat, %.2f bpm\n", us, bpm);
|
||||
printf("Tempo %ld us/beat, %.2f bpm\n", us, bpm);
|
||||
}
|
||||
|
||||
/* store the new tempo and timestamp of the tempo change */
|
||||
|
|
|
|||
187
test/seq-ump-example.c
Normal file
187
test/seq-ump-example.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
// An example program to create a virtual UMP Endpoint
|
||||
//
|
||||
// A client simply reads each UMP packet and sends to subscribers
|
||||
// while the note on/off velocity is halved
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/ump_msg.h>
|
||||
|
||||
/* make the note on/off velocity half for MIDI1 CVM */
|
||||
static void midi1_half_note_velocity(snd_seq_ump_event_t *ev)
|
||||
{
|
||||
snd_ump_msg_midi1_t *midi1 = (snd_ump_msg_midi1_t *)ev->ump;
|
||||
|
||||
switch (snd_ump_msg_status(ev->ump)) {
|
||||
case SND_UMP_MSG_NOTE_OFF:
|
||||
case SND_UMP_MSG_NOTE_ON:
|
||||
midi1->note_on.velocity >>= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* make the note on/off velocity half for MIDI2 CVM */
|
||||
static void midi2_half_note_velocity(snd_seq_ump_event_t *ev)
|
||||
{
|
||||
snd_ump_msg_midi2_t *midi2 = (snd_ump_msg_midi2_t *)ev->ump;
|
||||
|
||||
switch (snd_ump_msg_status(ev->ump)) {
|
||||
case SND_UMP_MSG_NOTE_OFF:
|
||||
case SND_UMP_MSG_NOTE_ON:
|
||||
midi2->note_on.velocity >>= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("seq-ump-example: Create a virtual UMP Endpoint and Blocks\n"
|
||||
"\n"
|
||||
"Usage: seq-ump-example [OPTIONS]\n"
|
||||
"\n"
|
||||
"-n,--num-blocks blocks Number of blocks (groups) to create\n"
|
||||
"-m,--midi-version version MIDI protocol version (1 or 2)\n"
|
||||
"-N--name UMP Endpoint name string\n"
|
||||
"-P,--product name UMP Product ID string\n"
|
||||
"-M,--manufacturer id UMP Manufacturer ID value (24bit)\n"
|
||||
"-F,--family id UMP Family ID value (16bit)\n"
|
||||
"-O,--model id UMP Model ID value (16bit)\n"
|
||||
"-R,--sw-revision id UMP Software Revision ID (32bit)\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int midi_version = 2;
|
||||
int num_blocks = 1;
|
||||
const char *name = "ACMESynth";
|
||||
const char *product = "Halfmoon";
|
||||
unsigned int manufacturer = 0x123456;
|
||||
unsigned int family = 0x1234;
|
||||
unsigned int model = 0xabcd;
|
||||
unsigned int sw_revision = 0x12345678;
|
||||
snd_seq_t *seq;
|
||||
snd_ump_endpoint_info_t *ep;
|
||||
snd_ump_block_info_t *blk;
|
||||
snd_seq_ump_event_t *ev;
|
||||
int i, c, err;
|
||||
unsigned char tmp[4];
|
||||
|
||||
static const struct option long_option[] = {
|
||||
{"num-blocks", required_argument, 0, 'n'},
|
||||
{"midi-version", required_argument, 0, 'm'},
|
||||
{"name", required_argument, 0, 'N'},
|
||||
{"product", required_argument, 0, 'P'},
|
||||
{"manufacturer", required_argument, 0, 'M'},
|
||||
{"family", required_argument, 0, 'F'},
|
||||
{"model", required_argument, 0, 'O'},
|
||||
{"sw-revision", required_argument, 0, 'R'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "n:m:N:P:M:F:O:R:",
|
||||
long_option, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
num_blocks = atoi(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
midi_version = atoi(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
name = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
product = optarg;
|
||||
break;
|
||||
case 'M':
|
||||
manufacturer = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'F':
|
||||
family = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'O':
|
||||
model = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'R':
|
||||
sw_revision = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to open sequencer: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_ump_endpoint_info_alloca(&ep);
|
||||
snd_ump_endpoint_info_set_name(ep, name);
|
||||
snd_ump_endpoint_info_set_product_id(ep, product);
|
||||
if (midi_version == 1) {
|
||||
snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
|
||||
snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
|
||||
} else {
|
||||
snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
|
||||
snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
|
||||
}
|
||||
snd_ump_endpoint_info_set_num_blocks(ep, num_blocks);
|
||||
snd_ump_endpoint_info_set_manufacturer_id(ep, manufacturer);
|
||||
snd_ump_endpoint_info_set_family_id(ep, family);
|
||||
snd_ump_endpoint_info_set_model_id(ep, model);
|
||||
for (i = 0; i < 4; i++)
|
||||
tmp[i] = (sw_revision >> ((3 - i) * 8)) & 0xff;
|
||||
snd_ump_endpoint_info_set_sw_revision(ep, tmp);
|
||||
|
||||
err = snd_seq_create_ump_endpoint(seq, ep, num_blocks);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to set UMP EP info: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_ump_block_info_alloca(&blk);
|
||||
|
||||
for (i = 0; i < num_blocks; i++) {
|
||||
char blkname[32];
|
||||
|
||||
sprintf(blkname, "Filter %d", i + 1);
|
||||
snd_ump_block_info_set_name(blk, blkname);
|
||||
snd_ump_block_info_set_direction(blk, SND_UMP_DIR_BIDIRECTION);
|
||||
snd_ump_block_info_set_first_group(blk, i);
|
||||
snd_ump_block_info_set_num_groups(blk, 1);
|
||||
snd_ump_block_info_set_ui_hint(blk, SND_UMP_BLOCK_UI_HINT_BOTH);
|
||||
|
||||
err = snd_seq_create_ump_block(seq, i, blk);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to set UMP block info %d: %d\n",
|
||||
i, err);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* halve the incoming note-on / off velocity and pass through
|
||||
* to subscribers
|
||||
*/
|
||||
while (snd_seq_ump_event_input(seq, &ev) >= 0) {
|
||||
if (!snd_seq_ev_is_ump(ev))
|
||||
continue;
|
||||
switch (snd_ump_msg_type(ev->ump)) {
|
||||
case SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
|
||||
midi1_half_note_velocity(ev);
|
||||
break;
|
||||
case SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
|
||||
midi2_half_note_velocity(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
snd_seq_ev_set_subs(ev);
|
||||
snd_seq_ev_set_direct(ev);
|
||||
snd_seq_ump_event_output(seq, ev);
|
||||
snd_seq_drain_output(seq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
147
test/umpinfo.c
Normal file
147
test/umpinfo.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// Inquire UMP Endpoint and Block info in various APIs
|
||||
|
||||
#include <stdio.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
enum { UNKNOWN, SEQ, RAWMIDI, CTL };
|
||||
static int mode = UNKNOWN;
|
||||
|
||||
static snd_seq_t *seq;
|
||||
static int client;
|
||||
static snd_ump_t *ump;
|
||||
static snd_ctl_t *ctl;
|
||||
|
||||
static int get_ump_endpoint_info(snd_ump_endpoint_info_t *ep)
|
||||
{
|
||||
switch (mode) {
|
||||
case SEQ:
|
||||
return snd_seq_get_ump_endpoint_info(seq, client, ep);
|
||||
case RAWMIDI:
|
||||
return snd_ump_endpoint_info(ump, ep);
|
||||
case CTL:
|
||||
return snd_ctl_ump_endpoint_info(ctl, ep);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_ump_block_info(int blk, snd_ump_block_info_t *bp)
|
||||
{
|
||||
switch (mode) {
|
||||
case SEQ:
|
||||
return snd_seq_get_ump_block_info(seq, client, blk, bp);
|
||||
case RAWMIDI:
|
||||
snd_ump_block_info_set_block_id(bp, blk);
|
||||
return snd_ump_block_info(ump, bp);
|
||||
case CTL:
|
||||
snd_ump_block_info_set_block_id(bp, blk);
|
||||
return snd_ctl_ump_block_info(ctl, bp);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("umpinfo: inquire UMP Endpoint and Block info\n"
|
||||
" umpinfo -c target inquiry via control API\n"
|
||||
" umpinfo -m target inquiry via UMP rawmidi API\n"
|
||||
" umpinfo -s client inquiry via sequencer API\n"
|
||||
" target = hw:0, etc\n"
|
||||
" client = sequencer client number\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *target = "hw:0";
|
||||
snd_ump_endpoint_info_t *ep;
|
||||
snd_ump_block_info_t *blk;
|
||||
const unsigned char *s;
|
||||
int c, i, num_blks;
|
||||
|
||||
while ((c = getopt(argc, argv, "s:m:c:h")) >= 0) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
mode = SEQ;
|
||||
client = atoi(target);
|
||||
break;
|
||||
case 'm':
|
||||
mode = RAWMIDI;
|
||||
target = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
mode = CTL;
|
||||
target = optarg;
|
||||
break;
|
||||
default:
|
||||
help();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case SEQ:
|
||||
if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0)) {
|
||||
fprintf(stderr, "failed to open sequencer\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case RAWMIDI:
|
||||
if (snd_ump_open(&ump, NULL, target, 0)) {
|
||||
fprintf(stderr, "failed to open UMP rawmidi\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case CTL:
|
||||
if (snd_ctl_open(&ctl, target, 0)) {
|
||||
fprintf(stderr, "failed to open control\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
help();
|
||||
break;
|
||||
}
|
||||
|
||||
snd_ump_endpoint_info_alloca(&ep);
|
||||
snd_ump_block_info_alloca(&blk);
|
||||
|
||||
if (get_ump_endpoint_info(ep)) {
|
||||
fprintf(stderr, "failed to get UMP EP info\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Name: %s\n", snd_ump_endpoint_info_get_name(ep));
|
||||
printf("Product ID: %s\n", snd_ump_endpoint_info_get_product_id(ep));
|
||||
printf("Flags: 0x%x\n", snd_ump_endpoint_info_get_flags(ep));
|
||||
printf("Protocol Caps: 0x%x\n", snd_ump_endpoint_info_get_protocol_caps(ep));
|
||||
printf("Protocol: 0x%x\n", snd_ump_endpoint_info_get_protocol(ep));
|
||||
printf("Num Blocks: %d\n", snd_ump_endpoint_info_get_num_blocks(ep));
|
||||
printf("Version: 0x%x\n", snd_ump_endpoint_info_get_version(ep));
|
||||
printf("Manufacturer ID: 0x%x\n", snd_ump_endpoint_info_get_manufacturer_id(ep));
|
||||
printf("Family ID: 0x%x\n", snd_ump_endpoint_info_get_family_id(ep));
|
||||
printf("Model ID: 0x%x\n", snd_ump_endpoint_info_get_model_id(ep));
|
||||
s = snd_ump_endpoint_info_get_sw_revision(ep);
|
||||
printf("SW Revision: %02x:%02x:%02x:%02x\n", s[0], s[1], s[2], s[3]);
|
||||
num_blks = snd_ump_endpoint_info_get_num_blocks(ep);
|
||||
for (i = 0; i < num_blks; i++) {
|
||||
if (get_ump_block_info(i, blk)) {
|
||||
fprintf(stderr, "failed to get UMP Block info for %d\n", i);
|
||||
continue;
|
||||
}
|
||||
printf("\n");
|
||||
printf("Block ID: %d\n", snd_ump_block_info_get_block_id(blk));
|
||||
printf("Name: %s\n", snd_ump_block_info_get_name(blk));
|
||||
printf("Active: %d\n", snd_ump_block_info_get_active(blk));
|
||||
printf("Flags: 0x%x\n", snd_ump_block_info_get_flags(blk));
|
||||
printf("Direction: %d\n", snd_ump_block_info_get_direction(blk));
|
||||
printf("First Group: %d\n", snd_ump_block_info_get_first_group(blk));
|
||||
printf("Num Groups: %d\n", snd_ump_block_info_get_num_groups(blk));
|
||||
printf("MIDI-CI Version: %d\n", snd_ump_block_info_get_midi_ci_version(blk));
|
||||
printf("Sysex8 Streams: %d\n", snd_ump_block_info_get_sysex8_streams(blk));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ if INSTALL_M4
|
|||
aclocaldir=$(datadir)/aclocal
|
||||
aclocal_DATA=alsa.m4
|
||||
endif
|
||||
EXTRA_DIST=alsa.m4 buildrpm alsa.pc.in
|
||||
EXTRA_DIST=alsa.m4 buildrpm alsa.pc.in alsa-topology.pc.in
|
||||
|
||||
alsapkgconfdir = @ALSA_PKGCONF_DIR@
|
||||
pkgconfigdir = $(alsapkgconfdir)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue