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