mirror of https://github.com/ericonr/sndio.git
Compare commits
48 Commits
7a03da2848
...
c4b354abd7
Author | SHA1 | Date |
---|---|---|
Alexandre Ratchov | c4b354abd7 | |
Alexandre Ratchov | aac840d9f9 | |
Alexandre Ratchov | 4d63a3b185 | |
Alexandre Ratchov | 1f42a21368 | |
Alexandre Ratchov | 23e9ebebc4 | |
Alexandre Ratchov | fde5ad8a68 | |
Alexandre Ratchov | 0cb3defc3c | |
Alexandre Ratchov | 12b31d021a | |
Alexandre Ratchov | e450bab99e | |
Alexandre Ratchov | a26f7fdf36 | |
Alexandre Ratchov | 90684ad458 | |
Alexandre Ratchov | 9a5092b08e | |
Alexandre Ratchov | 5a20439ec8 | |
Alexandre Ratchov | ce7e998772 | |
Alexandre Ratchov | 1649f75532 | |
Alexandre Ratchov | d6a1624f29 | |
Alexandre Ratchov | f712cdb11b | |
Alexandre Ratchov | 6869540f3b | |
Alexandre Ratchov | 302865ddd8 | |
Alexandre Ratchov | 5451c3c55e | |
Alexandre Ratchov | ada702087d | |
Alexandre Ratchov | bb27629080 | |
Alexandre Ratchov | 0adedb2a89 | |
Alexandre Ratchov | a6a6dcb57c | |
Alexandre Ratchov | e5766cbfc0 | |
Alexandre Ratchov | 350db6ce41 | |
Alexandre Ratchov | 7534418e78 | |
Alexandre Ratchov | a78ec25e07 | |
Alexandre Ratchov | 1e1589d70e | |
Alexandre Ratchov | e891595ec7 | |
Alexandre Ratchov | 8e99cca36c | |
Alexandre Ratchov | 4710960bbe | |
Alexandre Ratchov | 8bb6267fdb | |
Michael Forney | 7551d499a8 | |
Alexandre Ratchov | ae7637d044 | |
Alexandre Ratchov | 2cd5b8e0ab | |
Alexandre Ratchov | ea692625ea | |
Alexandre Ratchov | 6f741dab61 | |
Alexandre Ratchov | fd4c58aae7 | |
Alexandre Ratchov | 63d4639f9a | |
Alexandre Ratchov | ae76a1f941 | |
Alexandre Ratchov | ac7ddc5301 | |
Alexandre Ratchov | b1c2df5d9c | |
Alexandre Ratchov | 21580f56b5 | |
Alexandre Ratchov | 2996dcdc03 | |
Alexandre Ratchov | 40cdc42e22 | |
Alexandre Ratchov | d1c4d40cb9 | |
Alexandre Ratchov | 62bc69d71c |
|
@ -31,6 +31,7 @@ distclean: clean
|
|||
rm -f \
|
||||
Makefile aucat/Makefile midicat/Makefile sndiod/Makefile \
|
||||
libsndio/Makefile \
|
||||
libsndio/sndio.pc \
|
||||
sndioctl/Makefile \
|
||||
examples/Makefile \
|
||||
contrib/init.d.sndiod \
|
||||
|
|
|
@ -131,28 +131,28 @@ struct au_hdr {
|
|||
/* followed by optional desc[] continuation */
|
||||
};
|
||||
|
||||
char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
|
||||
char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
|
||||
char wav_id_data[4] = {'d', 'a', 't', 'a'};
|
||||
char wav_id_fmt[4] = {'f', 'm', 't', ' '};
|
||||
char wav_guid[14] = {
|
||||
const char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
|
||||
const char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
|
||||
const char wav_id_data[4] = {'d', 'a', 't', 'a'};
|
||||
const char wav_id_fmt[4] = {'f', 'm', 't', ' '};
|
||||
const char wav_guid[14] = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x80, 0x00,
|
||||
0x00, 0xAA, 0x00, 0x38,
|
||||
0x9B, 0x71
|
||||
};
|
||||
|
||||
char aiff_id_form[4] = {'F', 'O', 'R', 'M'};
|
||||
char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'};
|
||||
char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'};
|
||||
char aiff_id_data[4] = {'S', 'S', 'N', 'D'};
|
||||
char aiff_id_comm[4] = {'C', 'O', 'M', 'M'};
|
||||
char aiff_id_none[4] = {'N', 'O', 'N', 'E'};
|
||||
char aiff_id_fl32[4] = {'f', 'l', '3', '2'};
|
||||
char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'};
|
||||
char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'};
|
||||
const char aiff_id_form[4] = {'F', 'O', 'R', 'M'};
|
||||
const char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'};
|
||||
const char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'};
|
||||
const char aiff_id_data[4] = {'S', 'S', 'N', 'D'};
|
||||
const char aiff_id_comm[4] = {'C', 'O', 'M', 'M'};
|
||||
const char aiff_id_none[4] = {'N', 'O', 'N', 'E'};
|
||||
const char aiff_id_fl32[4] = {'f', 'l', '3', '2'};
|
||||
const char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'};
|
||||
const char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'};
|
||||
|
||||
char au_id[4] = {'.', 's', 'n', 'd'};
|
||||
const char au_id[4] = {'.', 's', 'n', 'd'};
|
||||
|
||||
static inline unsigned int
|
||||
le16_get(le16_t *p)
|
||||
|
|
|
@ -132,8 +132,8 @@ struct slot *slot_list = NULL;
|
|||
/*
|
||||
* length of voice and common MIDI messages (status byte included)
|
||||
*/
|
||||
unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
|
||||
unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
|
||||
const unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
|
||||
const unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
|
||||
|
||||
char usagestr[] = "usage: aucat [-dn] [-b size] "
|
||||
"[-c min:max] [-e enc] [-f device] [-g position]\n\t"
|
||||
|
|
139
aucat/dsp.c
139
aucat/dsp.c
|
@ -18,7 +18,7 @@
|
|||
#include "dsp.h"
|
||||
#include "utils.h"
|
||||
|
||||
int aparams_ctltovol[128] = {
|
||||
const int aparams_ctltovol[128] = {
|
||||
0,
|
||||
256, 266, 276, 287, 299, 310, 323, 335,
|
||||
348, 362, 376, 391, 406, 422, 439, 456,
|
||||
|
@ -38,7 +38,7 @@ int aparams_ctltovol[128] = {
|
|||
26008, 27029, 28090, 29193, 30339, 31530, 32768
|
||||
};
|
||||
|
||||
short dec_ulawmap[256] = {
|
||||
const short dec_ulawmap[256] = {
|
||||
-32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
|
||||
-23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
|
||||
-15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
|
||||
|
@ -73,7 +73,7 @@ short dec_ulawmap[256] = {
|
|||
56, 48, 40, 32, 24, 16, 8, 0
|
||||
};
|
||||
|
||||
short dec_alawmap[256] = {
|
||||
const short dec_alawmap[256] = {
|
||||
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
|
||||
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
|
||||
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
|
||||
|
@ -108,6 +108,75 @@ short dec_alawmap[256] = {
|
|||
944, 912, 1008, 976, 816, 784, 880, 848
|
||||
};
|
||||
|
||||
const int resamp_filt[RESAMP_LENGTH / RESAMP_STEP + 1] = {
|
||||
0, 0, 3, 9, 22, 42, 73, 116,
|
||||
174, 248, 341, 454, 589, 749, 934, 1148,
|
||||
1392, 1666, 1974, 2316, 2693, 3107, 3560, 4051,
|
||||
4582, 5154, 5766, 6420, 7116, 7853, 8632, 9451,
|
||||
10311, 11210, 12148, 13123, 14133, 15178, 16253, 17359,
|
||||
18491, 19647, 20824, 22018, 23226, 24443, 25665, 26888,
|
||||
28106, 29315, 30509, 31681, 32826, 33938, 35009, 36033,
|
||||
37001, 37908, 38744, 39502, 40174, 40750, 41223, 41582,
|
||||
41819, 41925, 41890, 41704, 41358, 40842, 40147, 39261,
|
||||
38176, 36881, 35366, 33623, 31641, 29411, 26923, 24169,
|
||||
21140, 17827, 14222, 10317, 6105, 1580, -3267, -8440,
|
||||
-13944, -19785, -25967, -32492, -39364, -46584, -54153, -62072,
|
||||
-70339, -78953, -87911, -97209, -106843, -116806, -127092, -137692,
|
||||
-148596, -159795, -171276, -183025, -195029, -207271, -219735, -232401,
|
||||
-245249, -258259, -271407, -284670, -298021, -311434, -324880, -338329,
|
||||
-351750, -365111, -378378, -391515, -404485, -417252, -429775, -442015,
|
||||
-453930, -465477, -476613, -487294, -497472, -507102, -516137, -524527,
|
||||
-532225, -539181, -545344, -550664, -555090, -558571, -561055, -562490,
|
||||
-562826, -562010, -559990, -556717, -552139, -546205, -538866, -530074,
|
||||
-519779, -507936, -494496, -479416, -462652, -444160, -423901, -401835,
|
||||
-377923, -352132, -324425, -294772, -263143, -229509, -193847, -156134,
|
||||
-116348, -74474, -30494, 15601, 63822, 114174, 166661, 221283,
|
||||
278037, 336916, 397911, 461009, 526194, 593446, 662741, 734054,
|
||||
807354, 882608, 959779, 1038826, 1119706, 1202370, 1286768, 1372846,
|
||||
1460546, 1549808, 1640566, 1732753, 1826299, 1921130, 2017169, 2114336,
|
||||
2212550, 2311723, 2411770, 2512598, 2614116, 2716228, 2818836, 2921841,
|
||||
3025142, 3128636, 3232218, 3335782, 3439219, 3542423, 3645282, 3747687,
|
||||
3849526, 3950687, 4051059, 4150530, 4248987, 4346320, 4442415, 4537163,
|
||||
4630453, 4722177, 4812225, 4900493, 4986873, 5071263, 5153561, 5233668,
|
||||
5311485, 5386917, 5459872, 5530259, 5597992, 5662986, 5725160, 5784436,
|
||||
5840739, 5893999, 5944148, 5991122, 6034862, 6075313, 6112422, 6146142,
|
||||
6176430, 6203247, 6226559, 6246335, 6262551, 6275185, 6284220, 6289647,
|
||||
6291456, 6289647, 6284220, 6275185, 6262551, 6246335, 6226559, 6203247,
|
||||
6176430, 6146142, 6112422, 6075313, 6034862, 5991122, 5944148, 5893999,
|
||||
5840739, 5784436, 5725160, 5662986, 5597992, 5530259, 5459872, 5386917,
|
||||
5311485, 5233668, 5153561, 5071263, 4986873, 4900493, 4812225, 4722177,
|
||||
4630453, 4537163, 4442415, 4346320, 4248987, 4150530, 4051059, 3950687,
|
||||
3849526, 3747687, 3645282, 3542423, 3439219, 3335782, 3232218, 3128636,
|
||||
3025142, 2921841, 2818836, 2716228, 2614116, 2512598, 2411770, 2311723,
|
||||
2212550, 2114336, 2017169, 1921130, 1826299, 1732753, 1640566, 1549808,
|
||||
1460546, 1372846, 1286768, 1202370, 1119706, 1038826, 959779, 882608,
|
||||
807354, 734054, 662741, 593446, 526194, 461009, 397911, 336916,
|
||||
278037, 221283, 166661, 114174, 63822, 15601, -30494, -74474,
|
||||
-116348, -156134, -193847, -229509, -263143, -294772, -324425, -352132,
|
||||
-377923, -401835, -423901, -444160, -462652, -479416, -494496, -507936,
|
||||
-519779, -530074, -538866, -546205, -552139, -556717, -559990, -562010,
|
||||
-562826, -562490, -561055, -558571, -555090, -550664, -545344, -539181,
|
||||
-532225, -524527, -516137, -507102, -497472, -487294, -476613, -465477,
|
||||
-453930, -442015, -429775, -417252, -404485, -391515, -378378, -365111,
|
||||
-351750, -338329, -324880, -311434, -298021, -284670, -271407, -258259,
|
||||
-245249, -232401, -219735, -207271, -195029, -183025, -171276, -159795,
|
||||
-148596, -137692, -127092, -116806, -106843, -97209, -87911, -78953,
|
||||
-70339, -62072, -54153, -46584, -39364, -32492, -25967, -19785,
|
||||
-13944, -8440, -3267, 1580, 6105, 10317, 14222, 17827,
|
||||
21140, 24169, 26923, 29411, 31641, 33623, 35366, 36881,
|
||||
38176, 39261, 40147, 40842, 41358, 41704, 41890, 41925,
|
||||
41819, 41582, 41223, 40750, 40174, 39502, 38744, 37908,
|
||||
37001, 36033, 35009, 33938, 32826, 31681, 30509, 29315,
|
||||
28106, 26888, 25665, 24443, 23226, 22018, 20824, 19647,
|
||||
18491, 17359, 16253, 15178, 14133, 13123, 12148, 11210,
|
||||
10311, 9451, 8632, 7853, 7116, 6420, 5766, 5154,
|
||||
4582, 4051, 3560, 3107, 2693, 2316, 1974, 1666,
|
||||
1392, 1148, 934, 749, 589, 454, 341, 248,
|
||||
174, 116, 73, 42, 22, 9, 3, 0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Generate a string corresponding to the encoding in par,
|
||||
* return the length of the resulting string.
|
||||
|
@ -262,7 +331,9 @@ aparams_log(struct aparams *par)
|
|||
int
|
||||
aparams_native(struct aparams *par)
|
||||
{
|
||||
return par->bps == sizeof(adata_t) && par->bits == ADATA_BITS &&
|
||||
return par->sig &&
|
||||
par->bps == sizeof(adata_t) &&
|
||||
par->bits == ADATA_BITS &&
|
||||
(par->bps == 1 || par->le == ADATA_LE) &&
|
||||
(par->bits == par->bps * 8 || !par->msb);
|
||||
}
|
||||
|
@ -307,8 +378,10 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt)
|
|||
unsigned int iblksz;
|
||||
unsigned int ofr;
|
||||
unsigned int c;
|
||||
int64_t f[NCHAN_MAX];
|
||||
adata_t *ctxbuf, *ctx;
|
||||
unsigned int ctx_start;
|
||||
int q, qi, qf, n;
|
||||
|
||||
/*
|
||||
* Partially copy structures into local variables, to avoid
|
||||
|
@ -344,7 +417,7 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt)
|
|||
if (diff >= oblksz) {
|
||||
if (ifr == 0)
|
||||
break;
|
||||
ctx_start ^= 1;
|
||||
ctx_start = (ctx_start - 1) & (RESAMP_NCTX - 1);
|
||||
ctx = ctxbuf + ctx_start;
|
||||
for (c = nch; c > 0; c--) {
|
||||
*ctx = *idata++;
|
||||
|
@ -355,13 +428,48 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt)
|
|||
} else {
|
||||
if (ofr == 0)
|
||||
break;
|
||||
ctx = ctxbuf;
|
||||
for (c = nch; c > 0; c--) {
|
||||
s = ctx[ctx_start ^ 1];
|
||||
ds = ctx[ctx_start] - s;
|
||||
ctx += RESAMP_NCTX;
|
||||
*odata++ = s + ADATA_MULDIV(ds, diff, oblksz);
|
||||
|
||||
for (c = 0; c < nch; c++)
|
||||
f[c] = 0;
|
||||
|
||||
q = diff * p->filt_step;
|
||||
n = ctx_start;
|
||||
|
||||
while (q < RESAMP_LENGTH) {
|
||||
qi = q >> RESAMP_STEP_BITS;
|
||||
qf = q & (RESAMP_STEP - 1);
|
||||
s = resamp_filt[qi];
|
||||
ds = resamp_filt[qi + 1] - s;
|
||||
s += (int64_t)qf * ds >> RESAMP_STEP_BITS;
|
||||
ctx = ctxbuf;
|
||||
for (c = 0; c < nch; c++) {
|
||||
f[c] += (int64_t)ctx[n] * s;
|
||||
ctx += RESAMP_NCTX;
|
||||
}
|
||||
q += p->filt_cutoff;
|
||||
n = (n + 1) & (RESAMP_NCTX - 1);
|
||||
}
|
||||
|
||||
for (c = 0; c < nch; c++) {
|
||||
s = f[c] >> RESAMP_BITS;
|
||||
s = (int64_t)s * p->filt_cutoff >> RESAMP_BITS;
|
||||
#if ADATA_BITS == 16
|
||||
/*
|
||||
* In 16-bit mode, we've no room for filter
|
||||
* overshoots, so we need to clip the signal
|
||||
* to avoid 16-bit integers to wrap around.
|
||||
* In 24-bit mode, samples may exceed the
|
||||
* [-1:1] range. Later, cmap_add() will clip
|
||||
* them, so no need to clip them here as well.
|
||||
*/
|
||||
if (s >= ADATA_UNIT)
|
||||
s = ADATA_UNIT - 1;
|
||||
else if (s < -ADATA_UNIT)
|
||||
s = -ADATA_UNIT;
|
||||
#endif
|
||||
*odata++ = s;
|
||||
}
|
||||
|
||||
diff += iblksz;
|
||||
ofr--;
|
||||
}
|
||||
|
@ -427,6 +535,13 @@ resamp_init(struct resamp *p, unsigned int iblksz,
|
|||
p->nch = nch;
|
||||
p->ctx_start = 0;
|
||||
memset(p->ctx, 0, sizeof(p->ctx));
|
||||
if (p->iblksz < p->oblksz) {
|
||||
p->filt_cutoff = RESAMP_UNIT;
|
||||
p->filt_step = RESAMP_UNIT / p->oblksz;
|
||||
} else {
|
||||
p->filt_cutoff = (int64_t)RESAMP_UNIT * p->oblksz / p->iblksz;
|
||||
p->filt_step = RESAMP_UNIT / p->iblksz;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 3) {
|
||||
log_puts("resamp: ");
|
||||
|
@ -727,7 +842,7 @@ dec_do_ulaw(struct conv *p, unsigned char *in,
|
|||
unsigned int f;
|
||||
unsigned char *idata;
|
||||
adata_t *odata;
|
||||
short *map;
|
||||
const short *map;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
|
|
71
aucat/dsp.h
71
aucat/dsp.h
|
@ -40,57 +40,43 @@ typedef short adata_t;
|
|||
|
||||
#elif ADATA_BITS == 24
|
||||
|
||||
#if defined(__i386__) && defined(__GNUC__)
|
||||
|
||||
static inline int
|
||||
fp24_mul(int x, int a)
|
||||
{
|
||||
int res;
|
||||
|
||||
asm volatile (
|
||||
"imull %2\n\t"
|
||||
"shrdl $23, %%edx, %%eax\n\t"
|
||||
: "=a" (res)
|
||||
: "a" (x), "r" (a)
|
||||
: "%edx"
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
fp24_muldiv(int x, int a, int b)
|
||||
{
|
||||
int res;
|
||||
|
||||
asm volatile (
|
||||
"imull %2\n\t"
|
||||
"idivl %3\n\t"
|
||||
: "=a" (res)
|
||||
: "a" (x), "d" (a), "r" (b)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define ADATA_MUL(x,y) fp24_mul(x, y)
|
||||
#define ADATA_MULDIV(x,y,z) fp24_muldiv(x, y, z);
|
||||
|
||||
#elif defined(__amd64__) || defined(__sparc64__)
|
||||
|
||||
#define ADATA_MUL(x,y) \
|
||||
((int)(((long long)(x) * (long long)(y)) >> (ADATA_BITS - 1)))
|
||||
#define ADATA_MULDIV(x,y,z) \
|
||||
((int)((long long)(x) * (long long)(y) / (long long)(z)))
|
||||
|
||||
#else
|
||||
#error "no 24-bit code for this architecture"
|
||||
#endif
|
||||
|
||||
typedef int adata_t;
|
||||
|
||||
#else
|
||||
#error "only 16-bit and 24-bit precisions are supported"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The FIR is sampled and stored in a table of fixed-point numbers
|
||||
* with 23 fractional bits. For convenience, we use the same fixed-point
|
||||
* numbers to represent time and to walk through the table.
|
||||
*/
|
||||
#define RESAMP_BITS 23
|
||||
#define RESAMP_UNIT (1 << RESAMP_BITS)
|
||||
|
||||
/*
|
||||
* Filter window length (the time unit is RESAMP_UNIT)
|
||||
*/
|
||||
#define RESAMP_LENGTH (8 * RESAMP_UNIT)
|
||||
|
||||
/*
|
||||
* Time between samples of the FIR (the time unit is RESAMP_UNIT)
|
||||
*/
|
||||
#define RESAMP_STEP_BITS (RESAMP_BITS - 6)
|
||||
#define RESAMP_STEP (1 << RESAMP_STEP_BITS)
|
||||
|
||||
/*
|
||||
* Maximum downsample/upsample ratio we support, must be a power of two.
|
||||
* The ratio between the max and the min sample rates is 192kHz / 4kHz = 48,
|
||||
* so we can use 64
|
||||
*/
|
||||
#define RESAMP_RATIO 64
|
||||
|
||||
/*
|
||||
* Maximum size of the encording string (the longest possible
|
||||
* encoding is ``s24le3msb'').
|
||||
|
@ -111,9 +97,10 @@ struct aparams {
|
|||
};
|
||||
|
||||
struct resamp {
|
||||
#define RESAMP_NCTX 2
|
||||
#define RESAMP_NCTX (RESAMP_LENGTH / RESAMP_UNIT * RESAMP_RATIO)
|
||||
unsigned int ctx_start;
|
||||
adata_t ctx[NCHAN_MAX * RESAMP_NCTX];
|
||||
int filt_cutoff, filt_step;
|
||||
unsigned int iblksz, oblksz;
|
||||
int diff;
|
||||
int nch;
|
||||
|
@ -138,7 +125,7 @@ struct cmap {
|
|||
};
|
||||
|
||||
#define MIDI_TO_ADATA(m) (aparams_ctltovol[m] << (ADATA_BITS - 16))
|
||||
extern int aparams_ctltovol[128];
|
||||
extern const int aparams_ctltovol[128];
|
||||
|
||||
void aparams_init(struct aparams *);
|
||||
void aparams_log(struct aparams *);
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
help() {
|
||||
cat << END
|
||||
Usage: configure [options]
|
||||
--prefix=DIR set install prefix to DIR [$prefix]
|
||||
--bindir=DIR install executables in DIR [\$prefix/bin]
|
||||
--prefix=DIR set arch independent install prefix to DIR [$prefix]
|
||||
--exec-prefix=DIR set arch dependent install prefix to DIR [\$prefix]
|
||||
--bindir=DIR install executables in DIR [\$exec_prefix/bin]
|
||||
--datadir=DIR install read-only data in DIR [\$prefix/share]
|
||||
--includedir=DIR install header files in DIR [\$prefix/include]
|
||||
--libdir=DIR install libraries in DIR [\$prefix/lib]
|
||||
--libdir=DIR install libraries in DIR [\$exec_prefix/lib]
|
||||
--pkgconfdir=DIR install pkg-config file in DIR [\$libdir/pkgconfig]
|
||||
--mandir=DIR install man pages in DIR [\$prefix/man]
|
||||
--precision=NUMBER aucat/sndiod processing precision [$precision]
|
||||
--privsep-user=USER non-privileged user for sndio daemon [$user]
|
||||
|
@ -31,6 +33,7 @@ END
|
|||
#
|
||||
# defaults
|
||||
#
|
||||
version=1.8.0 # package version (used by pkg-config)
|
||||
prefix=/usr/local # where to install sndio
|
||||
so="libsndio.so.\${MAJ}.\${MIN}" # shared libs to build
|
||||
alsa=no # do we want alsa support ?
|
||||
|
@ -43,11 +46,13 @@ user=_sndio # non-privileged user for sndio daemon
|
|||
libbsd=no # use libbsd?
|
||||
so_ldflags= # extra linker flags for shared libs
|
||||
unset vars # variables passed as arguments
|
||||
unset exec_prefix # prefix for arch. independent files
|
||||
unset bindir # path where to install binaries
|
||||
unset datadir # path where to install doc
|
||||
unset mandir # path where to install man pages
|
||||
unset includedir # path where to install header file
|
||||
unset libdir # path where to install library
|
||||
unset pkgconfdir # path where to install pkg-config file
|
||||
unset defs # no extra #defines
|
||||
unset ldadd # no extra libraries (-l options)
|
||||
unset dev
|
||||
|
@ -112,6 +117,9 @@ for i; do
|
|||
--prefix=*)
|
||||
prefix="${i#--prefix=}"
|
||||
shift;;
|
||||
--exec-prefix=*)
|
||||
exec_prefix="${i#--exec-prefix=}"
|
||||
shift;;
|
||||
--bindir=*)
|
||||
bindir="${i#--bindir=}"
|
||||
shift;;
|
||||
|
@ -124,6 +132,9 @@ for i; do
|
|||
--libdir=*)
|
||||
libdir="${i#--libdir=}"
|
||||
shift;;
|
||||
--pkgconfdir=*)
|
||||
pkgconfdir="${i#--pkgconfdir=}"
|
||||
shift;;
|
||||
--mandir=*)
|
||||
mandir="${i#--mandir=}"
|
||||
shift;;
|
||||
|
@ -189,10 +200,12 @@ done
|
|||
#
|
||||
# if $xxxdir is not specified, define it to $prefix/xxx
|
||||
#
|
||||
bindir="${bindir:-$prefix/bin}"
|
||||
exec_prefix="${exec_prefix:-$prefix}"
|
||||
bindir="${bindir:-$exec_prefix/bin}"
|
||||
datadir="${datadir:-$prefix/share}"
|
||||
includedir="${includedir:-$prefix/include}"
|
||||
libdir="${libdir:-$prefix/lib}"
|
||||
libdir="${libdir:-$exec_prefix/lib}"
|
||||
pkgconfdir="${pkgconfdir:-$prefix/lib/pkgconfig}"
|
||||
mandir="${mandir:-$prefix/share/man}"
|
||||
|
||||
#
|
||||
|
@ -264,7 +277,9 @@ do
|
|||
-e "s:@datadir@:$datadir:" \
|
||||
-e "s:@includedir@:$includedir:" \
|
||||
-e "s:@libdir@:$libdir:" \
|
||||
-e "s:@pkgconfdir@:$pkgconfdir:" \
|
||||
-e "s:@mandir@:$mandir:" \
|
||||
-e "s:@version@:$version:" \
|
||||
-e "s:@defs@:$defs:" \
|
||||
-e "s:@ldadd@:$ldadd:" \
|
||||
-e "s:@so@:$so:" \
|
||||
|
@ -278,14 +293,35 @@ do
|
|||
< $f.in > $f
|
||||
done
|
||||
|
||||
#
|
||||
# Generate sndio.pc. Substitute path prefixes with ${prefix} or
|
||||
# ${exec_prefix} variable names, so that they can be overriden by the
|
||||
# user
|
||||
#
|
||||
cat <<EOF >libsndio/sndio.pc
|
||||
prefix=${prefix}
|
||||
exec_prefix=`echo $exec_prefix | sed -e "s:^${prefix}:\\${prefix}:"`
|
||||
libdir=`echo $libdir | sed -e "s:^${exec_prefix}:\\${exec_prefix}:"`
|
||||
includedir=`echo $includedir | sed -e "s:^${prefix}:\\${prefix}:"`
|
||||
|
||||
Name: sndio
|
||||
Description: sndio library
|
||||
Version: ${version}
|
||||
Requires:
|
||||
Libs: -L\${libdir} -lsndio
|
||||
Cflags: -I\${includedir}
|
||||
EOF
|
||||
|
||||
chmod +x contrib/init.d.sndiod
|
||||
|
||||
cat <<EOF
|
||||
|
||||
version.................. $version
|
||||
bindir................... $bindir
|
||||
datadir.................. $datadir
|
||||
includedir............... $includedir
|
||||
libdir................... $libdir
|
||||
pkgconfdir............... $pkgconfdir
|
||||
mandir................... $mandir
|
||||
user..................... $user
|
||||
libbsd................... $libbsd
|
||||
|
|
|
@ -13,7 +13,7 @@ LDADD = -lsndio @ldadd@
|
|||
# variables defined on configure script command line (if any)
|
||||
@vars@
|
||||
|
||||
PROG = play rec fd vol cap
|
||||
PROG = play rec fd vol cap gen-fir
|
||||
|
||||
all: ${PROG}
|
||||
|
||||
|
@ -32,6 +32,9 @@ vol: vol.o tools.o
|
|||
cap: cap.o tools.o
|
||||
${CC} ${LDFLAGS} ${LIB} -o cap cap.o tools.o ${LDADD}
|
||||
|
||||
gen-fir: gen-fir.c
|
||||
${CC} ${LDFLAGS} ${LIB} -o gen-fir gen-fir.c -lm
|
||||
|
||||
.c.o:
|
||||
${CC} ${CFLAGS} ${INCLUDE} ${DEFS} -c $<
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program generates coefficients for the resampling low-pass
|
||||
* filter used in sndiod and aucat.
|
||||
*
|
||||
* The coefficients correspond to the filter impulse response sampled
|
||||
* with 64 points per time unit; they are represented as 24-bit
|
||||
* fixed-point numbers.
|
||||
*
|
||||
* The filter is an ideal low-pass (sinc function), multiplied by a 8
|
||||
* time units long Blackman window. The filter cut-off frequency is
|
||||
* set at 0.75 of the Nyquist frequency (for instance, at 48kHz, the
|
||||
* cut-off will be at 18kHz, beyond audible frequencies).
|
||||
*
|
||||
* References:
|
||||
* https://en.wikipedia.org/wiki/Sinc_filter
|
||||
* https://en.wikipedia.org/wiki/Window_function
|
||||
* https://ccrma.stanford.edu/~jos/resample/
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int order = 8, factor = 64, bits = 24;
|
||||
|
||||
/*
|
||||
* convert double to fixed-point integer
|
||||
*/
|
||||
int
|
||||
mkfp(double x)
|
||||
{
|
||||
long long r, unit;
|
||||
|
||||
unit = 1LL << (bits - 1);
|
||||
r = x * unit + ((x >= 0) ? 0.5 : -0.5);
|
||||
if (r < -unit || r >= unit) {
|
||||
fprintf(stderr, "%g: sample out of range\n", x);
|
||||
exit(1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blackman window function
|
||||
*/
|
||||
double
|
||||
win_blackman(double a, double x)
|
||||
{
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
return (x >= 0.5) ? 0 :
|
||||
0.5 * (1 - a) +
|
||||
0.5 * cos(2 * M_PI * x) +
|
||||
0.5 * a * cos(4 * M_PI * x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideal low-pass filter response
|
||||
*/
|
||||
double
|
||||
lowpass_sinc(double cutoff, double t)
|
||||
{
|
||||
double arg;
|
||||
|
||||
if (t == 0)
|
||||
return cutoff;
|
||||
arg = M_PI * t;
|
||||
return sin(cutoff * arg) / arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert table index to time
|
||||
*/
|
||||
double
|
||||
timeof(int i)
|
||||
{
|
||||
return (double)(i - order * factor / 2) / factor;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
double t;
|
||||
double h;
|
||||
double cutoff = 3. / 4.;
|
||||
double param = 0.16;
|
||||
int i;
|
||||
|
||||
printf("{");
|
||||
for (i = 0; i <= order * factor; i++) {
|
||||
t = timeof(i);
|
||||
h = lowpass_sinc(cutoff, t) * win_blackman(param, t / order);
|
||||
if (i != 0)
|
||||
printf(",");
|
||||
printf("%s", (i % 8 == 0) ? "\n\t" : " ");
|
||||
printf("%7d", mkfp(h));
|
||||
}
|
||||
printf("\n};\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -24,6 +24,7 @@ SO_LDFLAGS = -shared @so_ldflags@
|
|||
#
|
||||
INCLUDE_DIR = @includedir@
|
||||
LIB_DIR = @libdir@
|
||||
PKGCONF_DIR = @pkgconfdir@
|
||||
MAN3_DIR = @mandir@/man3
|
||||
MAN7_DIR = @mandir@/man7
|
||||
|
||||
|
@ -57,10 +58,12 @@ all: ${SO} ${SO_LINK} ${SO_LINK_MAJ}
|
|||
install:
|
||||
mkdir -p ${DESTDIR}${INCLUDE_DIR}
|
||||
mkdir -p ${DESTDIR}${LIB_DIR}
|
||||
mkdir -p ${DESTDIR}${PKGCONF_DIR}
|
||||
mkdir -p ${DESTDIR}${MAN3_DIR}
|
||||
mkdir -p ${DESTDIR}${MAN7_DIR}
|
||||
cp sndio.h ${DESTDIR}${INCLUDE_DIR}
|
||||
cp -R ${SO} ${SO_LINK} ${SO_LINK_MAJ} ${DESTDIR}${LIB_DIR}
|
||||
cp sndio.pc ${DESTDIR}${PKGCONF_DIR}
|
||||
cp sio_open.3 ${DESTDIR}${MAN3_DIR}
|
||||
ln -sf sio_open.3 ${DESTDIR}${MAN3_DIR}/sio_close.3
|
||||
ln -sf sio_open.3 ${DESTDIR}${MAN3_DIR}/sio_setpar.3
|
||||
|
@ -100,6 +103,7 @@ install:
|
|||
uninstall:
|
||||
rm -f ${DESTDIR}${INCLUDE_DIR}/sndio.h
|
||||
cd ${DESTDIR}${LIB_DIR} && rm -f ${SO} ${SO_LINK}
|
||||
cd ${DESTDIR}${PKGCONF_DIR} && rm -f sndio.pc
|
||||
cd ${DESTDIR}${MAN3_DIR} && rm -f ${MAN3}
|
||||
cd ${DESTDIR}${MAN7_DIR} && rm -f ${MAN7}
|
||||
|
||||
|
|
|
@ -53,7 +53,12 @@ sio_open(const char *str, unsigned int mode, int nbio)
|
|||
if (str == NULL) /* backward compat */
|
||||
str = devany;
|
||||
if (strcmp(str, devany) == 0 && !issetugid()) {
|
||||
str = getenv("AUDIODEVICE");
|
||||
if ((mode & SIO_PLAY) == 0)
|
||||
str = getenv("AUDIORECDEVICE");
|
||||
if ((mode & SIO_REC) == 0)
|
||||
str = getenv("AUDIOPLAYDEVICE");
|
||||
if (mode == (SIO_PLAY | SIO_REC) || str == NULL)
|
||||
str = getenv("AUDIODEVICE");
|
||||
if (str == NULL)
|
||||
str = devany;
|
||||
}
|
||||
|
|
|
@ -554,6 +554,11 @@ sio_alsa_setpar_hw(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwp,
|
|||
|
||||
req_rate = *rate;
|
||||
|
||||
err = snd_pcm_hw_free(pcm);
|
||||
if (err < 0) {
|
||||
DALSA("couldn't reset hw configuration", err);
|
||||
return 0;
|
||||
}
|
||||
err = snd_pcm_hw_params_any(pcm, hwp);
|
||||
if (err < 0) {
|
||||
DALSA("couldn't init pars", err);
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
.Nm sio_eof ,
|
||||
.Nm sio_setvol ,
|
||||
.Nm sio_onvol ,
|
||||
.Nm sio_initpar
|
||||
.Nm sio_initpar ,
|
||||
.Nm SIO_BPS
|
||||
.Nd sndio interface to audio devices
|
||||
.Sh SYNOPSIS
|
||||
.In sndio.h
|
||||
|
@ -80,8 +81,8 @@
|
|||
.Fc
|
||||
.Ft "void"
|
||||
.Fn sio_initpar "struct sio_par *par"
|
||||
.\"Fd #define SIO_BPS(bits)
|
||||
.\"Fd #define SIO_LE_NATIVE
|
||||
.Ft unsigned int
|
||||
.Fn SIO_BPS "unsigned int bits"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm sndio
|
||||
|
@ -270,7 +271,7 @@ To ease filling the
|
|||
structure, the
|
||||
following macros can be used:
|
||||
.Bl -tag -width "SIO_BPS(bits)"
|
||||
.It Dv SIO_BPS Ns Pq Fa bits
|
||||
.It Fn SIO_BPS bits
|
||||
Return the smallest value for
|
||||
.Fa bps
|
||||
that is a power of two and that is large enough to
|
||||
|
@ -280,6 +281,7 @@ hold
|
|||
Can be used to set the
|
||||
.Fa le
|
||||
parameter when native byte order is required.
|
||||
It is 1 if the native byte order is little endian or 0 otherwise.
|
||||
.El
|
||||
.Ss Getting device capabilities
|
||||
There's no way to get an exhaustive list of all parameter
|
||||
|
@ -385,17 +387,17 @@ bitmasks should always be used.
|
|||
.Ss Starting and stopping the device
|
||||
The
|
||||
.Fn sio_start
|
||||
function puts the device in a waiting state:
|
||||
the device will wait for playback data to be provided
|
||||
(using the
|
||||
.Fn sio_write
|
||||
function).
|
||||
Once enough data is queued to ensure that play buffers
|
||||
will not underrun, actual playback is started automatically.
|
||||
If record mode only is selected, then recording starts
|
||||
immediately.
|
||||
function prepares the device to start.
|
||||
Once the play buffer is full, i.e.\&
|
||||
.Fa sio_par.bufsz
|
||||
samples are queued with
|
||||
.Fn sio_write ,
|
||||
playback starts automatically.
|
||||
If record-only mode is selected, then
|
||||
.Fn sio_start
|
||||
starts recording immediately.
|
||||
In full-duplex mode, playback and recording will start
|
||||
synchronously as soon as enough data to play is available.
|
||||
synchronously as soon as the play buffer is full.
|
||||
.Pp
|
||||
The
|
||||
.Fn sio_stop
|
||||
|
@ -579,7 +581,7 @@ parameter of the
|
|||
structure, the audio subsystem will behave as follows:
|
||||
.Bl -tag -width "SIO_IGNORE"
|
||||
.It Dv SIO_IGNORE
|
||||
The devices pauses during overruns and underruns,
|
||||
The device pauses during overruns and underruns,
|
||||
thus the current position (obtained through
|
||||
.Fn sio_onmove )
|
||||
stops being incremented.
|
||||
|
@ -735,10 +737,17 @@ The debug level:
|
|||
may be a value between 0 and 2.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mio_open 3 ,
|
||||
.Xr sioctl_open 3 ,
|
||||
.Xr audio 4 ,
|
||||
.Xr sndio 7 ,
|
||||
.Xr sndiod 8 ,
|
||||
.Xr audio 9
|
||||
.Sh HISTORY
|
||||
These functions first appeared in
|
||||
.Ox 4.5 .
|
||||
.Sh AUTHORS
|
||||
.An Alexandre Ratchov Aq Mt ratchov@openbsd.org
|
||||
.Sh BUGS
|
||||
The
|
||||
.Xr audio 4
|
||||
|
|
|
@ -436,9 +436,9 @@ sio_oss_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||
if (hdl->rate > 192000)
|
||||
hdl->rate = 192000;
|
||||
|
||||
if (hdl->sio.mode & SIO_PLAY)
|
||||
if ((hdl->sio.mode & SIO_PLAY) && par->pchan != ~0U)
|
||||
hdl->chan = par->pchan;
|
||||
else if (hdl->sio.mode & SIO_REC)
|
||||
else if ((hdl->sio.mode & SIO_REC) && par->rchan != ~0U)
|
||||
hdl->chan = par->rchan;
|
||||
|
||||
if (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &hdl->fmt) == -1) {
|
||||
|
|
117
libsndio/sndio.7
117
libsndio/sndio.7
|
@ -19,7 +19,7 @@
|
|||
.Os
|
||||
.Sh NAME
|
||||
.Nm sndio
|
||||
.Nd interface to audio and MIDI
|
||||
.Nd audio and MIDI device descriptors
|
||||
.Sh DESCRIPTION
|
||||
Programs access audio and MIDI hardware using the
|
||||
.Nm sndio
|
||||
|
@ -62,8 +62,9 @@ Additionally,
|
|||
exposes a MIDI port used to control audio programs using
|
||||
standard MIDI Machine Control (MMC), MIDI Time Code (MTC),
|
||||
and master volume messages.
|
||||
.Sh AUDIO AND MIDI DESCRIPTORS
|
||||
From the user's perspective every audio device or MIDI port
|
||||
.Ss Server device descriptors
|
||||
From the user's perspective, every audio device or MIDI port exposed by
|
||||
.Xr sndiod 8
|
||||
has a descriptor of the form:
|
||||
.Bd -literal -offset center
|
||||
type[@hostname][,servnum]/devnum[.option]
|
||||
|
@ -77,14 +78,6 @@ The type of the audio device or MIDI port.
|
|||
Possible values are:
|
||||
.Pp
|
||||
.Bl -tag -width "midithru" -offset 3n -compact
|
||||
.It Cm rsnd
|
||||
Raw
|
||||
.Xr audio 4
|
||||
device.
|
||||
.It Cm rmidi
|
||||
Raw
|
||||
.Xr midi 4
|
||||
port.
|
||||
.It Cm snd
|
||||
Audio device exposed by
|
||||
.Xr sndiod 8 .
|
||||
|
@ -94,8 +87,6 @@ MIDI thru port created with
|
|||
.It Cm midi
|
||||
MIDI port exposed by
|
||||
.Xr sndiod 8 .
|
||||
.It Cm default
|
||||
Default audio device or MIDI port (see below).
|
||||
.El
|
||||
.It Ar hostname
|
||||
The hostname or address where the remote
|
||||
|
@ -113,47 +104,49 @@ Useful only if multiple
|
|||
servers are running on the same system.
|
||||
.It Ar devnum
|
||||
Device number.
|
||||
For hardware audio or MIDI ports, this corresponds to
|
||||
the character device minor number.
|
||||
For audio devices or MIDI ports created with
|
||||
It corresponds to the number of the corresponding
|
||||
.Fl f
|
||||
or
|
||||
.Fl q
|
||||
option on the
|
||||
.Xr sndiod 8
|
||||
it corresponds to the number of the corresponding
|
||||
.Fl fq
|
||||
option on the command line.
|
||||
command line.
|
||||
.It Ar option
|
||||
Corresponds to the sub-device string registered using the
|
||||
.Fl s
|
||||
option of
|
||||
.Xr sndiod 8 .
|
||||
.El
|
||||
.Ss Raw device descriptors
|
||||
Every raw audio device or MIDI port has a descriptor of the form:
|
||||
.Pp
|
||||
For example:
|
||||
.D1 Ar type Ns / Ns Ar devnum
|
||||
.Pp
|
||||
.Bl -tag -width "snd/0.rear" -offset 3n -compact
|
||||
.It Li rsnd/0
|
||||
Raw access to first audio device.
|
||||
.It Li rmidi/5
|
||||
Raw access to MIDI port number 5.
|
||||
.It Li snd/0
|
||||
Audio device referred by first
|
||||
.Fl f
|
||||
option of
|
||||
.Xr sndiod 8 .
|
||||
.It Li snd/0.rear
|
||||
Sub-device registered with
|
||||
.Fl s Fa rear .
|
||||
.It Li midithru/0
|
||||
First MIDI thru port created with
|
||||
.Xr sndiod 8 .
|
||||
.El
|
||||
.Sh DEFAULTS
|
||||
If
|
||||
The
|
||||
.Ar type
|
||||
can be either
|
||||
.Cm rsnd
|
||||
or
|
||||
.Cm rmidi .
|
||||
The rsnd/0 device descriptor accesses the
|
||||
.Pa /dev/audio0
|
||||
device, rsnd/1 accesses
|
||||
.Pa /dev/audio1 ,
|
||||
and so on.
|
||||
Similarly, rmidi/0 accesses
|
||||
.Pa /dev/rmidi0
|
||||
and so on.
|
||||
.Ss Default Audio and MIDI devices
|
||||
When no audio device descriptor is provided to a program
|
||||
or when the reserved word
|
||||
.Cm default
|
||||
is used as the audio device, the program will use the
|
||||
one specified in the
|
||||
.Ev AUDIODEVICE
|
||||
environment variable.
|
||||
If it is not set, the program first tries to connect to
|
||||
.Ev AUDIODEVICE , AUDIOPLAYDEVICE
|
||||
and/or
|
||||
.Ev AUDIORECDEVICE
|
||||
environment variables.
|
||||
If they are not set, the program first tries to connect to
|
||||
.Li snd/0 .
|
||||
If that fails, it then tries to use
|
||||
.Li rsnd/0 .
|
||||
|
@ -175,7 +168,7 @@ is running, this allows programs to exchange MIDI data on
|
|||
machines with no MIDI hardware by default, e.g. a MIDI player
|
||||
could use a software synthesizer with no manual configuration
|
||||
required.
|
||||
.Sh AUTHENTICATION
|
||||
.Ss Authentication
|
||||
For privacy reasons only one user may have connections to
|
||||
.Xr sndiod 8
|
||||
at a given time.
|
||||
|
@ -190,10 +183,20 @@ and contains 128 bits of raw random data.
|
|||
If a session needs to be shared between multiple users, they
|
||||
can connect to the server using the same cookie.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width "AUDIODEVICEXXX" -compact
|
||||
.Bl -tag -width "AUDIOPLAYDEVICE" -compact
|
||||
.It Ev AUDIODEVICE
|
||||
Audio device descriptor to use
|
||||
when no descriptor is explicitly specified to a program.
|
||||
.It Ev AUDIOPLAYDEVICE
|
||||
Audio device descriptor to use for play-only mode
|
||||
when no descriptor is explicitly specified to a program.
|
||||
Overrides
|
||||
.Ev AUDIODEVICE .
|
||||
.It Ev AUDIORECDEVICE
|
||||
Audio device descriptor to use for record-only mode
|
||||
when no descriptor is explicitly specified to a program.
|
||||
Overrides
|
||||
.Ev AUDIODEVICE .
|
||||
.It Ev MIDIDEVICE
|
||||
MIDI port descriptor to use
|
||||
when no descriptor is explicitly specified to a program.
|
||||
|
@ -207,9 +210,31 @@ if the program has the set-user-ID or set-group-ID bits set.
|
|||
.It Pa ~/.sndio/cookie
|
||||
User's session authentication cookie.
|
||||
.It Pa /dev/audioN
|
||||
Audio devices.
|
||||
Raw audio devices.
|
||||
.It Pa /dev/rmidiN
|
||||
MIDI ports.
|
||||
Raw MIDI ports.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Bl -tag -width "snd/0.rear" -compact
|
||||
.It Li snd/0
|
||||
Audio device referred to by the first
|
||||
.Fl f
|
||||
option of
|
||||
.Xr sndiod 8 .
|
||||
.It Li snd/0.rear
|
||||
Sub-device registered with
|
||||
.Dq -s rear .
|
||||
.It Li midithru/0
|
||||
First MIDI thru port created with
|
||||
.Xr sndiod 8 .
|
||||
.It Li default
|
||||
Default audio or MIDI device.
|
||||
.It Li rsnd/0
|
||||
Direct hardware access to
|
||||
.Pa /dev/audio0 .
|
||||
.It Li rmidi/5
|
||||
Direct hardware access to
|
||||
.Pa /dev/rmidi5 .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr aucat 1 ,
|
||||
|
|
|
@ -72,8 +72,8 @@ The set of available controls depends on the audio device.
|
|||
Commands use the following two formats to display and change
|
||||
controls respectively:
|
||||
.Pp
|
||||
.Dl group/stream[channel].function
|
||||
.Dl group/stream[channel].function=value
|
||||
.Dl [group/]stream[channel].function
|
||||
.Dl [group/]stream[channel].function=value
|
||||
.Pp
|
||||
On the left-hand side are specified the control group (if any),
|
||||
the affected stream name, and the optional channel number.
|
||||
|
@ -119,5 +119,13 @@ Toggle the above
|
|||
control:
|
||||
.Pp
|
||||
.Dl $ sndioctl output.mute=!
|
||||
.Pp
|
||||
Allow audio recording and set all
|
||||
.Cm input
|
||||
channels to 50%:
|
||||
.Bd -literal -offset indent
|
||||
# sysctl kern.audio.record=1
|
||||
$ sndioctl input.mute=0 input.level=0.5
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr sioctl_open 3
|
||||
|
|
|
@ -1015,6 +1015,7 @@ main(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
for (;;) {
|
||||
fflush(stdout);
|
||||
nfds = sioctl_pollfd(hdl, pfds, POLLIN);
|
||||
if (nfds == 0)
|
||||
break;
|
||||
|
|
|
@ -55,23 +55,26 @@ sndiod: ${OBJS}
|
|||
|
||||
abuf.o: abuf.c abuf.h utils.h
|
||||
dev.o: dev.c ../bsd-compat/bsd-compat.h abuf.h defs.h dev.h \
|
||||
dsp.h siofile.h file.h midi.h miofile.h sysex.h utils.h
|
||||
dsp.h siofile.h file.h dev_sioctl.h opt.h midi.h \
|
||||
miofile.h sysex.h utils.h
|
||||
dev_sioctl.o: dev_sioctl.c abuf.h defs.h dev.h dsp.h siofile.h file.h \
|
||||
utils.h
|
||||
dev_sioctl.h opt.h utils.h ../bsd-compat/bsd-compat.h
|
||||
dsp.o: dsp.c dsp.h defs.h utils.h
|
||||
file.o: file.c file.h utils.h
|
||||
file.o: file.c ../bsd-compat/bsd-compat.h file.h utils.h
|
||||
listen.o: listen.c listen.h file.h sock.h ../libsndio/amsg.h \
|
||||
utils.h ../bsd-compat/bsd-compat.h
|
||||
midi.o: midi.c abuf.h defs.h dev.h dsp.h siofile.h file.h midi.h \
|
||||
miofile.h sysex.h utils.h ../bsd-compat/bsd-compat.h
|
||||
midi.o: midi.c abuf.h defs.h dev.h dsp.h siofile.h file.h \
|
||||
dev_sioctl.h opt.h midi.h miofile.h sysex.h utils.h \
|
||||
../bsd-compat/bsd-compat.h
|
||||
miofile.o: miofile.c defs.h file.h midi.h abuf.h miofile.h utils.h
|
||||
opt.o: opt.c dev.h abuf.h dsp.h defs.h siofile.h file.h opt.h \
|
||||
utils.h
|
||||
opt.o: opt.c dev.h abuf.h dsp.h defs.h siofile.h file.h \
|
||||
dev_sioctl.h opt.h midi.h miofile.h sysex.h utils.h
|
||||
siofile.o: siofile.c abuf.h defs.h dev.h dsp.h siofile.h file.h \
|
||||
utils.h
|
||||
dev_sioctl.h opt.h utils.h
|
||||
sndiod.o: sndiod.c ../libsndio/amsg.h defs.h dev.h abuf.h dsp.h \
|
||||
siofile.h file.h listen.h midi.h miofile.h opt.h sock.h \
|
||||
utils.h ../bsd-compat/bsd-compat.h
|
||||
sock.o: sock.c abuf.h defs.h dev.h dsp.h siofile.h file.h midi.h \
|
||||
miofile.h opt.h sock.h ../libsndio/amsg.h utils.h
|
||||
siofile.h file.h dev_sioctl.h opt.h listen.h midi.h \
|
||||
miofile.h sock.h utils.h ../bsd-compat/bsd-compat.h
|
||||
sock.o: sock.c abuf.h defs.h dev.h dsp.h siofile.h file.h \
|
||||
dev_sioctl.h opt.h midi.h miofile.h sock.h \
|
||||
../libsndio/amsg.h utils.h ../bsd-compat/bsd-compat.h
|
||||
utils.o: utils.c utils.h
|
||||
|
|
1360
sndiod/dev.c
1360
sndiod/dev.c
File diff suppressed because it is too large
Load Diff
189
sndiod/dev.h
189
sndiod/dev.h
|
@ -21,11 +21,17 @@
|
|||
#include "dsp.h"
|
||||
#include "siofile.h"
|
||||
#include "dev_sioctl.h"
|
||||
#include "opt.h"
|
||||
|
||||
#define CTLADDR_SLOT_LEVEL(n) (n)
|
||||
#define CTLADDR_MASTER (DEV_NSLOT)
|
||||
#define CTLADDR_ALT_SEL (CTLADDR_MASTER + 1)
|
||||
#define CTLADDR_END (CTLADDR_ALT_SEL + DEV_NMAX)
|
||||
/*
|
||||
* preallocated audio clients
|
||||
*/
|
||||
#define DEV_NSLOT 8
|
||||
|
||||
/*
|
||||
* preallocated control clients
|
||||
*/
|
||||
#define DEV_NCTLSLOT 8
|
||||
|
||||
/*
|
||||
* audio stream state structure
|
||||
|
@ -50,7 +56,6 @@ struct ctlops
|
|||
struct slot {
|
||||
struct slotops *ops; /* client callbacks */
|
||||
struct slot *next; /* next on the play list */
|
||||
struct dev *dev; /* device this belongs to */
|
||||
struct opt *opt; /* config used */
|
||||
void *arg; /* user data for callbacks */
|
||||
struct aparams par; /* socket side params */
|
||||
|
@ -82,7 +87,7 @@ struct slot {
|
|||
int xrun; /* underrun policy */
|
||||
int skip; /* cycles to skip (for xrun) */
|
||||
#define SLOT_BUFSZ(s) \
|
||||
((s)->appbufsz + (s)->dev->bufsz / (s)->dev->round * (s)->round)
|
||||
((s)->appbufsz + (s)->opt->dev->bufsz / (s)->opt->dev->round * (s)->round)
|
||||
int appbufsz; /* slot-side buffer size */
|
||||
int round; /* slot-side block size */
|
||||
int rate; /* slot-side sample rate */
|
||||
|
@ -104,24 +109,13 @@ struct slot {
|
|||
unsigned int id; /* process id */
|
||||
};
|
||||
|
||||
struct opt {
|
||||
struct opt *next;
|
||||
#define OPT_NAMEMAX 11
|
||||
char name[OPT_NAMEMAX + 1];
|
||||
int maxweight; /* max dynamic range for clients */
|
||||
int pmin, pmax; /* play channels */
|
||||
int rmin, rmax; /* recording channels */
|
||||
int mmc; /* true if MMC control enabled */
|
||||
int dup; /* true if join/expand enabled */
|
||||
int mode; /* bitmap of MODE_XXX */
|
||||
};
|
||||
|
||||
/*
|
||||
* subset of channels of a stream
|
||||
*/
|
||||
|
||||
struct ctl {
|
||||
struct ctl *next;
|
||||
|
||||
#define CTL_NONE 0 /* deleted */
|
||||
#define CTL_NUM 2 /* number (aka integer value) */
|
||||
#define CTL_SW 3 /* on/off switch, only bit 7 counts */
|
||||
|
@ -129,7 +123,34 @@ struct ctl {
|
|||
#define CTL_LIST 5 /* switch, element of a list */
|
||||
#define CTL_SEL 6 /* element of a selector */
|
||||
unsigned int type; /* one of above */
|
||||
unsigned int addr; /* control address */
|
||||
|
||||
#define CTL_HW 0
|
||||
#define CTL_DEV_MASTER 1
|
||||
#define CTL_DEV_ALT 2
|
||||
#define CTL_SLOT_LEVEL 3
|
||||
unsigned int scope;
|
||||
union {
|
||||
struct {
|
||||
void *arg0;
|
||||
void *arg1;
|
||||
} any;
|
||||
struct {
|
||||
struct dev *dev;
|
||||
unsigned int addr;
|
||||
} hw;
|
||||
struct {
|
||||
struct dev *dev;
|
||||
} dev_master;
|
||||
struct {
|
||||
struct dev *dev;
|
||||
unsigned int idx;
|
||||
} dev_alt;
|
||||
struct {
|
||||
struct slot *slot;
|
||||
} slot_level;
|
||||
} u;
|
||||
|
||||
unsigned int addr; /* slot side control address */
|
||||
#define CTL_NAMEMAX 16 /* max name lenght */
|
||||
char func[CTL_NAMEMAX]; /* parameter function name */
|
||||
char group[CTL_NAMEMAX]; /* group aka namespace */
|
||||
|
@ -150,19 +171,50 @@ struct ctl {
|
|||
struct ctlslot {
|
||||
struct ctlops *ops;
|
||||
void *arg;
|
||||
struct dev *dev;
|
||||
unsigned int mask;
|
||||
struct opt *opt;
|
||||
unsigned int self; /* equal to (1 << index) */
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* MIDI time code (MTC)
|
||||
*/
|
||||
struct mtc {
|
||||
/*
|
||||
* MIDI time code (MTC) states
|
||||
*/
|
||||
#define MTC_STOP 1 /* stopped, can't start */
|
||||
#define MTC_START 2 /* attempting to start */
|
||||
#define MTC_RUN 3 /* started */
|
||||
unsigned int tstate; /* one of MTC_* constants */
|
||||
struct dev *dev;
|
||||
|
||||
unsigned int origin; /* MTC start time */
|
||||
unsigned int fps; /* MTC frames per second */
|
||||
#define MTC_FPS_24 0
|
||||
#define MTC_FPS_25 1
|
||||
#define MTC_FPS_30 3
|
||||
unsigned int fps_id; /* one of above */
|
||||
unsigned int hr; /* MTC hours */
|
||||
unsigned int min; /* MTC minutes */
|
||||
unsigned int sec; /* MTC seconds */
|
||||
unsigned int fr; /* MTC frames */
|
||||
unsigned int qfr; /* MTC quarter frames */
|
||||
int delta; /* rel. to the last MTC tick */
|
||||
int refs;
|
||||
};
|
||||
|
||||
/*
|
||||
* audio device with plenty of slots
|
||||
*/
|
||||
struct dev {
|
||||
struct dev *next;
|
||||
struct slot *slot_list; /* audio streams attached */
|
||||
struct opt *opt_list;
|
||||
struct midi *midi;
|
||||
|
||||
/*
|
||||
* name used for various controls
|
||||
*/
|
||||
char name[CTL_NAMEMAX];
|
||||
|
||||
/*
|
||||
* audio device (while opened)
|
||||
|
@ -181,13 +233,6 @@ struct dev {
|
|||
unsigned char *encbuf; /* buffer for encoding */
|
||||
unsigned char *decbuf; /* buffer for decoding */
|
||||
|
||||
/*
|
||||
* preallocated audio sub-devices
|
||||
*/
|
||||
#define DEV_NSLOT 8
|
||||
struct slot slot[DEV_NSLOT];
|
||||
unsigned int serial; /* for slot allocation */
|
||||
|
||||
/*
|
||||
* current position, relative to the current cycle
|
||||
*/
|
||||
|
@ -225,46 +270,17 @@ struct dev {
|
|||
unsigned int bufsz, round, rate;
|
||||
unsigned int prime;
|
||||
|
||||
/*
|
||||
* MIDI time code (MTC)
|
||||
*/
|
||||
struct {
|
||||
unsigned int origin; /* MTC start time */
|
||||
unsigned int fps; /* MTC frames per second */
|
||||
#define MTC_FPS_24 0
|
||||
#define MTC_FPS_25 1
|
||||
#define MTC_FPS_30 3
|
||||
unsigned int fps_id; /* one of above */
|
||||
unsigned int hr; /* MTC hours */
|
||||
unsigned int min; /* MTC minutes */
|
||||
unsigned int sec; /* MTC seconds */
|
||||
unsigned int fr; /* MTC frames */
|
||||
unsigned int qfr; /* MTC quarter frames */
|
||||
int delta; /* rel. to the last MTC tick */
|
||||
int refs;
|
||||
} mtc;
|
||||
|
||||
/*
|
||||
* MIDI machine control (MMC)
|
||||
*/
|
||||
#define MMC_STOP 1 /* stopped, can't start */
|
||||
#define MMC_START 2 /* attempting to start */
|
||||
#define MMC_RUN 3 /* started */
|
||||
unsigned int tstate; /* one of above */
|
||||
|
||||
unsigned int master; /* software vol. knob */
|
||||
unsigned int master_enabled; /* 1 if h/w has no vo. knob */
|
||||
|
||||
/*
|
||||
* control
|
||||
*/
|
||||
|
||||
struct ctl *ctl_list;
|
||||
#define DEV_NCTLSLOT 8
|
||||
struct ctlslot ctlslot[DEV_NCTLSLOT];
|
||||
};
|
||||
|
||||
extern struct dev *dev_list;
|
||||
extern struct ctl *ctl_list;
|
||||
extern struct slot slot_array[DEV_NSLOT];
|
||||
extern struct ctlslot ctlslot_array[DEV_NCTLSLOT];
|
||||
extern struct mtc mtc_array[1];
|
||||
|
||||
void slot_array_init(void);
|
||||
|
||||
void dev_log(struct dev *);
|
||||
void dev_abort(struct dev *);
|
||||
|
@ -291,39 +307,56 @@ void dev_cycle(struct dev *);
|
|||
/*
|
||||
* midi & midi call-backs
|
||||
*/
|
||||
void dev_mmcstart(struct dev *);
|
||||
void dev_mmcstop(struct dev *);
|
||||
void dev_mmcloc(struct dev *, unsigned int);
|
||||
void dev_master(struct dev *, unsigned int);
|
||||
void dev_midi_send(struct dev *, void *, int);
|
||||
void dev_midi_vol(struct dev *, struct slot *);
|
||||
void dev_midi_master(struct dev *);
|
||||
void dev_midi_slotdesc(struct dev *, struct slot *);
|
||||
void dev_midi_dump(struct dev *);
|
||||
|
||||
void mtc_midi_qfr(struct mtc *, int);
|
||||
void mtc_midi_full(struct mtc *);
|
||||
void mtc_trigger(struct mtc *);
|
||||
void mtc_start(struct mtc *);
|
||||
void mtc_stop(struct mtc *);
|
||||
void mtc_loc(struct mtc *, unsigned int);
|
||||
void mtc_setdev(struct mtc *, struct dev *);
|
||||
|
||||
/*
|
||||
* sio_open(3) like interface for clients
|
||||
*/
|
||||
void slot_log(struct slot *);
|
||||
struct slot *slot_new(struct dev *, struct opt *, unsigned int, char *,
|
||||
struct slot *slot_new(struct opt *, unsigned int, char *,
|
||||
struct slotops *, void *, int);
|
||||
void slot_del(struct slot *);
|
||||
void slot_setvol(struct slot *, unsigned int);
|
||||
void slot_start(struct slot *);
|
||||
void slot_stop(struct slot *);
|
||||
void slot_stop(struct slot *, int);
|
||||
void slot_read(struct slot *);
|
||||
void slot_write(struct slot *);
|
||||
void slot_initconv(struct slot *);
|
||||
void slot_attach(struct slot *);
|
||||
void slot_detach(struct slot *);
|
||||
|
||||
/*
|
||||
* control related functions
|
||||
*/
|
||||
|
||||
struct ctl *ctl_new(int, void *, void *,
|
||||
int, char *, char *, int, char *, char *, int, int, int);
|
||||
void ctl_del(int, void *, void *);
|
||||
void ctl_log(struct ctl *);
|
||||
struct ctlslot *ctlslot_new(struct dev *, struct ctlops *, void *);
|
||||
int ctl_setval(struct ctl *c, int val);
|
||||
int ctl_match(struct ctl *, int, void *, void *);
|
||||
struct ctl *ctl_find(int, void *, void *);
|
||||
void ctl_update(struct ctl *);
|
||||
int ctl_onval(int, void *, void *, int);
|
||||
|
||||
struct ctlslot *ctlslot_new(struct opt *, struct ctlops *, void *);
|
||||
void ctlslot_del(struct ctlslot *);
|
||||
int dev_setctl(struct dev *, int, int);
|
||||
int dev_onval(struct dev *, int, int);
|
||||
int dev_nctl(struct dev *);
|
||||
int ctlslot_visible(struct ctlslot *, struct ctl *);
|
||||
struct ctl *ctlslot_lookup(struct ctlslot *, int);
|
||||
void dev_label(struct dev *, int);
|
||||
struct ctl *dev_addctl(struct dev *, char *, int, int,
|
||||
char *, int, char *, char *, int, int, int);
|
||||
void dev_rmctl(struct dev *, int);
|
||||
int dev_makeunit(struct dev *, char *);
|
||||
void dev_ctlsync(struct dev *);
|
||||
|
||||
#endif /* !defined(DEV_H) */
|
||||
|
|
|
@ -51,34 +51,27 @@ struct fileops dev_sioctl_ops = {
|
|||
void
|
||||
dev_sioctl_ondesc(void *arg, struct sioctl_desc *desc, int val)
|
||||
{
|
||||
#define GROUP_PREFIX "hw"
|
||||
char group_buf[CTL_NAMEMAX], *group;
|
||||
struct dev *d = arg;
|
||||
int addr;
|
||||
char *group, group_buf[CTL_NAMEMAX];
|
||||
|
||||
if (desc == NULL) {
|
||||
dev_ctlsync(d);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = CTLADDR_END + desc->addr;
|
||||
dev_rmctl(d, addr);
|
||||
ctl_del(CTL_HW, d, &desc->addr);
|
||||
|
||||
/*
|
||||
* prefix with "hw/" group names of controls we expose, to
|
||||
* ensure that all controls have unique names when multiple
|
||||
* sndiod's are chained
|
||||
*/
|
||||
if (strcmp(desc->group, "app") == 0 || (desc->group[0] == 0 &&
|
||||
strcmp(desc->node0.name, "server") == 0)) {
|
||||
group = group_buf;
|
||||
if (snprintf(group_buf, CTL_NAMEMAX, GROUP_PREFIX "/%s",
|
||||
desc->group) >= CTL_NAMEMAX)
|
||||
if (desc->group[0] == 0)
|
||||
group = d->name;
|
||||
else {
|
||||
if (snprintf(group_buf, CTL_NAMEMAX, "%s/%s",
|
||||
d->name, desc->group) >= CTL_NAMEMAX)
|
||||
return;
|
||||
} else
|
||||
group = desc->group;
|
||||
group = group_buf;
|
||||
}
|
||||
|
||||
dev_addctl(d, group, desc->type, addr,
|
||||
ctl_new(CTL_HW, d, &desc->addr,
|
||||
desc->type, group,
|
||||
desc->node0.name, desc->node0.unit, desc->func,
|
||||
desc->node1.name, desc->node1.unit, desc->maxval, val);
|
||||
}
|
||||
|
@ -89,8 +82,6 @@ dev_sioctl_onval(void *arg, unsigned int addr, unsigned int val)
|
|||
struct dev *d = arg;
|
||||
struct ctl *c;
|
||||
|
||||
addr += CTLADDR_END;
|
||||
|
||||
dev_log(d);
|
||||
log_puts(": onctl: addr = ");
|
||||
log_putu(addr);
|
||||
|
@ -98,8 +89,8 @@ dev_sioctl_onval(void *arg, unsigned int addr, unsigned int val)
|
|||
log_putu(val);
|
||||
log_puts("\n");
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->addr != addr)
|
||||
for (c = ctl_list; c != NULL; c = c->next) {
|
||||
if (c->scope != CTL_HW || c->u.hw.addr != addr)
|
||||
continue;
|
||||
ctl_log(c);
|
||||
log_puts(": new value -> ");
|
||||
|
@ -139,9 +130,9 @@ dev_sioctl_close(struct dev *d)
|
|||
struct ctl *c, **pc;
|
||||
|
||||
/* remove controls */
|
||||
pc = &d->ctl_list;
|
||||
pc = &ctl_list;
|
||||
while ((c = *pc) != NULL) {
|
||||
if (c->addr >= CTLADDR_END) {
|
||||
if (c->scope == CTL_HW && c->u.hw.dev == d) {
|
||||
c->refs_mask &= ~CTL_DEVMASK;
|
||||
if (c->refs_mask == 0) {
|
||||
*pc = c->next;
|
||||
|
@ -163,8 +154,8 @@ dev_sioctl_pollfd(void *arg, struct pollfd *pfd)
|
|||
struct ctl *c;
|
||||
int events = 0;
|
||||
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->dirty)
|
||||
for (c = ctl_list; c != NULL; c = c->next) {
|
||||
if (c->scope == CTL_HW && c->u.hw.dev == d && c->dirty)
|
||||
events |= POLLOUT;
|
||||
}
|
||||
return sioctl_pollfd(d->sioctl.hdl, pfd, events);
|
||||
|
@ -196,11 +187,10 @@ dev_sioctl_out(void *arg)
|
|||
* we've finished iterating on it.
|
||||
*/
|
||||
cnt = 0;
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (!c->dirty)
|
||||
for (c = ctl_list; c != NULL; c = c->next) {
|
||||
if (c->scope != CTL_HW || c->u.hw.dev != d || !c->dirty)
|
||||
continue;
|
||||
if (!sioctl_setval(d->sioctl.hdl,
|
||||
c->addr - CTLADDR_END, c->curval)) {
|
||||
if (!sioctl_setval(d->sioctl.hdl, c->u.hw.addr, c->curval)) {
|
||||
ctl_log(c);
|
||||
log_puts(": set failed\n");
|
||||
break;
|
||||
|
|
132
sndiod/dsp.c
132
sndiod/dsp.c
|
@ -18,7 +18,7 @@
|
|||
#include "dsp.h"
|
||||
#include "utils.h"
|
||||
|
||||
int aparams_ctltovol[128] = {
|
||||
const int aparams_ctltovol[128] = {
|
||||
0,
|
||||
256, 266, 276, 287, 299, 310, 323, 335,
|
||||
348, 362, 376, 391, 406, 422, 439, 456,
|
||||
|
@ -38,6 +38,75 @@ int aparams_ctltovol[128] = {
|
|||
26008, 27029, 28090, 29193, 30339, 31530, 32768
|
||||
};
|
||||
|
||||
const int resamp_filt[RESAMP_LENGTH / RESAMP_STEP + 1] = {
|
||||
0, 0, 3, 9, 22, 42, 73, 116,
|
||||
174, 248, 341, 454, 589, 749, 934, 1148,
|
||||
1392, 1666, 1974, 2316, 2693, 3107, 3560, 4051,
|
||||
4582, 5154, 5766, 6420, 7116, 7853, 8632, 9451,
|
||||
10311, 11210, 12148, 13123, 14133, 15178, 16253, 17359,
|
||||
18491, 19647, 20824, 22018, 23226, 24443, 25665, 26888,
|
||||
28106, 29315, 30509, 31681, 32826, 33938, 35009, 36033,
|
||||
37001, 37908, 38744, 39502, 40174, 40750, 41223, 41582,
|
||||
41819, 41925, 41890, 41704, 41358, 40842, 40147, 39261,
|
||||
38176, 36881, 35366, 33623, 31641, 29411, 26923, 24169,
|
||||
21140, 17827, 14222, 10317, 6105, 1580, -3267, -8440,
|
||||
-13944, -19785, -25967, -32492, -39364, -46584, -54153, -62072,
|
||||
-70339, -78953, -87911, -97209, -106843, -116806, -127092, -137692,
|
||||
-148596, -159795, -171276, -183025, -195029, -207271, -219735, -232401,
|
||||
-245249, -258259, -271407, -284670, -298021, -311434, -324880, -338329,
|
||||
-351750, -365111, -378378, -391515, -404485, -417252, -429775, -442015,
|
||||
-453930, -465477, -476613, -487294, -497472, -507102, -516137, -524527,
|
||||
-532225, -539181, -545344, -550664, -555090, -558571, -561055, -562490,
|
||||
-562826, -562010, -559990, -556717, -552139, -546205, -538866, -530074,
|
||||
-519779, -507936, -494496, -479416, -462652, -444160, -423901, -401835,
|
||||
-377923, -352132, -324425, -294772, -263143, -229509, -193847, -156134,
|
||||
-116348, -74474, -30494, 15601, 63822, 114174, 166661, 221283,
|
||||
278037, 336916, 397911, 461009, 526194, 593446, 662741, 734054,
|
||||
807354, 882608, 959779, 1038826, 1119706, 1202370, 1286768, 1372846,
|
||||
1460546, 1549808, 1640566, 1732753, 1826299, 1921130, 2017169, 2114336,
|
||||
2212550, 2311723, 2411770, 2512598, 2614116, 2716228, 2818836, 2921841,
|
||||
3025142, 3128636, 3232218, 3335782, 3439219, 3542423, 3645282, 3747687,
|
||||
3849526, 3950687, 4051059, 4150530, 4248987, 4346320, 4442415, 4537163,
|
||||
4630453, 4722177, 4812225, 4900493, 4986873, 5071263, 5153561, 5233668,
|
||||
5311485, 5386917, 5459872, 5530259, 5597992, 5662986, 5725160, 5784436,
|
||||
5840739, 5893999, 5944148, 5991122, 6034862, 6075313, 6112422, 6146142,
|
||||
6176430, 6203247, 6226559, 6246335, 6262551, 6275185, 6284220, 6289647,
|
||||
6291456, 6289647, 6284220, 6275185, 6262551, 6246335, 6226559, 6203247,
|
||||
6176430, 6146142, 6112422, 6075313, 6034862, 5991122, 5944148, 5893999,
|
||||
5840739, 5784436, 5725160, 5662986, 5597992, 5530259, 5459872, 5386917,
|
||||
5311485, 5233668, 5153561, 5071263, 4986873, 4900493, 4812225, 4722177,
|
||||
4630453, 4537163, 4442415, 4346320, 4248987, 4150530, 4051059, 3950687,
|
||||
3849526, 3747687, 3645282, 3542423, 3439219, 3335782, 3232218, 3128636,
|
||||
3025142, 2921841, 2818836, 2716228, 2614116, 2512598, 2411770, 2311723,
|
||||
2212550, 2114336, 2017169, 1921130, 1826299, 1732753, 1640566, 1549808,
|
||||
1460546, 1372846, 1286768, 1202370, 1119706, 1038826, 959779, 882608,
|
||||
807354, 734054, 662741, 593446, 526194, 461009, 397911, 336916,
|
||||
278037, 221283, 166661, 114174, 63822, 15601, -30494, -74474,
|
||||
-116348, -156134, -193847, -229509, -263143, -294772, -324425, -352132,
|
||||
-377923, -401835, -423901, -444160, -462652, -479416, -494496, -507936,
|
||||
-519779, -530074, -538866, -546205, -552139, -556717, -559990, -562010,
|
||||
-562826, -562490, -561055, -558571, -555090, -550664, -545344, -539181,
|
||||
-532225, -524527, -516137, -507102, -497472, -487294, -476613, -465477,
|
||||
-453930, -442015, -429775, -417252, -404485, -391515, -378378, -365111,
|
||||
-351750, -338329, -324880, -311434, -298021, -284670, -271407, -258259,
|
||||
-245249, -232401, -219735, -207271, -195029, -183025, -171276, -159795,
|
||||
-148596, -137692, -127092, -116806, -106843, -97209, -87911, -78953,
|
||||
-70339, -62072, -54153, -46584, -39364, -32492, -25967, -19785,
|
||||
-13944, -8440, -3267, 1580, 6105, 10317, 14222, 17827,
|
||||
21140, 24169, 26923, 29411, 31641, 33623, 35366, 36881,
|
||||
38176, 39261, 40147, 40842, 41358, 41704, 41890, 41925,
|
||||
41819, 41582, 41223, 40750, 40174, 39502, 38744, 37908,
|
||||
37001, 36033, 35009, 33938, 32826, 31681, 30509, 29315,
|
||||
28106, 26888, 25665, 24443, 23226, 22018, 20824, 19647,
|
||||
18491, 17359, 16253, 15178, 14133, 13123, 12148, 11210,
|
||||
10311, 9451, 8632, 7853, 7116, 6420, 5766, 5154,
|
||||
4582, 4051, 3560, 3107, 2693, 2316, 1974, 1666,
|
||||
1392, 1148, 934, 749, 589, 454, 341, 248,
|
||||
174, 116, 73, 42, 22, 9, 3, 0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Generate a string corresponding to the encoding in par,
|
||||
* return the length of the resulting string.
|
||||
|
@ -192,7 +261,9 @@ aparams_log(struct aparams *par)
|
|||
int
|
||||
aparams_native(struct aparams *par)
|
||||
{
|
||||
return par->bps == sizeof(adata_t) && par->bits == ADATA_BITS &&
|
||||
return par->sig &&
|
||||
par->bps == sizeof(adata_t) &&
|
||||
par->bits == ADATA_BITS &&
|
||||
(par->bps == 1 || par->le == ADATA_LE) &&
|
||||
(par->bits == par->bps * 8 || !par->msb);
|
||||
}
|
||||
|
@ -210,8 +281,10 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
|
|||
adata_t *odata;
|
||||
unsigned int iblksz;
|
||||
unsigned int c;
|
||||
int64_t f[NCHAN_MAX];
|
||||
adata_t *ctxbuf, *ctx;
|
||||
unsigned int ctx_start;
|
||||
int q, qi, qf, n;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (todo % p->iblksz != 0) {
|
||||
|
@ -238,7 +311,7 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
|
|||
if (diff >= oblksz) {
|
||||
if (todo == 0)
|
||||
break;
|
||||
ctx_start ^= 1;
|
||||
ctx_start = (ctx_start - 1) & (RESAMP_NCTX - 1);
|
||||
ctx = ctxbuf + ctx_start;
|
||||
for (c = nch; c > 0; c--) {
|
||||
*ctx = *idata++;
|
||||
|
@ -247,12 +320,46 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
|
|||
diff -= oblksz;
|
||||
todo--;
|
||||
} else {
|
||||
ctx = ctxbuf;
|
||||
for (c = nch; c > 0; c--) {
|
||||
s = ctx[ctx_start ^ 1];
|
||||
ds = ctx[ctx_start] - s;
|
||||
ctx += RESAMP_NCTX;
|
||||
*odata++ = s + ADATA_MULDIV(ds, diff, oblksz);
|
||||
|
||||
for (c = 0; c < nch; c++)
|
||||
f[c] = 0;
|
||||
|
||||
q = diff * p->filt_step;
|
||||
n = ctx_start;
|
||||
|
||||
while (q < RESAMP_LENGTH) {
|
||||
qi = q >> RESAMP_STEP_BITS;
|
||||
qf = q & (RESAMP_STEP - 1);
|
||||
s = resamp_filt[qi];
|
||||
ds = resamp_filt[qi + 1] - s;
|
||||
s += (int64_t)qf * ds >> RESAMP_STEP_BITS;
|
||||
ctx = ctxbuf;
|
||||
for (c = 0; c < nch; c++) {
|
||||
f[c] += (int64_t)ctx[n] * s;
|
||||
ctx += RESAMP_NCTX;
|
||||
}
|
||||
q += p->filt_cutoff;
|
||||
n = (n + 1) & (RESAMP_NCTX - 1);
|
||||
}
|
||||
|
||||
for (c = 0; c < nch; c++) {
|
||||
s = f[c] >> RESAMP_BITS;
|
||||
s = (int64_t)s * p->filt_cutoff >> RESAMP_BITS;
|
||||
#if ADATA_BITS == 16
|
||||
/*
|
||||
* In 16-bit mode, we've no room for filter
|
||||
* overshoots, so we need to clip the signal
|
||||
* to avoid 16-bit integers to wrap around.
|
||||
* In 24-bit mode, samples may exceed the
|
||||
* [-1:1] range. Later, cmap_add() will clip
|
||||
* them, so no need to clip them here as well.
|
||||
*/
|
||||
if (s >= ADATA_UNIT)
|
||||
s = ADATA_UNIT - 1;
|
||||
else if (s < -ADATA_UNIT)
|
||||
s = -ADATA_UNIT;
|
||||
#endif
|
||||
*odata++ = s;
|
||||
}
|
||||
diff += iblksz;
|
||||
}
|
||||
|
@ -273,6 +380,13 @@ resamp_init(struct resamp *p, unsigned int iblksz,
|
|||
p->nch = nch;
|
||||
p->ctx_start = 0;
|
||||
memset(p->ctx, 0, sizeof(p->ctx));
|
||||
if (p->iblksz < p->oblksz) {
|
||||
p->filt_cutoff = RESAMP_UNIT;
|
||||
p->filt_step = RESAMP_UNIT / p->oblksz;
|
||||
} else {
|
||||
p->filt_cutoff = (int64_t)RESAMP_UNIT * p->oblksz / p->iblksz;
|
||||
p->filt_step = RESAMP_UNIT / p->iblksz;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 3) {
|
||||
log_puts("resamp: ");
|
||||
|
|
71
sndiod/dsp.h
71
sndiod/dsp.h
|
@ -40,57 +40,43 @@ typedef short adata_t;
|
|||
|
||||
#elif ADATA_BITS == 24
|
||||
|
||||
#if defined(__i386__) && defined(__GNUC__)
|
||||
|
||||
static inline int
|
||||
fp24_mul(int x, int a)
|
||||
{
|
||||
int res;
|
||||
|
||||
asm volatile (
|
||||
"imull %2\n\t"
|
||||
"shrdl $23, %%edx, %%eax\n\t"
|
||||
: "=a" (res)
|
||||
: "a" (x), "r" (a)
|
||||
: "%edx"
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
fp24_muldiv(int x, int a, int b)
|
||||
{
|
||||
int res;
|
||||
|
||||
asm volatile (
|
||||
"imull %2\n\t"
|
||||
"idivl %3\n\t"
|
||||
: "=a" (res)
|
||||
: "a" (x), "d" (a), "r" (b)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define ADATA_MUL(x,y) fp24_mul(x, y)
|
||||
#define ADATA_MULDIV(x,y,z) fp24_muldiv(x, y, z);
|
||||
|
||||
#elif defined(__amd64__) || defined(__sparc64__)
|
||||
|
||||
#define ADATA_MUL(x,y) \
|
||||
((int)(((long long)(x) * (long long)(y)) >> (ADATA_BITS - 1)))
|
||||
#define ADATA_MULDIV(x,y,z) \
|
||||
((int)((long long)(x) * (long long)(y) / (long long)(z)))
|
||||
|
||||
#else
|
||||
#error "no 24-bit code for this architecture"
|
||||
#endif
|
||||
|
||||
typedef int adata_t;
|
||||
|
||||
#else
|
||||
#error "only 16-bit and 24-bit precisions are supported"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The FIR is sampled and stored in a table of fixed-point numbers
|
||||
* with 23 fractional bits. For convenience, we use the same fixed-point
|
||||
* numbers to represent time and to walk through the table.
|
||||
*/
|
||||
#define RESAMP_BITS 23
|
||||
#define RESAMP_UNIT (1 << RESAMP_BITS)
|
||||
|
||||
/*
|
||||
* Filter window length (the time unit is RESAMP_UNIT)
|
||||
*/
|
||||
#define RESAMP_LENGTH (8 * RESAMP_UNIT)
|
||||
|
||||
/*
|
||||
* Time between samples of the FIR (the time unit is RESAMP_UNIT)
|
||||
*/
|
||||
#define RESAMP_STEP_BITS (RESAMP_BITS - 6)
|
||||
#define RESAMP_STEP (1 << RESAMP_STEP_BITS)
|
||||
|
||||
/*
|
||||
* Maximum downsample/upsample ratio we support, must be a power of two.
|
||||
* The ratio between the max and the min sample rates is 192kHz / 4kHz = 48,
|
||||
* so we can use 64
|
||||
*/
|
||||
#define RESAMP_RATIO 64
|
||||
|
||||
/*
|
||||
* Maximum size of the encording string (the longest possible
|
||||
* encoding is ``s24le3msb'').
|
||||
|
@ -111,9 +97,10 @@ struct aparams {
|
|||
};
|
||||
|
||||
struct resamp {
|
||||
#define RESAMP_NCTX 2
|
||||
#define RESAMP_NCTX (RESAMP_LENGTH / RESAMP_UNIT * RESAMP_RATIO)
|
||||
unsigned int ctx_start;
|
||||
adata_t ctx[NCHAN_MAX * RESAMP_NCTX];
|
||||
int filt_cutoff, filt_step;
|
||||
unsigned int iblksz, oblksz;
|
||||
int nch;
|
||||
};
|
||||
|
@ -137,7 +124,7 @@ struct cmap {
|
|||
};
|
||||
|
||||
#define MIDI_TO_ADATA(m) (aparams_ctltovol[m] << (ADATA_BITS - 16))
|
||||
extern int aparams_ctltovol[128];
|
||||
extern const int aparams_ctltovol[128];
|
||||
|
||||
void aparams_init(struct aparams *);
|
||||
void aparams_log(struct aparams *);
|
||||
|
|
|
@ -55,8 +55,8 @@ struct midithru {
|
|||
/*
|
||||
* length of voice and common messages (status byte included)
|
||||
*/
|
||||
unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
|
||||
unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
|
||||
const unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
|
||||
const unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
|
||||
|
||||
void
|
||||
midi_log(struct midi *ep)
|
||||
|
@ -418,6 +418,22 @@ midi_out(struct midi *oep, unsigned char *idata, int icount)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* disconnect clients attached to this end-point
|
||||
*/
|
||||
void
|
||||
midi_abort(struct midi *p)
|
||||
{
|
||||
int i;
|
||||
struct midi *ep;
|
||||
|
||||
for (i = 0; i < MIDI_NEP; i++) {
|
||||
ep = midi_ep + i;
|
||||
if ((ep->txmask & p->self) || (p->txmask & ep->self))
|
||||
ep->ops->exit(ep->arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
port_log(struct port *p)
|
||||
{
|
||||
|
@ -467,7 +483,7 @@ port_exit(void *arg)
|
|||
struct port *
|
||||
port_new(char *path, unsigned int mode, int hold)
|
||||
{
|
||||
struct port *c;
|
||||
struct port *c, **pc;
|
||||
|
||||
c = xmalloc(sizeof(struct port));
|
||||
c->path_list = NULL;
|
||||
|
@ -476,8 +492,10 @@ port_new(char *path, unsigned int mode, int hold)
|
|||
c->hold = hold;
|
||||
c->midi = midi_new(&port_midiops, c, mode);
|
||||
c->num = midi_portnum++;
|
||||
c->next = port_list;
|
||||
port_list = c;
|
||||
for (pc = &port_list; *pc != NULL; pc = &(*pc)->next)
|
||||
;
|
||||
c->next = *pc;
|
||||
*pc = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -563,23 +581,6 @@ port_open(struct port *c)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
port_abort(struct port *c)
|
||||
{
|
||||
int i;
|
||||
struct midi *ep;
|
||||
|
||||
for (i = 0; i < MIDI_NEP; i++) {
|
||||
ep = midi_ep + i;
|
||||
if ((ep->txmask & c->midi->self) ||
|
||||
(c->midi->txmask & ep->self))
|
||||
ep->ops->exit(ep->arg);
|
||||
}
|
||||
|
||||
if (c->state != PORT_CFG)
|
||||
port_close(c);
|
||||
}
|
||||
|
||||
int
|
||||
port_close(struct port *c)
|
||||
{
|
||||
|
|
|
@ -112,6 +112,7 @@ void midi_fill(struct midi *);
|
|||
void midi_tag(struct midi *, unsigned int);
|
||||
unsigned int midi_tags(struct midi *);
|
||||
void midi_link(struct midi *, struct midi *);
|
||||
void midi_abort(struct midi *);
|
||||
|
||||
void port_log(struct port *);
|
||||
struct port *port_new(char *, unsigned int, int);
|
||||
|
@ -124,6 +125,5 @@ void port_done(struct port *);
|
|||
void port_drain(struct port *);
|
||||
int port_close(struct port *);
|
||||
int port_reopen(struct port *);
|
||||
void port_abort(struct port *);
|
||||
|
||||
#endif /* !defined(MIDI_H) */
|
||||
|
|
|
@ -186,6 +186,9 @@ port_mio_hup(void *arg)
|
|||
{
|
||||
struct port *p = arg;
|
||||
|
||||
if (!port_reopen(p))
|
||||
port_abort(p);
|
||||
if (!port_reopen(p)) {
|
||||
midi_abort(p->midi);
|
||||
if (p->state != PORT_CFG)
|
||||
port_close(p);
|
||||
}
|
||||
}
|
||||
|
|
217
sndiod/opt.c
217
sndiod/opt.c
|
@ -17,9 +17,154 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "dev.h"
|
||||
#include "midi.h"
|
||||
#include "opt.h"
|
||||
#include "sysex.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct opt *opt_list;
|
||||
|
||||
void opt_midi_imsg(void *, unsigned char *, int);
|
||||
void opt_midi_omsg(void *, unsigned char *, int);
|
||||
void opt_midi_fill(void *, int);
|
||||
void opt_midi_exit(void *);
|
||||
|
||||
struct midiops opt_midiops = {
|
||||
opt_midi_imsg,
|
||||
opt_midi_omsg,
|
||||
opt_midi_fill,
|
||||
opt_midi_exit
|
||||
};
|
||||
|
||||
void
|
||||
opt_midi_imsg(void *arg, unsigned char *msg, int len)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct opt *o = arg;
|
||||
|
||||
log_puts(o->name);
|
||||
log_puts(": can't receive midi messages\n");
|
||||
panic();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
opt_midi_omsg(void *arg, unsigned char *msg, int len)
|
||||
{
|
||||
struct opt *o = arg;
|
||||
struct sysex *x;
|
||||
unsigned int fps, chan;
|
||||
|
||||
if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
|
||||
chan = msg[0] & MIDI_CHANMASK;
|
||||
if (chan >= DEV_NSLOT)
|
||||
return;
|
||||
if (slot_array[chan].opt == NULL ||
|
||||
slot_array[chan].opt->dev != o->dev)
|
||||
return;
|
||||
slot_setvol(slot_array + chan, msg[2]);
|
||||
ctl_onval(CTL_SLOT_LEVEL, slot_array + chan, NULL, msg[2]);
|
||||
return;
|
||||
}
|
||||
x = (struct sysex *)msg;
|
||||
if (x->start != SYSEX_START)
|
||||
return;
|
||||
if (len < SYSEX_SIZE(empty))
|
||||
return;
|
||||
switch (x->type) {
|
||||
case SYSEX_TYPE_RT:
|
||||
if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
|
||||
if (len == SYSEX_SIZE(master)) {
|
||||
dev_master(o->dev, x->u.master.coarse);
|
||||
if (o->dev->master_enabled) {
|
||||
ctl_onval(CTL_DEV_MASTER, o->dev, NULL,
|
||||
x->u.master.coarse);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (x->id0 != SYSEX_MMC)
|
||||
return;
|
||||
switch (x->id1) {
|
||||
case SYSEX_MMC_STOP:
|
||||
if (len != SYSEX_SIZE(stop))
|
||||
return;
|
||||
if (o->mtc == NULL)
|
||||
return;
|
||||
if (log_level >= 2) {
|
||||
log_puts(o->name);
|
||||
log_puts(": mmc stop\n");
|
||||
}
|
||||
mtc_stop(o->mtc);
|
||||
break;
|
||||
case SYSEX_MMC_START:
|
||||
if (len != SYSEX_SIZE(start))
|
||||
return;
|
||||
if (o->mtc == NULL)
|
||||
return;
|
||||
if (log_level >= 2) {
|
||||
log_puts(o->name);
|
||||
log_puts(": mmc start\n");
|
||||
}
|
||||
mtc_start(o->mtc);
|
||||
break;
|
||||
case SYSEX_MMC_LOC:
|
||||
if (len != SYSEX_SIZE(loc) ||
|
||||
x->u.loc.len != SYSEX_MMC_LOC_LEN ||
|
||||
x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
|
||||
return;
|
||||
if (o->mtc == NULL)
|
||||
return;
|
||||
switch (x->u.loc.hr >> 5) {
|
||||
case MTC_FPS_24:
|
||||
fps = 24;
|
||||
break;
|
||||
case MTC_FPS_25:
|
||||
fps = 25;
|
||||
break;
|
||||
case MTC_FPS_30:
|
||||
fps = 30;
|
||||
break;
|
||||
default:
|
||||
mtc_stop(o->mtc);
|
||||
return;
|
||||
}
|
||||
mtc_loc(o->mtc,
|
||||
(x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
|
||||
x->u.loc.min * 60 * MTC_SEC +
|
||||
x->u.loc.sec * MTC_SEC +
|
||||
x->u.loc.fr * (MTC_SEC / fps));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SYSEX_TYPE_EDU:
|
||||
if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
|
||||
return;
|
||||
if (len != SYSEX_SIZE(dumpreq))
|
||||
return;
|
||||
dev_midi_dump(o->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opt_midi_fill(void *arg, int count)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
void
|
||||
opt_midi_exit(void *arg)
|
||||
{
|
||||
struct opt *o = arg;
|
||||
|
||||
if (log_level >= 1) {
|
||||
log_puts(o->name);
|
||||
log_puts(": midi end point died\n");
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new audio sub-device "configuration"
|
||||
*/
|
||||
|
@ -28,17 +173,10 @@ opt_new(struct dev *d, char *name,
|
|||
int pmin, int pmax, int rmin, int rmax,
|
||||
int maxweight, int mmc, int dup, unsigned int mode)
|
||||
{
|
||||
struct opt *o;
|
||||
unsigned int len;
|
||||
struct opt *o, **po;
|
||||
unsigned int len, num;
|
||||
char c;
|
||||
|
||||
if (opt_byname(d, name)) {
|
||||
dev_log(d);
|
||||
log_puts(".");
|
||||
log_puts(name);
|
||||
log_puts(": already defined\n");
|
||||
return NULL;
|
||||
}
|
||||
for (len = 0; name[len] != '\0'; len++) {
|
||||
if (len == OPT_NAMEMAX) {
|
||||
log_puts(name);
|
||||
|
@ -53,7 +191,49 @@ opt_new(struct dev *d, char *name,
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
num = 0;
|
||||
for (po = &opt_list; *po != NULL; po = &(*po)->next)
|
||||
num++;
|
||||
if (num >= OPT_NMAX) {
|
||||
log_puts(name);
|
||||
log_puts(": too many opts\n");
|
||||
return NULL;
|
||||
}
|
||||
if (opt_byname(d, name)) {
|
||||
dev_log(d);
|
||||
log_puts(".");
|
||||
log_puts(name);
|
||||
log_puts(": already defined\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mmc) {
|
||||
if (mtc_array[0].dev != NULL && mtc_array[0].dev != d) {
|
||||
log_puts(name);
|
||||
log_puts(": MTC already setup for another device\n");
|
||||
return NULL;
|
||||
}
|
||||
mtc_array[0].dev = d;
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": initial MTC source, controlled by MMC\n");
|
||||
}
|
||||
}
|
||||
|
||||
o = xmalloc(sizeof(struct opt));
|
||||
o->num = num;
|
||||
o->dev = d;
|
||||
|
||||
/*
|
||||
* XXX: below, we allocate a midi input buffer, since we don't
|
||||
* receive raw midi data, so no need to allocate a input
|
||||
* ibuf. Possibly set imsg & fill callbacks to NULL and
|
||||
* use this to in midi_new() to check if buffers need to be
|
||||
* allocated
|
||||
*/
|
||||
o->midi = midi_new(&opt_midiops, o, MODE_MIDIIN | MODE_MIDIOUT);
|
||||
midi_tag(o->midi, o->num);
|
||||
|
||||
if (mode & MODE_PLAY) {
|
||||
o->pmin = pmin;
|
||||
o->pmax = pmax;
|
||||
|
@ -63,12 +243,12 @@ opt_new(struct dev *d, char *name,
|
|||
o->rmax = rmax;
|
||||
}
|
||||
o->maxweight = maxweight;
|
||||
o->mmc = mmc;
|
||||
o->mtc = mmc ? &mtc_array[0] : NULL;
|
||||
o->dup = dup;
|
||||
o->mode = mode;
|
||||
memcpy(o->name, name, len + 1);
|
||||
o->next = d->opt_list;
|
||||
d->opt_list = o;
|
||||
o->next = *po;
|
||||
*po = o;
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(".");
|
||||
|
@ -95,8 +275,8 @@ opt_new(struct dev *d, char *name,
|
|||
log_putu(o->rmax);
|
||||
}
|
||||
if (o->mode & (MODE_RECMASK | MODE_PLAY)) {
|
||||
if (o->mmc)
|
||||
log_puts(" mmc");
|
||||
if (o->mtc)
|
||||
log_puts(" mtc");
|
||||
if (o->dup)
|
||||
log_puts(" dup");
|
||||
}
|
||||
|
@ -110,7 +290,9 @@ opt_byname(struct dev *d, char *name)
|
|||
{
|
||||
struct opt *o;
|
||||
|
||||
for (o = d->opt_list; o != NULL; o = o->next) {
|
||||
for (o = opt_list; o != NULL; o = o->next) {
|
||||
if (d != NULL && o->dev != d)
|
||||
continue;
|
||||
if (strcmp(name, o->name) == 0)
|
||||
return o;
|
||||
}
|
||||
|
@ -118,11 +300,11 @@ opt_byname(struct dev *d, char *name)
|
|||
}
|
||||
|
||||
void
|
||||
opt_del(struct dev *d, struct opt *o)
|
||||
opt_del(struct opt *o)
|
||||
{
|
||||
struct opt **po;
|
||||
|
||||
for (po = &d->opt_list; *po != o; po = &(*po)->next) {
|
||||
for (po = &opt_list; *po != o; po = &(*po)->next) {
|
||||
#ifdef DEBUG
|
||||
if (*po == NULL) {
|
||||
log_puts("opt_del: not on list\n");
|
||||
|
@ -130,6 +312,7 @@ opt_del(struct dev *d, struct opt *o)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
midi_del(o->midi);
|
||||
*po = o->next;
|
||||
xfree(o);
|
||||
}
|
||||
|
|
22
sndiod/opt.h
22
sndiod/opt.h
|
@ -17,11 +17,31 @@
|
|||
#ifndef OPT_H
|
||||
#define OPT_H
|
||||
|
||||
#define OPT_NMAX 16
|
||||
|
||||
struct dev;
|
||||
|
||||
struct opt {
|
||||
struct opt *next;
|
||||
struct dev *dev;
|
||||
struct midi *midi;
|
||||
struct mtc *mtc; /* if set, MMC-controlled MTC source */
|
||||
|
||||
int num;
|
||||
#define OPT_NAMEMAX 11
|
||||
char name[OPT_NAMEMAX + 1];
|
||||
int maxweight; /* max dynamic range for clients */
|
||||
int pmin, pmax; /* play channels */
|
||||
int rmin, rmax; /* recording channels */
|
||||
int dup; /* true if join/expand enabled */
|
||||
int mode; /* bitmap of MODE_XXX */
|
||||
};
|
||||
|
||||
extern struct opt *opt_list;
|
||||
|
||||
struct opt *opt_new(struct dev *, char *, int, int, int, int,
|
||||
int, int, int, unsigned int);
|
||||
void opt_del(struct dev *, struct opt *);
|
||||
void opt_del(struct opt *);
|
||||
struct opt *opt_byname(struct dev *, char *);
|
||||
|
||||
#endif /* !defined(OPT_H) */
|
||||
|
|
180
sndiod/siofile.c
180
sndiod/siofile.c
|
@ -86,76 +86,24 @@ dev_sio_timeout(void *arg)
|
|||
dev_abort(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device using one of the provided paths
|
||||
*/
|
||||
static struct sio_hdl *
|
||||
dev_sio_openlist(struct dev *d, unsigned int mode, struct sioctl_hdl **rctlhdl)
|
||||
static int
|
||||
dev_sio_openalt(struct dev *d, struct dev_alt *n,
|
||||
struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
|
||||
{
|
||||
struct dev_alt *n;
|
||||
struct sio_hdl *hdl;
|
||||
struct sioctl_hdl *ctlhdl;
|
||||
struct ctl *c;
|
||||
int val;
|
||||
unsigned int mode = d->reqmode & (MODE_PLAY | MODE_REC);
|
||||
|
||||
for (n = d->alt_list; n != NULL; n = n->next) {
|
||||
if (d->alt_num == n->idx)
|
||||
continue;
|
||||
hdl = sio_open(n->name, mode, 1);
|
||||
if (hdl != NULL) {
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": using ");
|
||||
log_puts(n->name);
|
||||
log_puts("\n");
|
||||
}
|
||||
ctlhdl = sioctl_open(n->name,
|
||||
SIOCTL_READ | SIOCTL_WRITE, 0);
|
||||
if (ctlhdl == NULL) {
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": no control device\n");
|
||||
}
|
||||
}
|
||||
d->alt_num = n->idx;
|
||||
for (c = d->ctl_list; c != NULL; c = c->next) {
|
||||
if (c->addr < CTLADDR_ALT_SEL ||
|
||||
c->addr >= CTLADDR_ALT_SEL + DEV_NMAX)
|
||||
continue;
|
||||
val = (c->addr - CTLADDR_ALT_SEL) == n->idx;
|
||||
if (c->curval == val)
|
||||
continue;
|
||||
c->curval = val;
|
||||
if (val)
|
||||
c->val_mask = ~0U;
|
||||
}
|
||||
*rctlhdl = ctlhdl;
|
||||
return hdl;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device.
|
||||
*/
|
||||
int
|
||||
dev_sio_open(struct dev *d)
|
||||
{
|
||||
struct sio_par par;
|
||||
unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
|
||||
|
||||
d->sio.hdl = dev_sio_openlist(d, mode, &d->sioctl.hdl);
|
||||
if (d->sio.hdl == NULL) {
|
||||
hdl = sio_open(n->name, mode, 1);
|
||||
if (hdl == NULL) {
|
||||
if (mode != (SIO_PLAY | SIO_REC))
|
||||
return 0;
|
||||
d->sio.hdl = dev_sio_openlist(d, SIO_PLAY, &d->sioctl.hdl);
|
||||
if (d->sio.hdl != NULL)
|
||||
hdl = sio_open(n->name, SIO_PLAY, 1);
|
||||
if (hdl != NULL)
|
||||
mode = SIO_PLAY;
|
||||
else {
|
||||
d->sio.hdl = dev_sio_openlist(d,
|
||||
SIO_REC, &d->sioctl.hdl);
|
||||
if (d->sio.hdl != NULL)
|
||||
hdl = sio_open(n->name, SIO_REC, 1);
|
||||
if (hdl != NULL)
|
||||
mode = SIO_REC;
|
||||
else
|
||||
return 0;
|
||||
|
@ -166,15 +114,85 @@ dev_sio_open(struct dev *d)
|
|||
log_puts(" mode\n");
|
||||
}
|
||||
}
|
||||
|
||||
ctlhdl = sioctl_open(n->name, SIOCTL_READ | SIOCTL_WRITE, 0);
|
||||
if (ctlhdl == NULL) {
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": no control device\n");
|
||||
}
|
||||
}
|
||||
|
||||
*rhdl = hdl;
|
||||
*rctlhdl = ctlhdl;
|
||||
*rmode = mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device using one of the provided paths
|
||||
*/
|
||||
static int
|
||||
dev_sio_openlist(struct dev *d,
|
||||
struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
|
||||
{
|
||||
struct dev_alt *n;
|
||||
struct ctl *c;
|
||||
int val;
|
||||
|
||||
for (n = d->alt_list; n != NULL; n = n->next) {
|
||||
if (d->alt_num == n->idx)
|
||||
continue;
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": trying ");
|
||||
log_puts(n->name);
|
||||
log_puts("\n");
|
||||
}
|
||||
if (dev_sio_openalt(d, n, rhdl, rctlhdl, rmode)) {
|
||||
if (log_level >= 2) {
|
||||
dev_log(d);
|
||||
log_puts(": using ");
|
||||
log_puts(n->name);
|
||||
log_puts("\n");
|
||||
}
|
||||
d->alt_num = n->idx;
|
||||
for (c = ctl_list; c != NULL; c = c->next) {
|
||||
if (!ctl_match(c, CTL_DEV_ALT, d, NULL))
|
||||
continue;
|
||||
val = c->u.dev_alt.idx == n->idx;
|
||||
if (c->curval == val)
|
||||
continue;
|
||||
c->curval = val;
|
||||
if (val)
|
||||
c->val_mask = ~0U;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device.
|
||||
*/
|
||||
int
|
||||
dev_sio_open(struct dev *d)
|
||||
{
|
||||
struct sio_par par;
|
||||
|
||||
if (!dev_sio_openlist(d, &d->sio.hdl, &d->sioctl.hdl, &d->mode))
|
||||
return 0;
|
||||
|
||||
sio_initpar(&par);
|
||||
par.bits = d->par.bits;
|
||||
par.bps = d->par.bps;
|
||||
par.sig = d->par.sig;
|
||||
par.le = d->par.le;
|
||||
par.msb = d->par.msb;
|
||||
if (mode & SIO_PLAY)
|
||||
if (d->mode & SIO_PLAY)
|
||||
par.pchan = d->pchan;
|
||||
if (mode & SIO_REC)
|
||||
if (d->mode & SIO_REC)
|
||||
par.rchan = d->rchan;
|
||||
if (d->bufsz)
|
||||
par.appbufsz = d->bufsz;
|
||||
|
@ -210,14 +228,14 @@ dev_sio_open(struct dev *d)
|
|||
log_puts(": unsupported sample size\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
|
||||
if ((d->mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.pchan);
|
||||
log_puts(": unsupported number of play channels\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) {
|
||||
if ((d->mode & SIO_REC) && par.rchan > NCHAN_MAX) {
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.rchan);
|
||||
|
@ -253,17 +271,15 @@ dev_sio_open(struct dev *d)
|
|||
d->par.sig = par.sig;
|
||||
d->par.le = par.le;
|
||||
d->par.msb = par.msb;
|
||||
if (mode & SIO_PLAY)
|
||||
if (d->mode & SIO_PLAY)
|
||||
d->pchan = par.pchan;
|
||||
if (mode & SIO_REC)
|
||||
if (d->mode & SIO_REC)
|
||||
d->rchan = par.rchan;
|
||||
d->bufsz = par.bufsz;
|
||||
d->round = par.round;
|
||||
d->rate = par.rate;
|
||||
if (!(mode & MODE_PLAY))
|
||||
d->mode &= ~(MODE_PLAY | MODE_MON);
|
||||
if (!(mode & MODE_REC))
|
||||
d->mode &= ~MODE_REC;
|
||||
if (d->mode & MODE_PLAY)
|
||||
d->mode |= MODE_MON;
|
||||
sio_onmove(d->sio.hdl, dev_sio_onmove, d);
|
||||
d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl));
|
||||
if (d->sioctl.hdl) {
|
||||
|
@ -290,18 +306,13 @@ dev_sio_open(struct dev *d)
|
|||
int
|
||||
dev_sio_reopen(struct dev *d)
|
||||
{
|
||||
struct sioctl_hdl *ctlhdl;
|
||||
struct sio_par par;
|
||||
struct sio_hdl *hdl;
|
||||
struct sioctl_hdl *ctlhdl;
|
||||
unsigned int mode;
|
||||
|
||||
hdl = dev_sio_openlist(d, d->mode & (MODE_PLAY | MODE_REC), &ctlhdl);
|
||||
if (hdl == NULL) {
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": couldn't open an alternate device\n");
|
||||
}
|
||||
if (!dev_sio_openlist(d, &hdl, &ctlhdl, &mode))
|
||||
return 0;
|
||||
}
|
||||
|
||||
sio_initpar(&par);
|
||||
par.bits = d->par.bits;
|
||||
|
@ -309,10 +320,10 @@ dev_sio_reopen(struct dev *d)
|
|||
par.sig = d->par.sig;
|
||||
par.le = d->par.le;
|
||||
par.msb = d->par.msb;
|
||||
if (d->mode & SIO_PLAY)
|
||||
par.pchan = d->pchan;
|
||||
if (d->mode & SIO_REC)
|
||||
par.rchan = d->rchan;
|
||||
if (mode & SIO_PLAY)
|
||||
par.pchan = d->reqpchan;
|
||||
if (mode & SIO_REC)
|
||||
par.rchan = d->reqrchan;
|
||||
par.appbufsz = d->bufsz;
|
||||
par.round = d->round;
|
||||
par.rate = d->rate;
|
||||
|
@ -342,6 +353,7 @@ dev_sio_reopen(struct dev *d)
|
|||
}
|
||||
|
||||
/* update parameters */
|
||||
d->mode = mode;
|
||||
d->par.bits = par.bits;
|
||||
d->par.bps = par.bps;
|
||||
d->par.sig = par.sig;
|
||||
|
|
|
@ -329,7 +329,7 @@ to audio programs.
|
|||
Unit number.
|
||||
Each
|
||||
.Nm
|
||||
server instance has an unique unit number,
|
||||
server instance has a unique unit number,
|
||||
used in
|
||||
.Xr sndio 7
|
||||
device names.
|
||||
|
@ -343,7 +343,7 @@ Reducing the volume in advance allows a client's volume to stay independent
|
|||
from the number of clients as long as their number is small enough.
|
||||
18 volume units (i.e. \-6dB attenuation) allows the number
|
||||
of playback programs to be doubled.
|
||||
The default is 118 i.e. \-3dB.
|
||||
The default is 127.
|
||||
.It Fl w Ar flag
|
||||
Control
|
||||
.Nm
|
||||
|
@ -355,11 +355,8 @@ option.
|
|||
If the flag is
|
||||
.Va on ,
|
||||
then the master volume is automatically adjusted to avoid clipping.
|
||||
Using
|
||||
.Va off
|
||||
makes sense in the rare situation where all programs lower their volumes.
|
||||
The default is
|
||||
.Va on .
|
||||
.Va off .
|
||||
.It Fl z Ar nframes
|
||||
The audio device block size in frames.
|
||||
This is the number of frames between audio clock ticks,
|
||||
|
|
|
@ -366,7 +366,7 @@ mkopt(char *path, struct dev *d,
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c, i, background, unit, devindex;
|
||||
int c, i, background, unit;
|
||||
int pmin, pmax, rmin, rmax;
|
||||
char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
|
||||
unsigned int mode, dup, mmc, vol;
|
||||
|
@ -387,11 +387,11 @@ main(int argc, char **argv)
|
|||
/*
|
||||
* global options defaults
|
||||
*/
|
||||
vol = 118;
|
||||
vol = 127;
|
||||
dup = 1;
|
||||
mmc = 0;
|
||||
hold = 0;
|
||||
autovol = 1;
|
||||
autovol = 0;
|
||||
bufsz = 0;
|
||||
round = 0;
|
||||
rate = DEFAULT_RATE;
|
||||
|
@ -404,7 +404,10 @@ main(int argc, char **argv)
|
|||
aparams_init(&par);
|
||||
mode = MODE_PLAY | MODE_REC;
|
||||
tcpaddr_list = NULL;
|
||||
devindex = 0;
|
||||
d = NULL;
|
||||
p = NULL;
|
||||
|
||||
slot_array_init();
|
||||
|
||||
while ((c = getopt(argc, argv,
|
||||
"a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
|
||||
|
@ -453,21 +456,24 @@ main(int argc, char **argv)
|
|||
errx(1, "%s: volume is %s", optarg, str);
|
||||
break;
|
||||
case 's':
|
||||
if ((d = dev_list) == NULL) {
|
||||
d = mkdev(default_devs[devindex++], &par, 0,
|
||||
bufsz, round, rate, hold, autovol);
|
||||
if (d == NULL) {
|
||||
for (i = 0; default_devs[i] != NULL; i++) {
|
||||
mkdev(default_devs[i], &par, 0,
|
||||
bufsz, round, rate, 0, autovol);
|
||||
}
|
||||
d = dev_list;
|
||||
}
|
||||
if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
|
||||
mode, vol, mmc, dup) == NULL)
|
||||
return 1;
|
||||
break;
|
||||
case 'q':
|
||||
mkport(optarg, hold);
|
||||
p = mkport(optarg, hold);
|
||||
break;
|
||||
case 'Q':
|
||||
if (port_list == NULL)
|
||||
if (p == NULL)
|
||||
errx(1, "-Q %s: no ports defined", optarg);
|
||||
namelist_add(&port_list->path_list, optarg);
|
||||
namelist_add(&p->path_list, optarg);
|
||||
break;
|
||||
case 'a':
|
||||
hold = opt_onoff();
|
||||
|
@ -486,12 +492,11 @@ main(int argc, char **argv)
|
|||
errx(1, "%s: block size is %s", optarg, str);
|
||||
break;
|
||||
case 'f':
|
||||
mkdev(optarg, &par, 0, bufsz, round,
|
||||
d = mkdev(optarg, &par, 0, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
devindex = -1;
|
||||
break;
|
||||
case 'F':
|
||||
if ((d = dev_list) == NULL)
|
||||
if (d == NULL)
|
||||
errx(1, "-F %s: no devices defined", optarg);
|
||||
if (!dev_addname(d, optarg))
|
||||
exit(1);
|
||||
|
@ -511,8 +516,8 @@ main(int argc, char **argv)
|
|||
for (i = 0; default_ports[i] != NULL; i++)
|
||||
mkport(default_ports[i], 0);
|
||||
}
|
||||
if (devindex != -1) {
|
||||
for (i = devindex; default_devs[i] != NULL; i++) {
|
||||
if (dev_list == NULL) {
|
||||
for (i = 0; default_devs[i] != NULL; i++) {
|
||||
mkdev(default_devs[i], &par, 0,
|
||||
bufsz, round, rate, 0, autovol);
|
||||
}
|
||||
|
@ -593,6 +598,8 @@ main(int argc, char **argv)
|
|||
; /* nothing */
|
||||
midi_done();
|
||||
|
||||
while (opt_list)
|
||||
opt_del(opt_list);
|
||||
while (dev_list)
|
||||
dev_del(dev_list);
|
||||
while (port_list)
|
||||
|
|
|
@ -114,7 +114,7 @@ sock_log(struct sock *f)
|
|||
midi_log(f->midi);
|
||||
else if (f->ctlslot) {
|
||||
log_puts("ctlslot");
|
||||
log_putu(f->ctlslot - f->ctlslot->dev->ctlslot);
|
||||
log_putu(f->ctlslot - ctlslot_array);
|
||||
} else
|
||||
log_puts("sock");
|
||||
#ifdef DEBUG
|
||||
|
@ -616,7 +616,7 @@ int
|
|||
sock_setpar(struct sock *f)
|
||||
{
|
||||
struct slot *s = f->slot;
|
||||
struct dev *d = s->dev;
|
||||
struct dev *d = s->opt->dev;
|
||||
struct amsg_par *p = &f->rmsg.u.par;
|
||||
unsigned int min, max;
|
||||
uint32_t rate, appbufsz;
|
||||
|
@ -748,7 +748,7 @@ sock_setpar(struct sock *f)
|
|||
return 0;
|
||||
}
|
||||
s->xrun = p->xrun;
|
||||
if (s->opt->mmc && s->xrun == XRUN_IGNORE)
|
||||
if (s->opt->mtc != NULL && s->xrun == XRUN_IGNORE)
|
||||
s->xrun = XRUN_SYNC;
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 3) {
|
||||
|
@ -869,9 +869,12 @@ sock_hello(struct sock *f)
|
|||
d = dev_bynum(p->devnum);
|
||||
if (d == NULL)
|
||||
return 0;
|
||||
opt = opt_byname(d, p->opt);
|
||||
if (opt == NULL)
|
||||
return 0;
|
||||
if (!dev_ref(d))
|
||||
return 0;
|
||||
midi_tag(f->midi, p->devnum);
|
||||
midi_tag(f->midi, opt->num);
|
||||
} else if (p->devnum < 32) {
|
||||
midi_tag(f->midi, p->devnum);
|
||||
} else if (p->devnum < 48) {
|
||||
|
@ -895,7 +898,10 @@ sock_hello(struct sock *f)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
f->ctlslot = ctlslot_new(d, &sock_ctlops, f);
|
||||
opt = opt_byname(d, p->opt);
|
||||
if (opt == NULL)
|
||||
return 0;
|
||||
f->ctlslot = ctlslot_new(opt, &sock_ctlops, f);
|
||||
if (f->ctlslot == NULL) {
|
||||
if (log_level >= 2) {
|
||||
sock_log(f);
|
||||
|
@ -915,7 +921,7 @@ sock_hello(struct sock *f)
|
|||
opt = opt_byname(d, p->opt);
|
||||
if (opt == NULL)
|
||||
return 0;
|
||||
f->slot = slot_new(d, opt, id, p->who, &sock_slotops, f, mode);
|
||||
f->slot = slot_new(opt, id, p->who, &sock_slotops, f, mode);
|
||||
if (f->slot == NULL)
|
||||
return 0;
|
||||
f->midi = NULL;
|
||||
|
@ -1130,7 +1136,7 @@ sock_execmsg(struct sock *f)
|
|||
f->ralign = s->round * s->mix.bpf;
|
||||
}
|
||||
}
|
||||
slot_stop(s);
|
||||
slot_stop(s, 1);
|
||||
break;
|
||||
case AMSG_SETPAR:
|
||||
#ifdef DEBUG
|
||||
|
@ -1225,9 +1231,8 @@ sock_execmsg(struct sock *f)
|
|||
f->rstate = SOCK_RMSG;
|
||||
f->lastvol = ctl; /* dont trigger feedback message */
|
||||
slot_setvol(s, ctl);
|
||||
dev_midi_vol(s->dev, s);
|
||||
dev_onval(s->dev,
|
||||
CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl);
|
||||
dev_midi_vol(s->opt->dev, s);
|
||||
ctl_onval(CTL_SLOT_LEVEL, s, NULL, ctl);
|
||||
break;
|
||||
case AMSG_CTLSUB:
|
||||
#ifdef DEBUG
|
||||
|
@ -1252,10 +1257,11 @@ sock_execmsg(struct sock *f)
|
|||
}
|
||||
if (m->u.ctlsub.desc) {
|
||||
if (!(f->ctlops & SOCK_CTLDESC)) {
|
||||
ctl = f->ctlslot->mask;
|
||||
c = f->ctlslot->dev->ctl_list;
|
||||
ctl = f->ctlslot->self;
|
||||
c = ctl_list;
|
||||
while (c != NULL) {
|
||||
c->desc_mask |= ctl;
|
||||
if (ctlslot_visible(f->ctlslot, c))
|
||||
c->desc_mask |= ctl;
|
||||
c = c->next;
|
||||
}
|
||||
f->ctlops |= SOCK_CTLDESC;
|
||||
|
@ -1287,13 +1293,23 @@ sock_execmsg(struct sock *f)
|
|||
sock_close(f);
|
||||
return 0;
|
||||
}
|
||||
if (!dev_setctl(f->ctlslot->dev,
|
||||
ntohs(m->u.ctlset.addr),
|
||||
ntohs(m->u.ctlset.val))) {
|
||||
|
||||
c = ctlslot_lookup(f->ctlslot, ntohs(m->u.ctlset.addr));
|
||||
if (c == NULL) {
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 1) {
|
||||
sock_log(f);
|
||||
log_puts(": CTLSET, wrong addr/val\n");
|
||||
log_puts(": CTLSET, wrong addr\n");
|
||||
}
|
||||
#endif
|
||||
sock_close(f);
|
||||
return 0;
|
||||
}
|
||||
if (!ctl_setval(c, ntohs(m->u.ctlset.val))) {
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 1) {
|
||||
sock_log(f);
|
||||
log_puts(": CTLSET, bad value\n");
|
||||
}
|
||||
#endif
|
||||
sock_close(f);
|
||||
|
@ -1389,7 +1405,7 @@ sock_execmsg(struct sock *f)
|
|||
int
|
||||
sock_buildmsg(struct sock *f)
|
||||
{
|
||||
unsigned int size, mask;
|
||||
unsigned int size, type, mask;
|
||||
struct amsg_ctl_desc *desc;
|
||||
struct ctl *c, **pc;
|
||||
|
||||
|
@ -1539,9 +1555,9 @@ sock_buildmsg(struct sock *f)
|
|||
*/
|
||||
if (f->ctlslot && (f->ctlops & SOCK_CTLDESC)) {
|
||||
desc = f->ctldesc;
|
||||
mask = f->ctlslot->mask;
|
||||
mask = f->ctlslot->self;
|
||||
size = 0;
|
||||
pc = &f->ctlslot->dev->ctl_list;
|
||||
pc = &ctl_list;
|
||||
while ((c = *pc) != NULL) {
|
||||
if ((c->desc_mask & mask) == 0 ||
|
||||
(c->refs_mask & mask) == 0) {
|
||||
|
@ -1553,7 +1569,11 @@ sock_buildmsg(struct sock *f)
|
|||
break;
|
||||
c->desc_mask &= ~mask;
|
||||
c->val_mask &= ~mask;
|
||||
strlcpy(desc->group, c->group,
|
||||
type = ctlslot_visible(f->ctlslot, c) ?
|
||||
c->type : CTL_NONE;
|
||||
strlcpy(desc->group, (f->ctlslot->opt == NULL ||
|
||||
strcmp(c->group, f->ctlslot->opt->dev->name) != 0) ?
|
||||
c->group : "",
|
||||
AMSG_CTL_NAMEMAX);
|
||||
strlcpy(desc->node0.name, c->node0.name,
|
||||
AMSG_CTL_NAMEMAX);
|
||||
|
@ -1561,7 +1581,7 @@ sock_buildmsg(struct sock *f)
|
|||
strlcpy(desc->node1.name, c->node1.name,
|
||||
AMSG_CTL_NAMEMAX);
|
||||
desc->node1.unit = ntohs(c->node1.unit);
|
||||
desc->type = c->type;
|
||||
desc->type = type;
|
||||
strlcpy(desc->func, c->func, AMSG_CTL_NAMEMAX);
|
||||
desc->addr = htons(c->addr);
|
||||
desc->maxval = htons(c->maxval);
|
||||
|
@ -1570,7 +1590,7 @@ sock_buildmsg(struct sock *f)
|
|||
desc++;
|
||||
|
||||
/* if this is a deleted entry unref it */
|
||||
if (c->type == CTL_NONE) {
|
||||
if (type == CTL_NONE) {
|
||||
c->refs_mask &= ~mask;
|
||||
if (c->refs_mask == 0) {
|
||||
*pc = c->next;
|
||||
|
@ -1597,8 +1617,10 @@ sock_buildmsg(struct sock *f)
|
|||
}
|
||||
}
|
||||
if (f->ctlslot && (f->ctlops & SOCK_CTLVAL)) {
|
||||
mask = f->ctlslot->mask;
|
||||
for (c = f->ctlslot->dev->ctl_list; c != NULL; c = c->next) {
|
||||
mask = f->ctlslot->self;
|
||||
for (c = ctl_list; c != NULL; c = c->next) {
|
||||
if (!ctlslot_visible(f->ctlslot, c))
|
||||
continue;
|
||||
if ((c->val_mask & mask) == 0)
|
||||
continue;
|
||||
c->val_mask &= ~mask;
|
||||
|
|
Loading…
Reference in New Issue