1 |
|
|
/* |
2 |
|
|
* Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org> |
3 |
|
|
* |
4 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
5 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
6 |
|
|
* copyright notice and this permission notice appear in all copies. |
7 |
|
|
* |
8 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 |
|
|
*/ |
16 |
|
|
|
17 |
|
|
#include <errno.h> |
18 |
|
|
#include <limits.h> |
19 |
|
|
#include <poll.h> |
20 |
|
|
#include <signal.h> |
21 |
|
|
#include <sndio.h> |
22 |
|
|
#include <stdlib.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
#include <unistd.h> |
25 |
|
|
#include "abuf.h" |
26 |
|
|
#include "afile.h" |
27 |
|
|
#include "dsp.h" |
28 |
|
|
#include "sysex.h" |
29 |
|
|
#include "utils.h" |
30 |
|
|
|
31 |
|
|
/* |
32 |
|
|
* masks to extract command and channel of status byte |
33 |
|
|
*/ |
34 |
|
|
#define MIDI_CMDMASK 0xf0 |
35 |
|
|
#define MIDI_CHANMASK 0x0f |
36 |
|
|
|
37 |
|
|
/* |
38 |
|
|
* MIDI status bytes of voice messages |
39 |
|
|
*/ |
40 |
|
|
#define MIDI_NOFF 0x80 /* note off */ |
41 |
|
|
#define MIDI_NON 0x90 /* note on */ |
42 |
|
|
#define MIDI_KAT 0xa0 /* key after touch */ |
43 |
|
|
#define MIDI_CTL 0xb0 /* controller */ |
44 |
|
|
#define MIDI_PC 0xc0 /* program change */ |
45 |
|
|
#define MIDI_CAT 0xd0 /* channel after touch */ |
46 |
|
|
#define MIDI_BEND 0xe0 /* pitch bend */ |
47 |
|
|
#define MIDI_ACK 0xfe /* active sensing message */ |
48 |
|
|
|
49 |
|
|
/* |
50 |
|
|
* MIDI controller numbers |
51 |
|
|
*/ |
52 |
|
|
#define MIDI_CTL_VOL 7 |
53 |
|
|
|
54 |
|
|
/* |
55 |
|
|
* Max coarse value |
56 |
|
|
*/ |
57 |
|
|
#define MIDI_MAXCTL 127 |
58 |
|
|
|
59 |
|
|
/* |
60 |
|
|
* MIDI status bytes for sysex |
61 |
|
|
*/ |
62 |
|
|
#define MIDI_SX_START 0xf0 |
63 |
|
|
#define MIDI_SX_STOP 0xf7 |
64 |
|
|
|
65 |
|
|
/* |
66 |
|
|
* audio device defaults |
67 |
|
|
*/ |
68 |
|
|
#define DEFAULT_RATE 48000 |
69 |
|
|
#define DEFAULT_BUFSZ_MS 200 |
70 |
|
|
|
71 |
|
|
struct slot { |
72 |
|
|
struct slot *next; /* next on the play/rec list */ |
73 |
|
|
int vol; /* dynamic range */ |
74 |
|
|
int volctl; /* volume in the 0..127 range */ |
75 |
|
|
struct abuf buf; /* file i/o buffer */ |
76 |
|
|
int bpf; /* bytes per frame */ |
77 |
|
|
int cmin, cmax; /* file channel range */ |
78 |
|
|
struct cmap cmap; /* channel mapper state */ |
79 |
|
|
struct resamp resamp; /* resampler state */ |
80 |
|
|
struct conv conv; /* format encoder state */ |
81 |
|
|
int join; /* channel join factor */ |
82 |
|
|
int expand; /* channel expand factor */ |
83 |
|
|
void *resampbuf, *convbuf; /* conversion tmp buffers */ |
84 |
|
|
int dup; /* mono-to-stereo and alike */ |
85 |
|
|
int round; /* slot-side block size */ |
86 |
|
|
int mode; /* MODE_{PLAY,REC} */ |
87 |
|
|
#define SLOT_CFG 0 /* buffers not allocated yet */ |
88 |
|
|
#define SLOT_INIT 1 /* not trying to do anything */ |
89 |
|
|
#define SLOT_RUN 2 /* playing/recording */ |
90 |
|
|
#define SLOT_STOP 3 /* draining (play only) */ |
91 |
|
|
int pstate; /* one of above */ |
92 |
|
|
long long skip; /* frames to skip at the beginning */ |
93 |
|
|
long long pos; /* start position (at device rate) */ |
94 |
|
|
struct afile afile; /* file desc & friends */ |
95 |
|
|
}; |
96 |
|
|
|
97 |
|
|
/* |
98 |
|
|
* device properties |
99 |
|
|
*/ |
100 |
|
|
unsigned int dev_mode; /* bitmap of SIO_{PLAY,REC} */ |
101 |
|
|
unsigned int dev_bufsz; /* device buffer size */ |
102 |
|
|
unsigned int dev_round; /* device block size */ |
103 |
|
|
int dev_rate; /* device sample rate (Hz) */ |
104 |
|
|
unsigned int dev_pchan, dev_rchan; /* play & rec channels count */ |
105 |
|
|
adata_t *dev_pbuf, *dev_rbuf; /* play & rec buffers */ |
106 |
|
|
long long dev_pos; /* last MMC position in frames */ |
107 |
|
|
#define DEV_STOP 0 /* stopped */ |
108 |
|
|
#define DEV_START 1 /* started */ |
109 |
|
|
unsigned int dev_pstate; /* one of above */ |
110 |
|
|
char *dev_name; /* device sndio(7) name */ |
111 |
|
|
char *dev_port; /* control port sndio(7) name */ |
112 |
|
|
struct sio_hdl *dev_sh; /* device handle */ |
113 |
|
|
struct mio_hdl *dev_mh; /* MIDI control port handle */ |
114 |
|
|
unsigned int dev_volctl = MIDI_MAXCTL; /* master volume */ |
115 |
|
|
|
116 |
|
|
/* |
117 |
|
|
* MIDI parser state |
118 |
|
|
*/ |
119 |
|
|
#define MIDI_MSGMAX 32 /* max size of MIDI msg */ |
120 |
|
|
unsigned char dev_msg[MIDI_MSGMAX]; /* parsed input message */ |
121 |
|
|
unsigned int dev_mst; /* input MIDI running status */ |
122 |
|
|
unsigned int dev_mused; /* bytes used in ``msg'' */ |
123 |
|
|
unsigned int dev_midx; /* current ``msg'' size */ |
124 |
|
|
unsigned int dev_mlen; /* expected ``msg'' length */ |
125 |
|
|
unsigned int dev_prime; /* blocks to write to start */ |
126 |
|
|
|
127 |
|
|
unsigned int log_level = 1; |
128 |
|
|
volatile sig_atomic_t quit_flag = 0; |
129 |
|
|
struct slot *slot_list = NULL; |
130 |
|
|
|
131 |
|
|
/* |
132 |
|
|
* length of voice and common MIDI messages (status byte included) |
133 |
|
|
*/ |
134 |
|
|
unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; |
135 |
|
|
unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; |
136 |
|
|
|
137 |
|
|
char usagestr[] = "usage: aucat [-dn] [-b size] " |
138 |
|
|
"[-c min:max] [-e enc] [-f device] [-g position]\n\t" |
139 |
|
|
"[-h fmt] [-i file] [-j flag] [-o file] [-p position] [-q port]\n\t" |
140 |
|
|
"[-r rate] [-v volume]\n"; |
141 |
|
|
|
142 |
|
|
static void |
143 |
|
|
slot_log(struct slot *s) |
144 |
|
|
{ |
145 |
|
|
#ifdef DEBUG |
146 |
|
|
static char *pstates[] = { |
147 |
|
|
"cfg", "ini", "run", "stp" |
148 |
|
|
}; |
149 |
|
|
#endif |
150 |
|
|
log_puts(s->afile.path); |
151 |
|
|
#ifdef DEBUG |
152 |
|
|
if (log_level >= 3) { |
153 |
|
|
log_puts(",pst="); |
154 |
|
|
log_puts(pstates[s->pstate]); |
155 |
|
|
} |
156 |
|
|
#endif |
157 |
|
|
} |
158 |
|
|
|
159 |
|
|
static void |
160 |
|
|
slot_flush(struct slot *s) |
161 |
|
|
{ |
162 |
|
|
int count, n; |
163 |
|
|
unsigned char *data; |
164 |
|
|
|
165 |
|
|
for (;;) { |
166 |
|
|
data = abuf_rgetblk(&s->buf, &count); |
167 |
|
|
if (count == 0) |
168 |
|
|
break; |
169 |
|
|
n = afile_write(&s->afile, data, count); |
170 |
|
|
if (n == 0) { |
171 |
|
|
slot_log(s); |
172 |
|
|
log_puts(": can't write, disabled\n"); |
173 |
|
|
s->pstate = SLOT_INIT; |
174 |
|
|
return; |
175 |
|
|
} |
176 |
|
|
abuf_rdiscard(&s->buf, n); |
177 |
|
|
} |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
static void |
181 |
|
|
slot_fill(struct slot *s) |
182 |
|
|
{ |
183 |
|
|
int count, n; |
184 |
|
|
unsigned char *data; |
185 |
|
|
|
186 |
|
|
for (;;) { |
187 |
|
|
data = abuf_wgetblk(&s->buf, &count); |
188 |
|
|
if (count == 0) |
189 |
|
|
break; |
190 |
|
|
n = afile_read(&s->afile, data, count); |
191 |
|
|
if (n == 0) { |
192 |
|
|
#ifdef DEBUG |
193 |
|
|
if (log_level >= 3) { |
194 |
|
|
slot_log(s); |
195 |
|
|
log_puts(": eof reached, stopping\n"); |
196 |
|
|
} |
197 |
|
|
#endif |
198 |
|
|
s->pstate = SLOT_STOP; |
199 |
|
|
break; |
200 |
|
|
} |
201 |
|
|
abuf_wcommit(&s->buf, n); |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
static int |
206 |
|
|
slot_new(char *path, int mode, struct aparams *par, int hdr, |
207 |
|
|
int cmin, int cmax, int rate, int dup, int vol, long long pos) |
208 |
|
|
{ |
209 |
|
|
struct slot *s; |
210 |
|
|
|
211 |
|
|
s = xmalloc(sizeof(struct slot)); |
212 |
|
|
if (!afile_open(&s->afile, path, hdr, |
213 |
|
|
mode == SIO_PLAY ? AFILE_FREAD : AFILE_FWRITE, |
214 |
|
|
par, rate, cmax - cmin + 1)) { |
215 |
|
|
xfree(s); |
216 |
|
|
return 0; |
217 |
|
|
} |
218 |
|
|
s->cmin = cmin; |
219 |
|
|
s->cmax = cmin + s->afile.nch - 1; |
220 |
|
|
s->dup = dup; |
221 |
|
|
s->vol = MIDI_TO_ADATA(vol); |
222 |
|
|
s->mode = mode; |
223 |
|
|
s->pstate = SLOT_CFG; |
224 |
|
|
s->pos = pos; |
225 |
|
|
if (log_level >= 2) { |
226 |
|
|
slot_log(s); |
227 |
|
|
log_puts(": "); |
228 |
|
|
log_puts(s->mode == SIO_PLAY ? "play" : "rec"); |
229 |
|
|
log_puts(", chan "); |
230 |
|
|
log_putu(s->cmin); |
231 |
|
|
log_puts(":"); |
232 |
|
|
log_putu(s->cmax); |
233 |
|
|
log_puts(", "); |
234 |
|
|
log_putu(s->afile.rate); |
235 |
|
|
log_puts("Hz, "); |
236 |
|
|
switch (s->afile.fmt) { |
237 |
|
|
case AFILE_FMT_PCM: |
238 |
|
|
aparams_log(&s->afile.par); |
239 |
|
|
break; |
240 |
|
|
case AFILE_FMT_ULAW: |
241 |
|
|
log_puts("ulaw"); |
242 |
|
|
break; |
243 |
|
|
case AFILE_FMT_ALAW: |
244 |
|
|
log_puts("alaw"); |
245 |
|
|
break; |
246 |
|
|
case AFILE_FMT_FLOAT: |
247 |
|
|
log_puts("f32le"); |
248 |
|
|
break; |
249 |
|
|
} |
250 |
|
|
if (s->mode == SIO_PLAY && s->afile.endpos >= 0) { |
251 |
|
|
log_puts(", bytes "); |
252 |
|
|
log_puti(s->afile.startpos); |
253 |
|
|
log_puts(".."); |
254 |
|
|
log_puti(s->afile.endpos); |
255 |
|
|
} |
256 |
|
|
if (s->mode == SIO_PLAY) { |
257 |
|
|
log_puts(", vol "); |
258 |
|
|
log_puti(s->vol); |
259 |
|
|
} |
260 |
|
|
log_puts("\n"); |
261 |
|
|
} |
262 |
|
|
s->next = slot_list; |
263 |
|
|
slot_list = s; |
264 |
|
|
return 1; |
265 |
|
|
} |
266 |
|
|
|
267 |
|
|
static void |
268 |
|
|
slot_init(struct slot *s) |
269 |
|
|
{ |
270 |
|
|
unsigned int slot_nch, bufsz; |
271 |
|
|
|
272 |
|
|
#ifdef DEBUG |
273 |
|
|
if (s->pstate != SLOT_CFG) { |
274 |
|
|
slot_log(s); |
275 |
|
|
log_puts(": slot_init: wrong state\n"); |
276 |
|
|
panic(); |
277 |
|
|
} |
278 |
|
|
#endif |
279 |
|
|
s->bpf = s->afile.par.bps * (s->cmax - s->cmin + 1); |
280 |
|
|
s->round = (dev_round * s->afile.rate + dev_rate - 1) / dev_rate; |
281 |
|
|
|
282 |
|
|
bufsz = s->round * (dev_bufsz / dev_round); |
283 |
|
|
bufsz -= bufsz % s->round; |
284 |
|
|
if (bufsz == 0) |
285 |
|
|
bufsz = s->round; |
286 |
|
|
abuf_init(&s->buf, bufsz * s->bpf); |
287 |
|
|
#ifdef DEBUG |
288 |
|
|
if (log_level >= 3) { |
289 |
|
|
slot_log(s); |
290 |
|
|
log_puts(": allocated "); |
291 |
|
|
log_putu(bufsz); |
292 |
|
|
log_puts(" frame buffer\n"); |
293 |
|
|
} |
294 |
|
|
#endif |
295 |
|
|
|
296 |
|
|
slot_nch = s->cmax - s->cmin + 1; |
297 |
|
|
s->convbuf = NULL; |
298 |
|
|
s->resampbuf = NULL; |
299 |
|
|
s->join = 1; |
300 |
|
|
s->expand = 1; |
301 |
|
|
if (s->mode & SIO_PLAY) { |
302 |
|
|
if (s->dup) { |
303 |
|
|
if (dev_pchan > slot_nch) |
304 |
|
|
s->expand = dev_pchan / slot_nch; |
305 |
|
|
else if (dev_pchan < slot_nch) |
306 |
|
|
s->join = slot_nch / dev_pchan; |
307 |
|
|
} |
308 |
|
|
cmap_init(&s->cmap, |
309 |
|
|
s->cmin, s->cmax, |
310 |
|
|
s->cmin, s->cmax, |
311 |
|
|
0, dev_pchan - 1, |
312 |
|
|
0, dev_pchan - 1); |
313 |
|
|
if (s->afile.fmt != AFILE_FMT_PCM || |
314 |
|
|
!aparams_native(&s->afile.par)) { |
315 |
|
|
dec_init(&s->conv, &s->afile.par, slot_nch); |
316 |
|
|
s->convbuf = |
317 |
|
|
xmalloc(s->round * slot_nch * sizeof(adata_t)); |
318 |
|
|
} |
319 |
|
|
if (s->afile.rate != dev_rate) { |
320 |
|
|
resamp_init(&s->resamp, s->afile.rate, dev_rate, |
321 |
|
|
slot_nch); |
322 |
|
|
s->resampbuf = |
323 |
|
|
xmalloc(dev_round * slot_nch * sizeof(adata_t)); |
324 |
|
|
} |
325 |
|
|
} |
326 |
|
|
if (s->mode & SIO_REC) { |
327 |
|
|
if (s->dup) { |
328 |
|
|
if (dev_rchan > slot_nch) |
329 |
|
|
s->join = dev_rchan / slot_nch; |
330 |
|
|
else if (dev_rchan < slot_nch) |
331 |
|
|
s->expand = slot_nch / dev_rchan; |
332 |
|
|
} |
333 |
|
|
cmap_init(&s->cmap, |
334 |
|
|
0, dev_rchan - 1, |
335 |
|
|
0, dev_rchan - 1, |
336 |
|
|
s->cmin, s->cmax, |
337 |
|
|
s->cmin, s->cmax); |
338 |
|
|
if (s->afile.rate != dev_rate) { |
339 |
|
|
resamp_init(&s->resamp, dev_rate, s->afile.rate, |
340 |
|
|
slot_nch); |
341 |
|
|
s->resampbuf = |
342 |
|
|
xmalloc(dev_round * slot_nch * sizeof(adata_t)); |
343 |
|
|
} |
344 |
|
|
if (!aparams_native(&s->afile.par)) { |
345 |
|
|
enc_init(&s->conv, &s->afile.par, slot_nch); |
346 |
|
|
s->convbuf = |
347 |
|
|
xmalloc(s->round * slot_nch * sizeof(adata_t)); |
348 |
|
|
} |
349 |
|
|
} |
350 |
|
|
s->pstate = SLOT_INIT; |
351 |
|
|
#ifdef DEBUG |
352 |
|
|
if (log_level >= 3) { |
353 |
|
|
slot_log(s); |
354 |
|
|
log_puts(": chain initialized\n"); |
355 |
|
|
} |
356 |
|
|
#endif |
357 |
|
|
} |
358 |
|
|
|
359 |
|
|
static void |
360 |
|
|
slot_start(struct slot *s, long long pos) |
361 |
|
|
{ |
362 |
|
|
#ifdef DEBUG |
363 |
|
|
if (s->pstate != SLOT_INIT) { |
364 |
|
|
slot_log(s); |
365 |
|
|
log_puts(": slot_start: wrong state\n"); |
366 |
|
|
panic(); |
367 |
|
|
} |
368 |
|
|
#endif |
369 |
|
|
pos -= s->pos; |
370 |
|
|
if (pos < 0) { |
371 |
|
|
s->skip = -pos; |
372 |
|
|
pos = 0; |
373 |
|
|
} else |
374 |
|
|
s->skip = 0; |
375 |
|
|
|
376 |
|
|
/* |
377 |
|
|
* convert pos to slot sample rate |
378 |
|
|
* |
379 |
|
|
* At this stage, we could adjust s->resamp.diff to get |
380 |
|
|
* sub-frame accuracy. |
381 |
|
|
*/ |
382 |
|
|
pos = pos * s->afile.rate / dev_rate; |
383 |
|
|
|
384 |
|
|
if (!afile_seek(&s->afile, pos * s->bpf)) { |
385 |
|
|
s->pstate = SLOT_INIT; |
386 |
|
|
return; |
387 |
|
|
} |
388 |
|
|
s->pstate = SLOT_RUN; |
389 |
|
|
if (s->mode & SIO_PLAY) |
390 |
|
|
slot_fill(s); |
391 |
|
|
#ifdef DEBUG |
392 |
|
|
if (log_level >= 2) { |
393 |
|
|
slot_log(s); |
394 |
|
|
log_puts(": started\n"); |
395 |
|
|
} |
396 |
|
|
#endif |
397 |
|
|
} |
398 |
|
|
|
399 |
|
|
static void |
400 |
|
|
slot_stop(struct slot *s) |
401 |
|
|
{ |
402 |
|
|
if (s->pstate == SLOT_INIT) |
403 |
|
|
return; |
404 |
|
|
if (s->mode & SIO_REC) |
405 |
|
|
slot_flush(s); |
406 |
|
|
if (s->mode & SIO_PLAY) |
407 |
|
|
s->buf.used = s->buf.start = 0; |
408 |
|
|
s->pstate = SLOT_INIT; |
409 |
|
|
#ifdef DEBUG |
410 |
|
|
if (log_level >= 2) { |
411 |
|
|
slot_log(s); |
412 |
|
|
log_puts(": stopped\n"); |
413 |
|
|
} |
414 |
|
|
#endif |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
static void |
418 |
|
|
slot_del(struct slot *s) |
419 |
|
|
{ |
420 |
|
|
struct slot **ps; |
421 |
|
|
|
422 |
|
|
if (s->pstate != SLOT_CFG) { |
423 |
|
|
slot_stop(s); |
424 |
|
|
afile_close(&s->afile); |
425 |
|
|
#ifdef DEBUG |
426 |
|
|
if (log_level >= 3) { |
427 |
|
|
slot_log(s); |
428 |
|
|
log_puts(": closed\n"); |
429 |
|
|
} |
430 |
|
|
#endif |
431 |
|
|
abuf_done(&s->buf); |
432 |
|
|
if (s->resampbuf) |
433 |
|
|
xfree(s->resampbuf); |
434 |
|
|
if (s->convbuf) |
435 |
|
|
xfree(s->convbuf); |
436 |
|
|
} |
437 |
|
|
for (ps = &slot_list; *ps != s; ps = &(*ps)->next) |
438 |
|
|
; /* nothing */ |
439 |
|
|
*ps = s->next; |
440 |
|
|
xfree(s); |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
static void |
444 |
|
|
slot_getcnt(struct slot *s, int *icnt, int *ocnt) |
445 |
|
|
{ |
446 |
|
|
int cnt; |
447 |
|
|
|
448 |
|
|
if (s->resampbuf) |
449 |
|
|
resamp_getcnt(&s->resamp, icnt, ocnt); |
450 |
|
|
else { |
451 |
|
|
cnt = (*icnt < *ocnt) ? *icnt : *ocnt; |
452 |
|
|
*icnt = cnt; |
453 |
|
|
*ocnt = cnt; |
454 |
|
|
} |
455 |
|
|
} |
456 |
|
|
|
457 |
|
|
static void |
458 |
|
|
play_filt_resamp(struct slot *s, void *res_in, void *out, int icnt, int ocnt) |
459 |
|
|
{ |
460 |
|
|
int i, offs, vol, nch; |
461 |
|
|
void *in; |
462 |
|
|
|
463 |
|
|
if (s->resampbuf) { |
464 |
|
|
resamp_do(&s->resamp, res_in, s->resampbuf, icnt, ocnt); |
465 |
|
|
in = s->resampbuf; |
466 |
|
|
} else |
467 |
|
|
in = res_in; |
468 |
|
|
|
469 |
|
|
nch = s->cmap.nch; |
470 |
|
|
vol = s->vol / s->join; /* XXX */ |
471 |
|
|
cmap_add(&s->cmap, in, out, vol, ocnt); |
472 |
|
|
|
473 |
|
|
offs = 0; |
474 |
|
|
for (i = s->join - 1; i > 0; i--) { |
475 |
|
|
offs += nch; |
476 |
|
|
cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, ocnt); |
477 |
|
|
} |
478 |
|
|
offs = 0; |
479 |
|
|
for (i = s->expand - 1; i > 0; i--) { |
480 |
|
|
offs += nch; |
481 |
|
|
cmap_add(&s->cmap, in, (adata_t *)out + offs, vol, ocnt); |
482 |
|
|
} |
483 |
|
|
} |
484 |
|
|
|
485 |
|
|
static void |
486 |
|
|
play_filt_dec(struct slot *s, void *in, void *out, int icnt, int ocnt) |
487 |
|
|
{ |
488 |
|
|
void *tmp; |
489 |
|
|
|
490 |
|
|
tmp = s->convbuf; |
491 |
|
|
if (tmp) { |
492 |
|
|
switch (s->afile.fmt) { |
493 |
|
|
case AFILE_FMT_PCM: |
494 |
|
|
dec_do(&s->conv, in, tmp, icnt); |
495 |
|
|
break; |
496 |
|
|
case AFILE_FMT_ULAW: |
497 |
|
|
dec_do_ulaw(&s->conv, in, tmp, icnt, 0); |
498 |
|
|
break; |
499 |
|
|
case AFILE_FMT_ALAW: |
500 |
|
|
dec_do_ulaw(&s->conv, in, tmp, icnt, 1); |
501 |
|
|
break; |
502 |
|
|
case AFILE_FMT_FLOAT: |
503 |
|
|
dec_do_float(&s->conv, in, tmp, icnt); |
504 |
|
|
break; |
505 |
|
|
} |
506 |
|
|
} else |
507 |
|
|
tmp = in; |
508 |
|
|
play_filt_resamp(s, tmp, out, icnt, ocnt); |
509 |
|
|
} |
510 |
|
|
|
511 |
|
|
/* |
512 |
|
|
* Mix as many as possible frames (but not more than a block) from the |
513 |
|
|
* slot buffer to the given location. Return the number of frames mixed |
514 |
|
|
* in the output buffer |
515 |
|
|
*/ |
516 |
|
|
static int |
517 |
|
|
slot_mix_badd(struct slot *s, adata_t *odata) |
518 |
|
|
{ |
519 |
|
|
adata_t *idata; |
520 |
|
|
int len, icnt, ocnt, otodo, odone; |
521 |
|
|
|
522 |
|
|
odone = 0; |
523 |
|
|
otodo = dev_round; |
524 |
|
|
if (s->skip > 0) { |
525 |
|
|
ocnt = otodo; |
526 |
|
|
if (ocnt > s->skip) |
527 |
|
|
ocnt = s->skip; |
528 |
|
|
s->skip -= ocnt; |
529 |
|
|
odata += dev_pchan * ocnt; |
530 |
|
|
otodo -= ocnt; |
531 |
|
|
odone += ocnt; |
532 |
|
|
} |
533 |
|
|
while (otodo > 0) { |
534 |
|
|
idata = (adata_t *)abuf_rgetblk(&s->buf, &len); |
535 |
|
|
icnt = len / s->bpf; |
536 |
|
|
if (icnt > s->round) |
537 |
|
|
icnt = s->round; |
538 |
|
|
ocnt = otodo; |
539 |
|
|
slot_getcnt(s, &icnt, &ocnt); |
540 |
|
|
if (icnt == 0) |
541 |
|
|
break; |
542 |
|
|
play_filt_dec(s, idata, odata, icnt, ocnt); |
543 |
|
|
abuf_rdiscard(&s->buf, icnt * s->bpf); |
544 |
|
|
otodo -= ocnt; |
545 |
|
|
odone += ocnt; |
546 |
|
|
odata += ocnt * dev_pchan; |
547 |
|
|
} |
548 |
|
|
return odone; |
549 |
|
|
} |
550 |
|
|
|
551 |
|
|
static void |
552 |
|
|
rec_filt_resamp(struct slot *s, void *in, void *res_out, int icnt, int ocnt) |
553 |
|
|
{ |
554 |
|
|
int i, vol, offs, nch; |
555 |
|
|
void *out = res_out; |
556 |
|
|
|
557 |
|
|
out = (s->resampbuf) ? s->resampbuf : res_out; |
558 |
|
|
|
559 |
|
|
nch = s->cmap.nch; |
560 |
|
|
vol = ADATA_UNIT / s->join; |
561 |
|
|
cmap_copy(&s->cmap, in, out, vol, icnt); |
562 |
|
|
|
563 |
|
|
offs = 0; |
564 |
|
|
for (i = s->join - 1; i > 0; i--) { |
565 |
|
|
offs += nch; |
566 |
|
|
cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, icnt); |
567 |
|
|
} |
568 |
|
|
offs = 0; |
569 |
|
|
for (i = s->expand - 1; i > 0; i--) { |
570 |
|
|
offs += nch; |
571 |
|
|
cmap_copy(&s->cmap, in, (adata_t *)out + offs, vol, icnt); |
572 |
|
|
} |
573 |
|
|
if (s->resampbuf) |
574 |
|
|
resamp_do(&s->resamp, s->resampbuf, res_out, icnt, ocnt); |
575 |
|
|
else |
576 |
|
|
ocnt = icnt; |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
static void |
580 |
|
|
rec_filt_enc(struct slot *s, void *in, void *out, int icnt, int ocnt) |
581 |
|
|
{ |
582 |
|
|
void *tmp; |
583 |
|
|
|
584 |
|
|
tmp = s->convbuf; |
585 |
|
|
rec_filt_resamp(s, in, tmp ? tmp : out, icnt, ocnt); |
586 |
|
|
if (tmp) |
587 |
|
|
enc_do(&s->conv, tmp, out, ocnt); |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
/* |
591 |
|
|
* Copy "todo" frames from the given buffer to the slot buffer, |
592 |
|
|
* but not more than a block. |
593 |
|
|
*/ |
594 |
|
|
static void |
595 |
|
|
slot_sub_bcopy(struct slot *s, adata_t *idata, int itodo) |
596 |
|
|
{ |
597 |
|
|
adata_t *odata; |
598 |
|
|
int len, icnt, ocnt; |
599 |
|
|
|
600 |
|
|
if (s->skip > 0) { |
601 |
|
|
icnt = itodo; |
602 |
|
|
if (icnt > s->skip) |
603 |
|
|
icnt = s->skip; |
604 |
|
|
s->skip -= icnt; |
605 |
|
|
idata += dev_rchan * icnt; |
606 |
|
|
itodo -= icnt; |
607 |
|
|
} |
608 |
|
|
|
609 |
|
|
while (itodo > 0) { |
610 |
|
|
odata = (adata_t *)abuf_wgetblk(&s->buf, &len); |
611 |
|
|
ocnt = len / s->bpf; |
612 |
|
|
if (ocnt > s->round) |
613 |
|
|
ocnt = s->round; |
614 |
|
|
icnt = itodo; |
615 |
|
|
slot_getcnt(s, &icnt, &ocnt); |
616 |
|
|
if (ocnt == 0) |
617 |
|
|
break; |
618 |
|
|
rec_filt_enc(s, idata, odata, icnt, ocnt); |
619 |
|
|
abuf_wcommit(&s->buf, ocnt * s->bpf); |
620 |
|
|
itodo -= icnt; |
621 |
|
|
idata += icnt * dev_rchan; |
622 |
|
|
} |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
static int |
626 |
|
|
dev_open(char *dev, int mode, int bufsz, char *port) |
627 |
|
|
{ |
628 |
|
|
int rate, pmax, rmax; |
629 |
|
|
struct sio_par par; |
630 |
|
|
struct slot *s; |
631 |
|
|
|
632 |
|
|
if (port) { |
633 |
|
|
dev_port = port; |
634 |
|
|
dev_mh = mio_open(dev_port, MIO_IN, 0); |
635 |
|
|
if (dev_mh == NULL) { |
636 |
|
|
log_puts(port); |
637 |
|
|
log_puts(": couldn't open midi port\n"); |
638 |
|
|
return 0; |
639 |
|
|
} |
640 |
|
|
} else |
641 |
|
|
dev_mh = NULL; |
642 |
|
|
|
643 |
|
|
dev_name = dev; |
644 |
|
|
dev_sh = sio_open(dev, mode, 0); |
645 |
|
|
if (dev_sh == NULL) { |
646 |
|
|
log_puts(dev_name); |
647 |
|
|
log_puts(": couldn't open audio device\n"); |
648 |
|
|
return 0; |
649 |
|
|
} |
650 |
|
|
|
651 |
|
|
rate = pmax = rmax = 0; |
652 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
653 |
|
|
if (s->afile.rate > rate) |
654 |
|
|
rate = s->afile.rate; |
655 |
|
|
if (s->mode == SIO_PLAY) { |
656 |
|
|
if (s->cmax > pmax) |
657 |
|
|
pmax = s->cmax; |
658 |
|
|
} |
659 |
|
|
if (s->mode == SIO_REC) { |
660 |
|
|
if (s->cmax > rmax) |
661 |
|
|
rmax = s->cmax; |
662 |
|
|
} |
663 |
|
|
} |
664 |
|
|
sio_initpar(&par); |
665 |
|
|
par.bits = ADATA_BITS; |
666 |
|
|
par.bps = sizeof(adata_t); |
667 |
|
|
par.msb = 0; |
668 |
|
|
par.le = SIO_LE_NATIVE; |
669 |
|
|
par.rate = rate; |
670 |
|
|
if (mode & SIO_PLAY) |
671 |
|
|
par.pchan = pmax + 1; |
672 |
|
|
if (mode & SIO_REC) |
673 |
|
|
par.rchan = rmax + 1; |
674 |
|
|
par.appbufsz = bufsz > 0 ? bufsz : rate * DEFAULT_BUFSZ_MS / 1000; |
675 |
|
|
if (!sio_setpar(dev_sh, &par) || !sio_getpar(dev_sh, &par)) { |
676 |
|
|
log_puts(dev_name); |
677 |
|
|
log_puts(": couldn't set audio params\n"); |
678 |
|
|
return 0; |
679 |
|
|
} |
680 |
|
|
if (par.bits != ADATA_BITS || |
681 |
|
|
par.bps != sizeof(adata_t) || |
682 |
|
|
(par.bps > 1 && par.le != SIO_LE_NATIVE) || |
683 |
|
|
(par.bps * 8 > par.bits && par.msb)) { |
684 |
|
|
log_puts(dev_name); |
685 |
|
|
log_puts(": unsupported audio params\n"); |
686 |
|
|
return 0; |
687 |
|
|
} |
688 |
|
|
dev_mode = mode; |
689 |
|
|
dev_rate = par.rate; |
690 |
|
|
dev_bufsz = par.bufsz; |
691 |
|
|
dev_round = par.round; |
692 |
|
|
if (mode & SIO_PLAY) { |
693 |
|
|
dev_pchan = par.pchan; |
694 |
|
|
dev_pbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round); |
695 |
|
|
} |
696 |
|
|
if (mode & SIO_REC) { |
697 |
|
|
dev_rchan = par.rchan; |
698 |
|
|
dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round); |
699 |
|
|
} |
700 |
|
|
dev_pstate = DEV_STOP; |
701 |
|
|
if (log_level >= 2) { |
702 |
|
|
log_puts(dev_name); |
703 |
|
|
log_puts(": "); |
704 |
|
|
log_putu(dev_rate); |
705 |
|
|
log_puts("Hz"); |
706 |
|
|
if (dev_mode & SIO_PLAY) { |
707 |
|
|
log_puts(", play 0:"); |
708 |
|
|
log_puti(dev_pchan - 1); |
709 |
|
|
} |
710 |
|
|
if (dev_mode & SIO_REC) { |
711 |
|
|
log_puts(", rec 0:"); |
712 |
|
|
log_puti(dev_rchan - 1); |
713 |
|
|
} |
714 |
|
|
log_puts(", "); |
715 |
|
|
log_putu(dev_bufsz / dev_round); |
716 |
|
|
log_puts(" blocks of "); |
717 |
|
|
log_putu(dev_round); |
718 |
|
|
log_puts(" frames\n"); |
719 |
|
|
} |
720 |
|
|
return 1; |
721 |
|
|
} |
722 |
|
|
|
723 |
|
|
static void |
724 |
|
|
dev_close(void) |
725 |
|
|
{ |
726 |
|
|
sio_close(dev_sh); |
727 |
|
|
if (dev_mh) |
728 |
|
|
mio_close(dev_mh); |
729 |
|
|
if (dev_mode & SIO_PLAY) |
730 |
|
|
xfree(dev_pbuf); |
731 |
|
|
if (dev_mode & SIO_REC) |
732 |
|
|
xfree(dev_rbuf); |
733 |
|
|
} |
734 |
|
|
|
735 |
|
|
static void |
736 |
|
|
dev_master(int val) |
737 |
|
|
{ |
738 |
|
|
struct slot *s; |
739 |
|
|
int mastervol, slotvol; |
740 |
|
|
|
741 |
|
|
mastervol = MIDI_TO_ADATA(dev_volctl); |
742 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
743 |
|
|
slotvol = MIDI_TO_ADATA(val); |
744 |
|
|
s->vol = ADATA_MUL(mastervol, slotvol); |
745 |
|
|
} |
746 |
|
|
#ifdef DEBUG |
747 |
|
|
if (log_level >= 3) { |
748 |
|
|
log_puts("master volume set to "); |
749 |
|
|
log_putu(val); |
750 |
|
|
log_puts("\n"); |
751 |
|
|
} |
752 |
|
|
#endif |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
static void |
756 |
|
|
dev_slotvol(int midich, int val) |
757 |
|
|
{ |
758 |
|
|
struct slot *s; |
759 |
|
|
int mastervol, slotvol; |
760 |
|
|
|
761 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
762 |
|
|
if (midich == 0) { |
763 |
|
|
mastervol = MIDI_TO_ADATA(dev_volctl); |
764 |
|
|
slotvol = MIDI_TO_ADATA(val); |
765 |
|
|
s->vol = ADATA_MUL(mastervol, slotvol); |
766 |
|
|
#ifdef DEBUG |
767 |
|
|
if (log_level >= 3) { |
768 |
|
|
slot_log(s); |
769 |
|
|
log_puts(": volume set to "); |
770 |
|
|
log_putu(val); |
771 |
|
|
log_puts("\n"); |
772 |
|
|
} |
773 |
|
|
#endif |
774 |
|
|
break; |
775 |
|
|
} |
776 |
|
|
} |
777 |
|
|
} |
778 |
|
|
|
779 |
|
|
/* |
780 |
|
|
* start all slots simultaneously |
781 |
|
|
*/ |
782 |
|
|
static void |
783 |
|
|
dev_mmcstart(void) |
784 |
|
|
{ |
785 |
|
|
struct slot *s; |
786 |
|
|
|
787 |
|
|
if (dev_pstate == DEV_STOP) { |
788 |
|
|
dev_pstate = DEV_START; |
789 |
|
|
for (s = slot_list; s != NULL; s = s->next) |
790 |
|
|
slot_start(s, dev_pos); |
791 |
|
|
dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0; |
792 |
|
|
sio_start(dev_sh); |
793 |
|
|
if (log_level >= 2) |
794 |
|
|
log_puts("started\n"); |
795 |
|
|
} else { |
796 |
|
|
#ifdef DEBUG |
797 |
|
|
if (log_level >= 3) |
798 |
|
|
log_puts("ignoring mmc start\n"); |
799 |
|
|
#endif |
800 |
|
|
} |
801 |
|
|
} |
802 |
|
|
|
803 |
|
|
/* |
804 |
|
|
* stop all slots simultaneously |
805 |
|
|
*/ |
806 |
|
|
static void |
807 |
|
|
dev_mmcstop(void) |
808 |
|
|
{ |
809 |
|
|
struct slot *s; |
810 |
|
|
|
811 |
|
|
if (dev_pstate == DEV_START) { |
812 |
|
|
dev_pstate = DEV_STOP; |
813 |
|
|
for (s = slot_list; s != NULL; s = s->next) |
814 |
|
|
slot_stop(s); |
815 |
|
|
sio_stop(dev_sh); |
816 |
|
|
if (log_level >= 2) |
817 |
|
|
log_puts("stopped\n"); |
818 |
|
|
} else { |
819 |
|
|
#ifdef DEBUG |
820 |
|
|
if (log_level >= 3) |
821 |
|
|
log_puts("ignored mmc stop\n"); |
822 |
|
|
#endif |
823 |
|
|
} |
824 |
|
|
} |
825 |
|
|
|
826 |
|
|
/* |
827 |
|
|
* relocate all slots simultaneously |
828 |
|
|
*/ |
829 |
|
|
static void |
830 |
|
|
dev_mmcloc(int hr, int min, int sec, int fr, int cent, int fps) |
831 |
|
|
{ |
832 |
|
|
long long pos; |
833 |
|
|
|
834 |
|
|
pos = (long long)dev_rate * hr * 3600 + |
835 |
|
|
(long long)dev_rate * min * 60 + |
836 |
|
|
(long long)dev_rate * sec + |
837 |
|
|
(long long)dev_rate * fr / fps + |
838 |
|
|
(long long)dev_rate * cent / (100 * fps); |
839 |
|
|
if (dev_pos == pos) |
840 |
|
|
return; |
841 |
|
|
dev_pos = pos; |
842 |
|
|
if (log_level >= 2) { |
843 |
|
|
log_puts("relocated to "); |
844 |
|
|
log_putu(hr); |
845 |
|
|
log_puts(":"); |
846 |
|
|
log_putu(min); |
847 |
|
|
log_puts(":"); |
848 |
|
|
log_putu(sec); |
849 |
|
|
log_puts("."); |
850 |
|
|
log_putu(fr); |
851 |
|
|
log_puts("."); |
852 |
|
|
log_putu(cent); |
853 |
|
|
log_puts(" at "); |
854 |
|
|
log_putu(fps); |
855 |
|
|
log_puts("fps\n"); |
856 |
|
|
} |
857 |
|
|
if (dev_pstate == DEV_START) { |
858 |
|
|
dev_mmcstop(); |
859 |
|
|
dev_mmcstart(); |
860 |
|
|
} |
861 |
|
|
} |
862 |
|
|
|
863 |
|
|
static void |
864 |
|
|
dev_imsg(unsigned char *msg, unsigned int len) |
865 |
|
|
{ |
866 |
|
|
struct sysex *x; |
867 |
|
|
unsigned int fps, chan; |
868 |
|
|
|
869 |
|
|
if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) { |
870 |
|
|
chan = msg[0] & MIDI_CHANMASK; |
871 |
|
|
dev_slotvol(chan, msg[2]); |
872 |
|
|
return; |
873 |
|
|
} |
874 |
|
|
x = (struct sysex *)msg; |
875 |
|
|
if (x->start != SYSEX_START) |
876 |
|
|
return; |
877 |
|
|
if (len < SYSEX_SIZE(empty)) |
878 |
|
|
return; |
879 |
|
|
if (x->type != SYSEX_TYPE_RT) |
880 |
|
|
return; |
881 |
|
|
if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) { |
882 |
|
|
if (len == SYSEX_SIZE(master)) |
883 |
|
|
dev_master(x->u.master.coarse); |
884 |
|
|
return; |
885 |
|
|
} |
886 |
|
|
if (x->id0 != SYSEX_MMC) |
887 |
|
|
return; |
888 |
|
|
switch (x->id1) { |
889 |
|
|
case SYSEX_MMC_STOP: |
890 |
|
|
if (len != SYSEX_SIZE(stop)) |
891 |
|
|
return; |
892 |
|
|
dev_mmcstop(); |
893 |
|
|
break; |
894 |
|
|
case SYSEX_MMC_START: |
895 |
|
|
if (len != SYSEX_SIZE(start)) |
896 |
|
|
return; |
897 |
|
|
dev_mmcstart(); |
898 |
|
|
break; |
899 |
|
|
case SYSEX_MMC_LOC: |
900 |
|
|
if (len != SYSEX_SIZE(loc) || |
901 |
|
|
x->u.loc.len != SYSEX_MMC_LOC_LEN || |
902 |
|
|
x->u.loc.cmd != SYSEX_MMC_LOC_CMD) |
903 |
|
|
return; |
904 |
|
|
switch (x->u.loc.hr >> 5) { |
905 |
|
|
case MTC_FPS_24: |
906 |
|
|
fps = 24; |
907 |
|
|
break; |
908 |
|
|
case MTC_FPS_25: |
909 |
|
|
fps = 25; |
910 |
|
|
break; |
911 |
|
|
case MTC_FPS_30: |
912 |
|
|
fps = 30; |
913 |
|
|
break; |
914 |
|
|
default: |
915 |
|
|
dev_mmcstop(); |
916 |
|
|
return; |
917 |
|
|
} |
918 |
|
|
dev_mmcloc(x->u.loc.hr & 0x1f, |
919 |
|
|
x->u.loc.min, |
920 |
|
|
x->u.loc.sec, |
921 |
|
|
x->u.loc.fr, |
922 |
|
|
x->u.loc.cent, |
923 |
|
|
fps); |
924 |
|
|
break; |
925 |
|
|
} |
926 |
|
|
} |
927 |
|
|
|
928 |
|
|
/* |
929 |
|
|
* parse the given data chunk and call imsg() for each message |
930 |
|
|
*/ |
931 |
|
|
static void |
932 |
|
|
midi_in(unsigned char *idata, int icount) |
933 |
|
|
{ |
934 |
|
|
int i; |
935 |
|
|
unsigned char c; |
936 |
|
|
|
937 |
|
|
for (i = 0; i < icount; i++) { |
938 |
|
|
c = *idata++; |
939 |
|
|
if (c >= 0xf8) { |
940 |
|
|
/* we don't use real-time events */ |
941 |
|
|
} else if (c == SYSEX_END) { |
942 |
|
|
if (dev_mst == SYSEX_START) { |
943 |
|
|
dev_msg[dev_midx++] = c; |
944 |
|
|
dev_imsg(dev_msg, dev_midx); |
945 |
|
|
} |
946 |
|
|
dev_mst = 0; |
947 |
|
|
dev_midx = 0; |
948 |
|
|
} else if (c >= 0xf0) { |
949 |
|
|
dev_msg[0] = c; |
950 |
|
|
dev_mlen = common_len[c & 7]; |
951 |
|
|
dev_mst = c; |
952 |
|
|
dev_midx = 1; |
953 |
|
|
} else if (c >= 0x80) { |
954 |
|
|
dev_msg[0] = c; |
955 |
|
|
dev_mlen = voice_len[(c >> 4) & 7]; |
956 |
|
|
dev_mst = c; |
957 |
|
|
dev_midx = 1; |
958 |
|
|
} else if (dev_mst) { |
959 |
|
|
if (dev_midx == 0 && dev_mst != SYSEX_START) |
960 |
|
|
dev_msg[dev_midx++] = dev_mst; |
961 |
|
|
dev_msg[dev_midx++] = c; |
962 |
|
|
if (dev_midx == dev_mlen) { |
963 |
|
|
dev_imsg(dev_msg, dev_midx); |
964 |
|
|
if (dev_mst >= 0xf0) |
965 |
|
|
dev_mst = 0; |
966 |
|
|
dev_midx = 0; |
967 |
|
|
} else if (dev_midx == MIDI_MSGMAX) { |
968 |
|
|
/* sysex too long */ |
969 |
|
|
dev_mst = 0; |
970 |
|
|
} |
971 |
|
|
} |
972 |
|
|
} |
973 |
|
|
} |
974 |
|
|
|
975 |
|
|
static int |
976 |
|
|
slot_list_mix(unsigned int round, unsigned int pchan, adata_t *pbuf) |
977 |
|
|
{ |
978 |
|
|
unsigned int done, n; |
979 |
|
|
struct slot *s; |
980 |
|
|
|
981 |
|
|
memset(pbuf, 0, pchan * round * sizeof(adata_t)); |
982 |
|
|
done = 0; |
983 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
984 |
|
|
if (s->pstate == SLOT_INIT || !(s->mode & SIO_PLAY)) |
985 |
|
|
continue; |
986 |
|
|
if (s->pstate == SLOT_STOP && s->buf.used < s->bpf) { |
987 |
|
|
#ifdef DEBUG |
988 |
|
|
if (log_level >= 3) { |
989 |
|
|
slot_log(s); |
990 |
|
|
log_puts(": drained, done\n"); |
991 |
|
|
} |
992 |
|
|
#endif |
993 |
|
|
slot_stop(s); |
994 |
|
|
continue; |
995 |
|
|
} |
996 |
|
|
n = slot_mix_badd(s, dev_pbuf); |
997 |
|
|
if (n > done) |
998 |
|
|
done = n; |
999 |
|
|
} |
1000 |
|
|
return done; |
1001 |
|
|
} |
1002 |
|
|
|
1003 |
|
|
static int |
1004 |
|
|
slot_list_copy(unsigned int count, unsigned int rchan, adata_t *rbuf) |
1005 |
|
|
{ |
1006 |
|
|
unsigned int done; |
1007 |
|
|
struct slot *s; |
1008 |
|
|
|
1009 |
|
|
done = 0; |
1010 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
1011 |
|
|
if (s->pstate == SLOT_INIT || !(s->mode & SIO_REC)) |
1012 |
|
|
continue; |
1013 |
|
|
slot_sub_bcopy(s, rbuf, count); |
1014 |
|
|
done = count; |
1015 |
|
|
} |
1016 |
|
|
return done; |
1017 |
|
|
} |
1018 |
|
|
|
1019 |
|
|
static void |
1020 |
|
|
slot_list_iodo(void) |
1021 |
|
|
{ |
1022 |
|
|
struct slot *s; |
1023 |
|
|
|
1024 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
1025 |
|
|
if (s->pstate != SLOT_RUN) |
1026 |
|
|
continue; |
1027 |
|
|
if ((s->mode & SIO_PLAY) && |
1028 |
|
|
(s->buf.used < s->round * s->bpf)) |
1029 |
|
|
slot_fill(s); |
1030 |
|
|
if ((s->mode & SIO_REC) && |
1031 |
|
|
(s->buf.len - s->buf.used < s->round * s->bpf)) |
1032 |
|
|
slot_flush(s); |
1033 |
|
|
} |
1034 |
|
|
} |
1035 |
|
|
|
1036 |
|
|
static int |
1037 |
|
|
offline(void) |
1038 |
|
|
{ |
1039 |
|
|
unsigned int todo; |
1040 |
|
|
int rate, cmax; |
1041 |
|
|
struct slot *s; |
1042 |
|
|
|
1043 |
|
|
rate = cmax = 0; |
1044 |
|
|
for (s = slot_list; s != NULL; s = s->next) { |
1045 |
|
|
if (s->afile.rate > rate) |
1046 |
|
|
rate = s->afile.rate; |
1047 |
|
|
if (s->cmax > cmax) |
1048 |
|
|
cmax = s->cmax; |
1049 |
|
|
} |
1050 |
|
|
dev_sh = NULL; |
1051 |
|
|
dev_name = "offline"; |
1052 |
|
|
dev_mode = SIO_PLAY | SIO_REC; |
1053 |
|
|
dev_rate = rate; |
1054 |
|
|
dev_bufsz = rate; |
1055 |
|
|
dev_round = rate; |
1056 |
|
|
dev_pchan = dev_rchan = cmax + 1; |
1057 |
|
|
dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round); |
1058 |
|
|
dev_pstate = DEV_STOP; |
1059 |
|
|
for (s = slot_list; s != NULL; s = s->next) |
1060 |
|
|
slot_init(s); |
1061 |
|
|
for (s = slot_list; s != NULL; s = s->next) |
1062 |
|
|
slot_start(s, 0); |
1063 |
|
|
for (;;) { |
1064 |
|
|
todo = slot_list_mix(dev_round, dev_pchan, dev_pbuf); |
1065 |
|
|
if (todo == 0) |
1066 |
|
|
break; |
1067 |
|
|
slot_list_copy(todo, dev_pchan, dev_pbuf); |
1068 |
|
|
slot_list_iodo(); |
1069 |
|
|
} |
1070 |
|
|
xfree(dev_pbuf); |
1071 |
|
|
while (slot_list) |
1072 |
|
|
slot_del(slot_list); |
1073 |
|
|
return 1; |
1074 |
|
|
} |
1075 |
|
|
|
1076 |
|
|
static int |
1077 |
|
|
playrec_cycle(void) |
1078 |
|
|
{ |
1079 |
|
|
unsigned int n, todo; |
1080 |
|
|
unsigned char *p; |
1081 |
|
|
int pcnt, rcnt; |
1082 |
|
|
|
1083 |
|
|
#ifdef DEBUG |
1084 |
|
|
if (log_level >= 4) { |
1085 |
|
|
log_puts(dev_name); |
1086 |
|
|
log_puts(": cycle, prime = "); |
1087 |
|
|
log_putu(dev_prime); |
1088 |
|
|
log_puts("\n"); |
1089 |
|
|
} |
1090 |
|
|
#endif |
1091 |
|
|
pcnt = rcnt = 0; |
1092 |
|
|
if (dev_mode & SIO_REC) { |
1093 |
|
|
if (dev_prime > 0) |
1094 |
|
|
dev_prime--; |
1095 |
|
|
else { |
1096 |
|
|
todo = dev_round * dev_rchan * sizeof(adata_t); |
1097 |
|
|
p = (unsigned char *)dev_rbuf; |
1098 |
|
|
while (todo > 0) { |
1099 |
|
|
n = sio_read(dev_sh, p, todo); |
1100 |
|
|
if (n == 0) { |
1101 |
|
|
log_puts(dev_name); |
1102 |
|
|
log_puts(": failed to read " |
1103 |
|
|
"from device\n"); |
1104 |
|
|
return 0; |
1105 |
|
|
} |
1106 |
|
|
p += n; |
1107 |
|
|
todo -= n; |
1108 |
|
|
} |
1109 |
|
|
rcnt = slot_list_copy(dev_round, dev_rchan, dev_rbuf); |
1110 |
|
|
} |
1111 |
|
|
} |
1112 |
|
|
if (dev_mode & SIO_PLAY) { |
1113 |
|
|
pcnt = slot_list_mix(dev_round, dev_pchan, dev_pbuf); |
1114 |
|
|
todo = sizeof(adata_t) * dev_pchan * dev_round; |
1115 |
|
|
n = sio_write(dev_sh, dev_pbuf, todo); |
1116 |
|
|
if (n == 0) { |
1117 |
|
|
log_puts(dev_name); |
1118 |
|
|
log_puts(": failed to write to device\n"); |
1119 |
|
|
return 0; |
1120 |
|
|
} |
1121 |
|
|
} |
1122 |
|
|
slot_list_iodo(); |
1123 |
|
|
return pcnt > 0 || rcnt > 0; |
1124 |
|
|
} |
1125 |
|
|
|
1126 |
|
|
static void |
1127 |
|
|
sigint(int s) |
1128 |
|
|
{ |
1129 |
|
|
if (quit_flag) |
1130 |
|
|
_exit(1); |
1131 |
|
|
quit_flag = 1; |
1132 |
|
|
} |
1133 |
|
|
|
1134 |
|
|
static int |
1135 |
|
|
playrec(char *dev, int mode, int bufsz, char *port) |
1136 |
|
|
{ |
1137 |
|
|
#define MIDIBUFSZ 0x100 |
1138 |
|
|
unsigned char mbuf[MIDIBUFSZ]; |
1139 |
|
|
struct sigaction sa; |
1140 |
|
|
struct pollfd *pfds; |
1141 |
|
|
struct slot *s; |
1142 |
|
|
int n, ns, nm, ev; |
1143 |
|
|
|
1144 |
|
|
if (!dev_open(dev, mode, bufsz, port)) |
1145 |
|
|
return 0; |
1146 |
|
|
n = sio_nfds(dev_sh); |
1147 |
|
|
if (dev_mh) |
1148 |
|
|
n += mio_nfds(dev_mh); |
1149 |
|
|
pfds = xmalloc(n * sizeof(struct pollfd)); |
1150 |
|
|
for (s = slot_list; s != NULL; s = s->next) |
1151 |
|
|
slot_init(s); |
1152 |
|
|
if (dev_mh == NULL) |
1153 |
|
|
dev_mmcstart(); |
1154 |
|
|
else { |
1155 |
|
|
if (log_level >= 2) |
1156 |
|
|
log_puts("ready, waiting for mmc messages\n"); |
1157 |
|
|
} |
1158 |
|
|
|
1159 |
|
|
quit_flag = 0; |
1160 |
|
|
sigfillset(&sa.sa_mask); |
1161 |
|
|
sa.sa_flags = SA_RESTART; |
1162 |
|
|
sa.sa_handler = sigint; |
1163 |
|
|
sigaction(SIGINT, &sa, NULL); |
1164 |
|
|
sigaction(SIGTERM, &sa, NULL); |
1165 |
|
|
sigaction(SIGHUP, &sa, NULL); |
1166 |
|
|
while (!quit_flag) { |
1167 |
|
|
if (dev_pstate == DEV_START) { |
1168 |
|
|
ev = 0; |
1169 |
|
|
if (mode & SIO_PLAY) |
1170 |
|
|
ev |= POLLOUT; |
1171 |
|
|
if (mode & SIO_REC) |
1172 |
|
|
ev |= POLLIN; |
1173 |
|
|
ns = sio_pollfd(dev_sh, pfds, ev); |
1174 |
|
|
} else |
1175 |
|
|
ns = 0; |
1176 |
|
|
if (dev_mh) |
1177 |
|
|
nm = mio_pollfd(dev_mh, pfds + ns, POLLIN); |
1178 |
|
|
else |
1179 |
|
|
nm = 0; |
1180 |
|
|
if (poll(pfds, ns + nm, -1) < 0) { |
1181 |
|
|
if (errno == EINTR) |
1182 |
|
|
continue; |
1183 |
|
|
log_puts("poll failed\n"); |
1184 |
|
|
panic(); |
1185 |
|
|
} |
1186 |
|
|
if (dev_pstate == DEV_START) { |
1187 |
|
|
ev = sio_revents(dev_sh, pfds); |
1188 |
|
|
if (ev & POLLHUP) { |
1189 |
|
|
log_puts(dev); |
1190 |
|
|
log_puts(": audio device gone, stopping\n"); |
1191 |
|
|
break; |
1192 |
|
|
} |
1193 |
|
|
if (ev & (POLLIN | POLLOUT)) { |
1194 |
|
|
if (!playrec_cycle() && dev_mh == NULL) |
1195 |
|
|
break; |
1196 |
|
|
} |
1197 |
|
|
} |
1198 |
|
|
if (dev_mh) { |
1199 |
|
|
ev = mio_revents(dev_mh, pfds + ns); |
1200 |
|
|
if (ev & POLLHUP) { |
1201 |
|
|
log_puts(dev_port); |
1202 |
|
|
log_puts(": midi port gone, stopping\n"); |
1203 |
|
|
break; |
1204 |
|
|
} |
1205 |
|
|
if (ev & POLLIN) { |
1206 |
|
|
n = mio_read(dev_mh, mbuf, MIDIBUFSZ); |
1207 |
|
|
midi_in(mbuf, n); |
1208 |
|
|
} |
1209 |
|
|
} |
1210 |
|
|
} |
1211 |
|
|
sigfillset(&sa.sa_mask); |
1212 |
|
|
sa.sa_flags = SA_RESTART; |
1213 |
|
|
sa.sa_handler = SIG_DFL; |
1214 |
|
|
sigaction(SIGINT, &sa, NULL); |
1215 |
|
|
sigaction(SIGTERM, &sa, NULL); |
1216 |
|
|
sigaction(SIGHUP, &sa, NULL); |
1217 |
|
|
|
1218 |
|
|
if (dev_pstate == DEV_START) |
1219 |
|
|
dev_mmcstop(); |
1220 |
|
|
xfree(pfds); |
1221 |
|
|
dev_close(); |
1222 |
|
|
while (slot_list) |
1223 |
|
|
slot_del(slot_list); |
1224 |
|
|
return 1; |
1225 |
|
|
} |
1226 |
|
|
|
1227 |
|
|
static int |
1228 |
|
|
opt_onoff(char *s, int *flag) |
1229 |
|
|
{ |
1230 |
|
|
if (strcmp("off", s) == 0) { |
1231 |
|
|
*flag = 0; |
1232 |
|
|
return 1; |
1233 |
|
|
} |
1234 |
|
|
if (strcmp("on", s) == 0) { |
1235 |
|
|
*flag = 1; |
1236 |
|
|
return 1; |
1237 |
|
|
} |
1238 |
|
|
log_puts(s); |
1239 |
|
|
log_puts(": on/off expected\n"); |
1240 |
|
|
return 0; |
1241 |
|
|
} |
1242 |
|
|
|
1243 |
|
|
static int |
1244 |
|
|
opt_enc(char *s, struct aparams *par) |
1245 |
|
|
{ |
1246 |
|
|
int len; |
1247 |
|
|
|
1248 |
|
|
len = aparams_strtoenc(par, s); |
1249 |
|
|
if (len == 0 || s[len] != '\0') { |
1250 |
|
|
log_puts(s); |
1251 |
|
|
log_puts(": bad encoding\n"); |
1252 |
|
|
return 0; |
1253 |
|
|
} |
1254 |
|
|
return 1; |
1255 |
|
|
} |
1256 |
|
|
|
1257 |
|
|
static int |
1258 |
|
|
opt_hdr(char *s, int *hdr) |
1259 |
|
|
{ |
1260 |
|
|
if (strcmp("auto", s) == 0) { |
1261 |
|
|
*hdr = AFILE_HDR_AUTO; |
1262 |
|
|
return 1; |
1263 |
|
|
} |
1264 |
|
|
if (strcmp("raw", s) == 0) { |
1265 |
|
|
*hdr = AFILE_HDR_RAW; |
1266 |
|
|
return 1; |
1267 |
|
|
} |
1268 |
|
|
if (strcmp("wav", s) == 0) { |
1269 |
|
|
*hdr = AFILE_HDR_WAV; |
1270 |
|
|
return 1; |
1271 |
|
|
} |
1272 |
|
|
if (strcmp("aiff", s) == 0) { |
1273 |
|
|
*hdr = AFILE_HDR_AIFF; |
1274 |
|
|
return 1; |
1275 |
|
|
} |
1276 |
|
|
if (strcmp("au", s) == 0) { |
1277 |
|
|
*hdr = AFILE_HDR_AU; |
1278 |
|
|
return 1; |
1279 |
|
|
} |
1280 |
|
|
log_puts(s); |
1281 |
|
|
log_puts(": bad header type\n"); |
1282 |
|
|
return 0; |
1283 |
|
|
} |
1284 |
|
|
|
1285 |
|
|
static int |
1286 |
|
|
opt_ch(char *s, int *rcmin, int *rcmax) |
1287 |
|
|
{ |
1288 |
|
|
char *next, *end; |
1289 |
|
|
long cmin, cmax; |
1290 |
|
|
|
1291 |
|
|
errno = 0; |
1292 |
|
|
cmin = strtol(s, &next, 10); |
1293 |
|
|
if (next == s || *next != ':') |
1294 |
|
|
goto failed; |
1295 |
|
|
cmax = strtol(++next, &end, 10); |
1296 |
|
|
if (end == next || *end != '\0') |
1297 |
|
|
goto failed; |
1298 |
|
|
if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX) |
1299 |
|
|
goto failed; |
1300 |
|
|
*rcmin = cmin; |
1301 |
|
|
*rcmax = cmax; |
1302 |
|
|
return 1; |
1303 |
|
|
failed: |
1304 |
|
|
log_puts(s); |
1305 |
|
|
log_puts(": channel range expected\n"); |
1306 |
|
|
return 0; |
1307 |
|
|
} |
1308 |
|
|
|
1309 |
|
|
static int |
1310 |
|
|
opt_num(char *s, int min, int max, int *num) |
1311 |
|
|
{ |
1312 |
|
|
const char *errstr; |
1313 |
|
|
|
1314 |
|
|
*num = strtonum(s, min, max, &errstr); |
1315 |
|
|
if (errstr) { |
1316 |
|
|
log_puts(s); |
1317 |
|
|
log_puts(": expected integer between "); |
1318 |
|
|
log_puti(min); |
1319 |
|
|
log_puts(" and "); |
1320 |
|
|
log_puti(max); |
1321 |
|
|
log_puts("\n"); |
1322 |
|
|
return 0; |
1323 |
|
|
} |
1324 |
|
|
return 1; |
1325 |
|
|
} |
1326 |
|
|
|
1327 |
|
|
static int |
1328 |
|
|
opt_pos(char *s, long long *pos) |
1329 |
|
|
{ |
1330 |
|
|
const char *errstr; |
1331 |
|
|
|
1332 |
|
|
*pos = strtonum(s, 0, LLONG_MAX, &errstr); |
1333 |
|
|
if (errstr) { |
1334 |
|
|
log_puts(s); |
1335 |
|
|
log_puts(": positive number of samples expected\n"); |
1336 |
|
|
return 0; |
1337 |
|
|
} |
1338 |
|
|
return 1; |
1339 |
|
|
} |
1340 |
|
|
|
1341 |
|
|
int |
1342 |
|
|
main(int argc, char **argv) |
1343 |
|
|
{ |
1344 |
|
|
int dup, cmin, cmax, rate, vol, bufsz, hdr, mode; |
1345 |
|
|
char *port, *dev; |
1346 |
|
|
struct aparams par; |
1347 |
|
|
int n_flag, c; |
1348 |
|
|
long long pos; |
1349 |
|
|
|
1350 |
|
|
vol = 127; |
1351 |
|
|
dup = 0; |
1352 |
|
|
bufsz = 0; |
1353 |
|
|
rate = DEFAULT_RATE; |
1354 |
|
|
cmin = 0; |
1355 |
|
|
cmax = 1; |
1356 |
|
|
aparams_init(&par); |
1357 |
|
|
hdr = AFILE_HDR_AUTO; |
1358 |
|
|
n_flag = 0; |
1359 |
|
|
port = NULL; |
1360 |
|
|
dev = NULL; |
1361 |
|
|
mode = 0; |
1362 |
|
|
pos = 0; |
1363 |
|
|
|
1364 |
|
|
while ((c = getopt(argc, argv, |
1365 |
|
|
"b:c:de:f:g:h:i:j:no:p:q:r:t:v:")) != -1) { |
1366 |
|
|
switch (c) { |
1367 |
|
|
case 'b': |
1368 |
|
|
if (!opt_num(optarg, 1, RATE_MAX, &bufsz)) |
1369 |
|
|
return 1; |
1370 |
|
|
break; |
1371 |
|
|
case 'c': |
1372 |
|
|
if (!opt_ch(optarg, &cmin, &cmax)) |
1373 |
|
|
return 1; |
1374 |
|
|
break; |
1375 |
|
|
case 'd': |
1376 |
|
|
log_level++; |
1377 |
|
|
break; |
1378 |
|
|
case 'e': |
1379 |
|
|
if (!opt_enc(optarg, &par)) |
1380 |
|
|
return 1; |
1381 |
|
|
break; |
1382 |
|
|
case 'f': |
1383 |
|
|
dev = optarg; |
1384 |
|
|
break; |
1385 |
|
|
case 'g': |
1386 |
|
|
if (!opt_pos(optarg, &dev_pos)) |
1387 |
|
|
return 1; |
1388 |
|
|
break; |
1389 |
|
|
case 'h': |
1390 |
|
|
if (!opt_hdr(optarg, &hdr)) |
1391 |
|
|
return 1; |
1392 |
|
|
break; |
1393 |
|
|
case 'i': |
1394 |
|
|
if (!slot_new(optarg, SIO_PLAY, |
1395 |
|
|
&par, hdr, cmin, cmax, rate, dup, vol, pos)) |
1396 |
|
|
return 1; |
1397 |
|
|
mode |= SIO_PLAY; |
1398 |
|
|
break; |
1399 |
|
|
case 'j': |
1400 |
|
|
if (!opt_onoff(optarg, &dup)) |
1401 |
|
|
return 1; |
1402 |
|
|
break; |
1403 |
|
|
case 'n': |
1404 |
|
|
n_flag = 1; |
1405 |
|
|
break; |
1406 |
|
|
case 'o': |
1407 |
|
|
if (!slot_new(optarg, SIO_REC, |
1408 |
|
|
&par, hdr, cmin, cmax, rate, dup, 0, pos)) |
1409 |
|
|
return 1; |
1410 |
|
|
mode |= SIO_REC; |
1411 |
|
|
break; |
1412 |
|
|
case 'p': |
1413 |
|
|
if (!opt_pos(optarg, &pos)) |
1414 |
|
|
return 1; |
1415 |
|
|
break; |
1416 |
|
|
case 'q': |
1417 |
|
|
port = optarg; |
1418 |
|
|
break; |
1419 |
|
|
case 'r': |
1420 |
|
|
if (!opt_num(optarg, RATE_MIN, RATE_MAX, &rate)) |
1421 |
|
|
return 1; |
1422 |
|
|
break; |
1423 |
|
|
case 'v': |
1424 |
|
|
if (!opt_num(optarg, 0, MIDI_MAXCTL, &vol)) |
1425 |
|
|
return 1; |
1426 |
|
|
break; |
1427 |
|
|
default: |
1428 |
|
|
goto bad_usage; |
1429 |
|
|
} |
1430 |
|
|
} |
1431 |
|
|
argc -= optind; |
1432 |
|
|
argv += optind; |
1433 |
|
|
if (argc != 0) { |
1434 |
|
|
bad_usage: |
1435 |
|
|
log_puts(usagestr); |
1436 |
|
|
return 1; |
1437 |
|
|
} |
1438 |
|
|
if (n_flag) { |
1439 |
|
|
if (dev != NULL || port != NULL) { |
1440 |
|
|
log_puts("-f and -q make no sense in off-line mode\n"); |
1441 |
|
|
return 1; |
1442 |
|
|
} |
1443 |
|
|
if (mode != (SIO_PLAY | SIO_REC)) { |
1444 |
|
|
log_puts("both -i and -o required\n"); |
1445 |
|
|
return 1; |
1446 |
|
|
} |
1447 |
|
|
if (!offline()) |
1448 |
|
|
return 1; |
1449 |
|
|
} else { |
1450 |
|
|
if (dev == NULL) |
1451 |
|
|
dev = SIO_DEVANY; |
1452 |
|
|
if (mode == 0) { |
1453 |
|
|
log_puts("at least -i or -o required\n"); |
1454 |
|
|
return 1; |
1455 |
|
|
} |
1456 |
|
|
if (!playrec(dev, mode, bufsz, port)) |
1457 |
|
|
return 1; |
1458 |
|
|
} |
1459 |
|
|
return 0; |
1460 |
|
|
} |