diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2011-10-12 07:20:05 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2011-10-12 07:20:05 +0000 |
commit | 1000619d5c878b666a9d2ca0f084116e0db82287 (patch) | |
tree | 9780ea7d5f9aa13502408ac23af531e6a4cdc9bf | |
parent | 8cca00d73e143fc10aa31d89c64de9c96fef267e (diff) |
Simplify and improve the way options are parsed and remove ~300 lines
of code that becomes unused. Few command line arguments changes are
required though:
- stream definitions (-ios) now must follow devices definitions they
are attached to (-fMn)
- the -n option is now a special "loopback" device and is thus used
like -f, eg it must precede streams
- in midicat, midi thru boxes are not created automatically anymore,
the new "-M" option must be used for that
- channel numbers (-Cc options) correspond always to channel numbers
of the hardware.
- the -u option isn't needed anymore
- increase the log verbosity so user errors are logged
without using -d
tested by many, help from jmc
-rw-r--r-- | usr.bin/aucat/abuf.c | 4 | ||||
-rw-r--r-- | usr.bin/aucat/aucat.1 | 114 | ||||
-rw-r--r-- | usr.bin/aucat/aucat.c | 927 | ||||
-rw-r--r-- | usr.bin/aucat/conf.h | 6 | ||||
-rw-r--r-- | usr.bin/aucat/dev.c | 188 | ||||
-rw-r--r-- | usr.bin/aucat/dev.h | 11 | ||||
-rw-r--r-- | usr.bin/aucat/file.c | 11 | ||||
-rw-r--r-- | usr.bin/aucat/headers.c | 6 | ||||
-rw-r--r-- | usr.bin/aucat/listen.c | 48 | ||||
-rw-r--r-- | usr.bin/aucat/listen.h | 6 | ||||
-rw-r--r-- | usr.bin/aucat/midi.c | 8 | ||||
-rw-r--r-- | usr.bin/aucat/midicat.1 | 46 | ||||
-rw-r--r-- | usr.bin/aucat/opt.c | 48 | ||||
-rw-r--r-- | usr.bin/aucat/opt.h | 9 | ||||
-rw-r--r-- | usr.bin/aucat/siofile.c | 18 | ||||
-rw-r--r-- | usr.bin/aucat/wav.c | 254 | ||||
-rw-r--r-- | usr.bin/aucat/wav.h | 16 |
17 files changed, 688 insertions, 1032 deletions
diff --git a/usr.bin/aucat/abuf.c b/usr.bin/aucat/abuf.c index 5e565bc0dab..c96ffbb59ff 100644 --- a/usr.bin/aucat/abuf.c +++ b/usr.bin/aucat/abuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: abuf.c,v 1.22 2010/06/04 06:15:28 ratchov Exp $ */ +/* $OpenBSD: abuf.c,v 1.23 2011/10/12 07:20:03 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -127,7 +127,7 @@ abuf_del(struct abuf *buf) } if (ABUF_ROK(buf)) { /* - * XXX : we should call abort(), here. + * XXX: we should call abort(), here. * However, poll() doesn't seem to return POLLHUP, * so the reader is never destroyed; instead it appears * as blocked. Fix file_poll(), if fixable, and add diff --git a/usr.bin/aucat/aucat.1 b/usr.bin/aucat/aucat.1 index 307733094df..c1909386f46 100644 --- a/usr.bin/aucat/aucat.1 +++ b/usr.bin/aucat/aucat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: aucat.1,v 1.86 2011/06/29 07:39:02 ratchov Exp $ +.\" $OpenBSD: aucat.1,v 1.87 2011/10/12 07:20:03 ratchov Exp $ .\" .\" Copyright (c) 2006 Alexandre Ratchov <alex@caoua.org> .\" @@ -14,16 +14,16 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 29 2011 $ +.Dd $Mdocdate: October 12 2011 $ .Dt AUCAT 1 .Os .Sh NAME .Nm aucat -.Nd audio server and stream manipulation tool +.Nd audio/MIDI server and stream manipulation tool .Sh SYNOPSIS .Nm aucat .Bk -words -.Op Fl dln +.Op Fl dlMn .Op Fl a Ar flag .Op Fl b Ar nframes .Op Fl C Ar min : Ns Ar max @@ -36,12 +36,11 @@ .Op Fl L Ar addr .Op Fl m Ar mode .Op Fl o Ar file -.Op Fl q Ar device +.Op Fl q Ar port .Op Fl r Ar rate .Op Fl s Ar name .Op Fl t Ar mode .Op Fl U Ar unit -.Op Fl u Ar flag .Op Fl v Ar volume .Op Fl w Ar flag .Op Fl x Ar policy @@ -112,13 +111,14 @@ The default is signed, 16-bit, native byte order. Add this .Xr sndio 7 audio device to devices used for playing and/or recording. -Preceding streams -.Pq Fl ios , -control MIDI ports -.Pq Fl q , -and per-device options -.Pq Fl abuwz +Preceding per-device options +.Pq Fl abwz apply to this device. +Streams +.Pq Fl ios +and control MIDI ports +.Pq Fl q +that are applied after will be attached to this device. Device mode and parameters are determined from streams attached to it. .It Fl h Ar fmt @@ -162,33 +162,61 @@ then will accept connections from any address. .It Fl l Detach and become a daemon. +.It Fl M +Create a MIDI thru box +.Pq i.e. MIDI-only pseudo device . +It merges any number of MIDI inputs and broadcasts the result +to any number of MIDI outputs, similarly to a hardware MIDI thru box. +Only MIDI ports +.Pq Fl q +and MIDI files +.Po +.Fl io +preceded by +.Fl m Ar midi +.Pc +can be attached to it. +If sub-devices are exposed +.Pq Fl s +they behave like software MIDI ports, +allowing any MIDI-capable application to send MIDI messages to +MIDI hardware or to another application in a uniform way. .It Fl m Ar mode Set the stream mode. Valid modes are .Ar play , .Ar rec , -and .Ar mon , -corresponding to playback, recording and monitoring. +and +.Ar midi , +corresponding to playback, recording, monitoring and MIDI control. A monitoring stream is a fake recording stream corresponding to the mix of all playback streams. Multiple modes can be specified, separated by commas, but the same stream cannot be used for both recording and monitoring. The default is -.Ar play , Ns Ar rec -(i.e. full-duplex). +.Ar play , Ns Ar rec , Ns Ar midi +(i.e. full-duplex with MIDI control enabled). .It Fl n -Loopback mode. -Instead of using audio devices, send input streams +Create a loopback pseudo audio device. +Send input streams to the output, processing them on the fly. -This mode is useful to mix, demultiplex, resample or reencode +This pseudo-device is useful to mix, demultiplex, resample or re-encode audio files offline. +It requires at least one input +.Pq Fl i +and one output +.Pq Fl o . +It doesn't support MIDI control +.Pq Fl q +and can't expose sub-devices +.Pq Fl s . .It Fl o Ar file Add this file to the list of recording streams. If the option argument is .Sq - then standard output will be used. -.It Fl q Ar device +.It Fl q Ar port Expose the audio device clock on this .Xr sndio 7 MIDI port and allow audio device properties to be controlled @@ -239,21 +267,9 @@ used in .Xr sndio 7 device names. The default is 0. -.It Fl u Ar flag -Control how parameters of the audio device are chosen. -If the flag is -.Va on -then -.Nm -tries to automatically determine the optimal parameters to -match stream parameters and avoid conversions if possible. -If the flag is -.Va off -it will instead use the parameters specified by the -.Fl Ccer -options. -The default is -.Va on . +The unit number must be set before any server-specific +options are used +.Pq Fl Ls . .It Fl v Ar volume Software volume attenuation of the playback stream. The value must be between 1 and 127, @@ -326,9 +342,9 @@ to a 400 frame block size. .Pp On the command line, per-device parameters -.Pq Fl abuwz +.Pq Fl abwz must precede the device definition -.Pq Fl f , +.Pq Fl fMn , and per-stream parameters .Pq Fl Ccehjmrtvx must precede the stream definition @@ -337,24 +353,32 @@ MIDI ports .Pq Fl q and stream definitions .Pq Fl ios -must precede the definition of the device -.Pq Fl f +must follow the definition of the device +.Pq Fl fMn to which they are attached. Global parameters -.Pq Fl dlnUu +.Pq Fl dl are position-independent. .Pp If no audio devices -.Pq Fl f +.Pq Fl fMn are specified, settings are applied as if -the default device is specified as the last argument. +the default device is specified. If no streams .Pq Fl ios are specified for a device, a default server sub-device is created attached to it, meaning that .Nm behaves as an audio server. +If a device +.Pq Fl fMn +is defined twice, both definitions are merged: +parameters of the first one are used but streams +.Pq Fl ios +and MIDI control ports +.Pq Fl q +of both definitions are created. The default .Xr sndio 7 device is @@ -569,7 +593,7 @@ connected to the .Va midithru:0 MIDI device: .Bd -literal -offset indent -$ aucat -t slave -q midithru:0 -i file.wav -f aucat:0.mmc +$ aucat -f aucat:0.mmc -t slave -q midithru:0 -i file.wav .Ed .Pp At this stage, @@ -682,3 +706,7 @@ To avoid this, .Fl a Ar off is disabled for the default audio device, but nothing prevents the user from shooting himself in the foot by creating a similar deadlock. +.Pp +The ability to merge multiple inputs is provided to allow multiple +applications producing MIDI data to keep their connection open while +idling; it does not replace a fully featured MIDI merger. diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c index ead5162e571..9c614b3e7d4 100644 --- a/usr.bin/aucat/aucat.c +++ b/usr.bin/aucat/aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.119 2011/06/29 07:39:02 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.120 2011/10/12 07:20:03 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -65,11 +65,29 @@ #define DEFAULT_RATE 44100 #endif +/* + * block size if no ``-z'' is used + */ +#ifndef DEFAULT_ROUND +#define DEFAULT_ROUND (44100 / 15) +#endif + #ifdef DEBUG -volatile sig_atomic_t debug_level = 0; +volatile sig_atomic_t debug_level = 1; #endif volatile sig_atomic_t quit_flag = 0; +char aucat_usage[] = "usage: " PROG_AUCAT " [-dlMn] [-a flag] [-b nframes] " + "[-C min:max] [-c min:max] [-e enc]\n\t" + "[-f device] [-h fmt] [-i file] [-j flag] [-L addr] [-m mode] " + "[-o file]\n\t" + "[-q port] [-r rate] [-s name] [-t mode] [-U unit] [-v volume]\n\t" + "[-w flag] [-x policy] [-z nframes]\n"; + +char midicat_usage[] = "usage: " PROG_MIDICAT " [-dlM] [-a flag] " + "[-i file] [-L addr] [-s name] [-o file]\n\t" + "[-q port] [-U unit]\n"; + /* * SIGINT handler, it raises the quit flag. If the flag is already set, * that means that the last SIGINT was not handled, because the process @@ -196,9 +214,8 @@ opt_mode(void) mode |= MODE_REC; } else if (strncmp("mon", p, len) == 0) { mode |= MODE_MON; - } else if (strncmp("duplex", p, len) == 0) { - /* XXX: backward compat, remove this */ - mode |= MODE_REC | MODE_PLAY; + } else if (strncmp("midi", p, len) == 0) { + mode |= MODE_MIDIMASK; } else errx(1, "%s: bad mode", optarg); p += len; @@ -210,163 +227,6 @@ opt_mode(void) return mode; } -/* - * stream configuration - */ -struct cfstr { - SLIST_ENTRY(cfstr) entry; - unsigned mode; /* bitmap of MODE_XXX */ - struct aparams ipar; /* input (read) parameters */ - struct aparams opar; /* output (write) parameters */ - unsigned vol; /* last requested volume */ - int hdr; /* header format */ - int xrun; /* overrun/underrun policy */ - int mmc; /* MMC mode */ - int join; /* join/expand enabled */ - char *path; /* static path (no need to copy it) */ -}; - -SLIST_HEAD(cfstrlist, cfstr); - -/* - * midi device (control stream) - */ -struct cfmid { - SLIST_ENTRY(cfmid) entry; - char *path; /* static path (no need to copy it) */ -}; - -SLIST_HEAD(cfmidlist, cfmid); - -/* - * audio device configuration - */ -struct cfdev { - SLIST_ENTRY(cfdev) entry; - struct cfstrlist ins; /* files to play */ - struct cfstrlist outs; /* files to record */ - struct cfstrlist opts; /* subdevices to expose */ - struct cfmidlist mids; /* midi ports to subscribe */ - struct aparams ipar; /* input (read) parameters */ - struct aparams opar; /* output (write) parameters */ - unsigned hold; /* open immediately */ - unsigned autovol; /* adjust volumes */ - unsigned autopar; /* adjust parameters to streams */ - unsigned bufsz; /* par.bufsz for sio device */ - unsigned round; /* par.round for sio device */ - unsigned mode; /* bitmap of MODE_XXX */ - char *path; /* static path (no need to copy it) */ -}; - -SLIST_HEAD(cfdevlist, cfdev); - -/* - * local network addresse to listen on - */ -struct cfnet { - SLIST_ENTRY(cfnet) entry; - char *addr; -}; - -SLIST_HEAD(cfnetlist, cfnet); - -struct cfdev * -cfdev_new(struct cfdev *templ) -{ - struct cfdev *cd; - - cd = malloc(sizeof(struct cfdev)); - if (cd == NULL) { - perror("malloc"); - abort(); - } - if (templ) - memcpy(cd, templ, sizeof(struct cfdev)); - else { - aparams_init(&cd->ipar, 0, 1, DEFAULT_RATE); - aparams_init(&cd->opar, 0, 1, DEFAULT_RATE); - cd->bufsz = 0; - cd->round = 0; - cd->hold = 1; - cd->autovol = 1; - cd->autopar = 1; - } - SLIST_INIT(&cd->ins); - SLIST_INIT(&cd->outs); - SLIST_INIT(&cd->opts); - SLIST_INIT(&cd->mids); - cd->path = NULL; - return cd; -} - -void -cfdev_add(struct cfdevlist *list, struct cfdev *cd, char *path) -{ - cd->path = path; - SLIST_INSERT_HEAD(list, cd, entry); -} - -struct cfstr * -cfstr_new(struct cfstr *templ) -{ - struct cfstr *cs; - - cs = malloc(sizeof(struct cfstr)); - if (cs == NULL) { - perror("malloc"); - abort(); - } - if (templ) - memcpy(cs, templ, sizeof(struct cfstr)); - else { - aparams_init(&cs->ipar, 0, 1, DEFAULT_RATE); - aparams_init(&cs->opar, 0, 1, DEFAULT_RATE); - cs->mmc = 0; - cs->hdr = HDR_AUTO; - cs->xrun = XRUN_IGNORE; - cs->vol = MIDI_MAXCTL; - cs->mode = MODE_PLAY | MODE_REC; - cs->join = 1; - } - cs->path = NULL; - return cs; -} - -void -cfstr_add(struct cfstrlist *list, struct cfstr *cs, char *path) -{ - cs->path = path; - SLIST_INSERT_HEAD(list, cs, entry); -} - -void -cfmid_add(struct cfmidlist *list, char *path) -{ - struct cfmid *cm; - - cm = malloc(sizeof(struct cfmid)); - if (cm == NULL) { - perror("malloc"); - abort(); - } - cm->path = path; - SLIST_INSERT_HEAD(list, cm, entry); -} - -void -cfnet_add(struct cfnetlist *list, char *addr) -{ - struct cfnet *cn; - - cn = malloc(sizeof(struct cfnet)); - if (cn == NULL) { - perror("malloc"); - abort(); - } - cn->addr = addr; - SLIST_INSERT_HEAD(list, cn, entry); -} - void setsig(void) { @@ -459,363 +319,274 @@ privdrop(void) err(1, "cannot drop privileges"); } -void -aucat_usage(void) +struct dev * +mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol) +{ + struct dev *d; + + if (path) { + for (d = dev_list; d != NULL; d = d->next) { + if (d->reqmode & (MODE_LOOP | MODE_THRU)) + continue; + if (strcmp(d->path, path) == 0) + return d; + } + } else { + if (dev_list) + return dev_list; + path = "default"; + } + if (!bufsz) { + if (!round) + round = DEFAULT_ROUND; + bufsz = round * 4; + } else if (!round) + round = bufsz / 4; + return dev_new(path, mode, bufsz, round, hold, autovol); +} + +struct opt * +mkopt(char *path, struct dev *d, struct aparams *rpar, struct aparams *ppar, + int mode, int vol, int mmc, int join) { - (void)fputs("usage: " PROG_AUCAT " [-dln] [-a flag] [-b nframes] " - "[-C min:max] [-c min:max] [-e enc]\n\t" - "[-f device] [-h fmt] [-i file] [-j flag] [-L addr] [-m mode] " - "[-o file]\n\t" - "[-q device] [-r rate] [-s name] [-t mode] [-U unit] " - "[-u flag]\nt" - "[-v volume] [-w flag] [-x policy] [-z nframes]\n", - stderr); + struct opt *o; + + if (d->reqmode & MODE_LOOP) + errx(1, "%s: can't attach to loopback", path); + if (d->reqmode & MODE_THRU) + mode = MODE_MIDIMASK; + if (!rpar->rate) + ppar->rate = rpar->rate = DEFAULT_RATE; + o = opt_new(path, d, rpar, ppar, MIDI_TO_ADATA(vol), mmc, join, mode); + if (o == NULL) + errx(1, "%s: couldn't create subdev", path); + dev_adjpar(d, o->mode, rpar, ppar); + return o; } int -aucat_main(int argc, char **argv) +main(int argc, char **argv) { - struct cfdevlist cfdevs; - struct cfnetlist cfnets; - struct cfmid *cm; - struct cfstr *cs; - struct cfdev *cd; - struct cfnet *cn; - int c, d_flag, l_flag, n_flag, unit; + char *prog, *un_path, *optstr, *usagestr; + int c, background, unit, server, tcp_port, active; char base[PATH_MAX], path[PATH_MAX]; - unsigned mode, rate; + unsigned mode, hdr, xrun, rate, join, mmc, vol; + unsigned hold, autovol, bufsz, round; const char *str; - int autostart; + struct aparams ppar, rpar; struct dev *d, *dnext; - unsigned active; - unsigned nsock; + struct listen *l; + struct wav *w; /* * global options defaults */ - unit = -1; - d_flag = 0; - l_flag = 0; - n_flag = 0; - SLIST_INIT(&cfdevs); - SLIST_INIT(&cfnets); - nsock = 0; + hdr = HDR_AUTO; + xrun = XRUN_IGNORE; + vol = MIDI_MAXCTL; + hold = join = autovol = 1; + mmc = 0; + bufsz = 0; + round = 0; + unit = 0; + background = 0; + aparams_init(&ppar, 0, 1, DEFAULT_RATE); + aparams_init(&rpar, 0, 1, DEFAULT_RATE); + server = 0; - /* - * default device and stream - */ - cd = cfdev_new(NULL); - cs = cfstr_new(NULL); +#ifdef DEBUG + atexit(dbg_flush); +#endif + setsig(); + filelist_init(); - while ((c = getopt(argc, argv, "a:w:dnb:c:C:e:r:h:x:v:i:o:f:m:lu:q:s:U:L:t:j:z:")) != -1) { + prog = strrchr(argv[0], '/'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + if (strcmp(prog, PROG_AUCAT) == 0) { + mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC; + optstr = "a:b:c:C:de:f:h:i:j:lL:m:Mno:q:r:s:t:U:v:w:x:z:t:j:z:"; + usagestr = aucat_usage; + un_path = AUCAT_PATH; + tcp_port = AUCAT_PORT; + } else if (strcmp(prog, PROG_MIDICAT) == 0) { + mode = MODE_MIDIMASK | MODE_THRU; + optstr = "a:di:lL:Mo:q:s:U:"; + usagestr = midicat_usage; + un_path = MIDICAT_PATH; + tcp_port = MIDICAT_PORT; + mkdev("midithru", MODE_THRU, 0, 0, 1, 0); + } else { + fprintf(stderr, "%s: can't determine program to run\n", prog); + return 1; + } + + + while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'd': #ifdef DEBUG - if (d_flag) + if (debug_level < 4) debug_level++; #endif - d_flag = 1; - break; - case 'n': - n_flag = 1; break; case 'U': + if (server) + errx(1, "-U must come before server options"); unit = strtonum(optarg, 0, MIDI_MAXCTL, &str); if (str) errx(1, "%s: unit number is %s", optarg, str); + server = 1; break; case 'L': - cfnet_add(&cfnets, optarg); + listen_new_tcp(optarg, tcp_port + unit); + server = 1; break; case 'm': - cs->mode = opt_mode(); + mode = opt_mode(); break; case 'h': - cs->hdr = opt_hdr(); + hdr = opt_hdr(); break; case 'x': - cs->xrun = opt_xrun(); + xrun = opt_xrun(); break; case 'j': - cs->join = opt_onoff(); + join = opt_onoff(); break; case 't': - cs->mmc = opt_mmc(); + mmc = opt_mmc(); break; case 'c': - opt_ch(&cs->ipar); - cd->opar.cmin = cs->ipar.cmin; - cd->opar.cmax = cs->ipar.cmax; + opt_ch(&ppar); break; case 'C': - opt_ch(&cs->opar); - cd->ipar.cmin = cs->opar.cmin; - cd->ipar.cmax = cs->opar.cmax; + opt_ch(&rpar); break; case 'e': - opt_enc(&cs->ipar); - aparams_copyenc(&cs->opar, &cs->ipar); - aparams_copyenc(&cd->ipar, &cs->ipar); - aparams_copyenc(&cd->opar, &cd->ipar); + opt_enc(&ppar); + aparams_copyenc(&rpar, &ppar); break; case 'r': rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str); if (str) errx(1, "%s: rate is %s", optarg, str); - cs->opar.rate = cs->ipar.rate = rate; - cd->ipar.rate = cd->opar.rate = rate; + ppar.rate = rpar.rate = rate; break; case 'v': - cs->vol = strtonum(optarg, 0, MIDI_MAXCTL, &str); + vol = strtonum(optarg, 0, MIDI_MAXCTL, &str); if (str) errx(1, "%s: volume is %s", optarg, str); break; case 'i': - cfstr_add(&cd->ins, cs, optarg); - cs = cfstr_new(cs); - break; - case 'o': - cfstr_add(&cd->outs, cs, optarg); - cs = cfstr_new(cs); + d = mkdev(NULL, 0, bufsz, round, 1, autovol); + w = wav_new_in(&wav_ops, d, + mode & (MODE_PLAY | MODE_MIDIOUT), optarg, + hdr, &ppar, xrun, vol, mmc, join); + if (w == NULL) + errx(1, "%s: couldn't create stream", optarg); + dev_adjpar(d, w->mode, NULL, &w->hpar); + break; + case 'o': + d = mkdev(NULL, 0, bufsz, round, 1, autovol); + w = wav_new_out(&wav_ops, d, + mode & (MODE_RECMASK | MODE_MIDIIN), optarg, + hdr, &rpar, xrun, mmc, join); + if (w == NULL) + errx(1, "%s: couldn't create stream", optarg); + dev_adjpar(d, w->mode, &w->hpar, NULL); break; case 's': - cfstr_add(&cd->opts, cs, optarg); - cs = cfstr_new(cs); - nsock++; + d = mkdev(NULL, 0, bufsz, round, 1, autovol); + mkopt(optarg, d, &rpar, &ppar, + mode, vol, mmc, join); + /* XXX: set device rate, if never set */ + server = 1; + break; + case 'q': + d = mkdev(NULL, mode, bufsz, round, 1, autovol); + if (!devctl_add(d, optarg, MODE_MIDIMASK)) + errx(1, "%s: can't open port", optarg); + d->reqmode |= MODE_MIDIMASK; break; case 'a': - cd->hold = opt_onoff(); + hold = opt_onoff(); break; case 'w': - cd->autovol = opt_onoff(); - break; - case 'u': - cd->autopar = opt_onoff(); - break; - case 'q': - cfmid_add(&cd->mids, optarg); + autovol = opt_onoff(); break; case 'b': - cd->bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str); + bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str); if (str) errx(1, "%s: buffer size is %s", optarg, str); break; case 'z': - cd->round = strtonum(optarg, 1, SHRT_MAX, &str); + round = strtonum(optarg, 1, SHRT_MAX, &str); if (str) errx(1, "%s: block size is %s", optarg, str); break; case 'f': - if (SLIST_EMPTY(&cd->opts) && - SLIST_EMPTY(&cd->ins) && - SLIST_EMPTY(&cd->outs)) { - cfstr_add(&cd->opts, cs, DEFAULT_OPT); - cs = cfstr_new(cs); - nsock++; - } - cfdev_add(&cfdevs, cd, optarg); - cd = cfdev_new(cd); + mkdev(optarg, 0, bufsz, round, hold, autovol); + break; + case 'n': + mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol); + break; + case 'M': + mkdev("midithru", MODE_THRU, 0, 0, 1, 0); break; case 'l': - l_flag = 1; - autostart = 0; + background = 1; break; default: - aucat_usage(); + fputs(usagestr, stderr); exit(1); } } argc -= optind; argv += optind; - -#ifdef DEBUG - if (debug_level == 0) - debug_level = 1; -#endif if (argc > 0) { - aucat_usage(); + fputs(usagestr, stderr); exit(1); } - - /* - * Check constraints specific to -n option - */ - if (n_flag) { - if (!SLIST_EMPTY(&cfdevs) || - !SLIST_EMPTY(&cd->mids) || - !SLIST_EMPTY(&cd->opts)) - errx(1, "-f, -s, and -q not allowed in loopback mode"); - if (SLIST_EMPTY(&cd->ins) || SLIST_EMPTY(&cd->outs)) - errx(1, "-i and -o are required in loopback mode"); - } - - /* - * If there's no device specified, do as if the default - * device is specified as last argument. - */ - if (SLIST_EMPTY(&cfdevs)) { - if (SLIST_EMPTY(&cd->opts) && - SLIST_EMPTY(&cd->ins) && - SLIST_EMPTY(&cd->outs)) { - cfstr_add(&cd->opts, cs, DEFAULT_OPT); - nsock++; - } else - free(cs); - if (!cd->hold) - errx(1, "-a off not compatible with default device"); - cfdev_add(&cfdevs, cd, "default"); - } else { - if (!SLIST_EMPTY(&cd->opts) || - !SLIST_EMPTY(&cd->ins) || - !SLIST_EMPTY(&cd->outs) || - !SLIST_EMPTY(&cd->outs)) - errx(1, "no device to attach last stream to"); - free(cs); - free(cd); - } - - /* - * Check modes and calculate "best" device parameters. Iterate over all - * inputs and outputs and find the maximum sample rate and channel - * number. - */ - SLIST_FOREACH(cd, &cfdevs, entry) { - mode = 0; - if (cd->autopar) { - aparams_init(&cd->opar, NCHAN_MAX - 1, 0, RATE_MIN); - aparams_init(&cd->opar, NCHAN_MAX - 1, 0, RATE_MIN); + if (wav_list == NULL) { + if (opt_list == NULL) { + d = mkdev(NULL, 0, bufsz, round, 1, autovol); + mkopt("default", d, &rpar, &ppar, + mode, vol, mmc, join); + server = 1; } - SLIST_FOREACH(cs, &cd->ins, entry) { - if (cs->mode == 0) - errx(1, "%s: not in play mode", cs->path); - mode |= (cs->mode & MODE_PLAY); - if (cd->autopar) - aparams_grow(&cd->opar, &cs->ipar); - } - SLIST_FOREACH(cs, &cd->outs, entry) { - if (cs->mode == 0) - errx(1, "%s: not in rec/mon mode", cs->path); - if ((cs->mode & MODE_REC) && (cs->mode & MODE_MON)) - errx(1, "%s: can't rec and mon", cs->path); - mode |= (cs->mode & MODE_RECMASK); - if (cd->autopar) - aparams_grow(&cd->ipar, &cs->opar); - } - SLIST_FOREACH(cs, &cd->opts, entry) { - if ((cs->mode & MODE_REC) && (cs->mode & MODE_MON)) - errx(1, "%s: can't rec and mon", cs->path); - mode |= (cs->mode & (MODE_RECMASK | MODE_PLAY)); - if (cd->autopar) { - aparams_grow(&cd->opar, &cs->ipar); - aparams_grow(&cd->ipar, &cs->opar); - } + } else { + d = mkdev(NULL, 0, bufsz, round, 1, autovol); + if ((d->reqmode & MODE_THRU) && !d->ctl_list) { + if (!devctl_add(d, "default", MODE_MIDIMASK)) + errx(1, "%s: can't open port", optarg); + d->reqmode |= MODE_MIDIMASK; } - if ((mode & MODE_MON) && !(mode & MODE_PLAY)) - errx(1, "no playback stream to monitor"); - if (n_flag && (mode & MODE_MON)) - errx(1, "-m mon not allowed in loopback mode"); - rate = (mode & MODE_REC) ? cd->ipar.rate : cd->opar.rate; - if (!cd->round) - cd->round = rate / 15; - if (!cd->bufsz) - cd->bufsz = rate / 15 * 4; - cd->mode = mode; } - if (nsock > 0) { + if (server) { getbasepath(base, sizeof(base)); - if (unit < 0) - unit = 0; + snprintf(path, PATH_MAX, "%s/%s%u", base, un_path, unit); + listen_new_un(path); + if (geteuid() == 0) + privdrop(); } - setsig(); - filelist_init(); - - /* - * Open devices - */ - while (!SLIST_EMPTY(&cfdevs)) { - cd = SLIST_FIRST(&cfdevs); - SLIST_REMOVE_HEAD(&cfdevs, entry); - - if (n_flag) { - d = dev_new_loop(&cd->ipar, &cd->opar, cd->bufsz); - } else { - d = dev_new_sio(cd->path, cd->mode | MODE_MIDIMASK, - &cd->ipar, &cd->opar, cd->bufsz, cd->round, - cd->hold, cd->autovol); - } - if (d == NULL) - errx(1, "%s: can't open device", cd->path); - - /* - * register midi devices - */ - while (!SLIST_EMPTY(&cd->mids)) { - cm = SLIST_FIRST(&cd->mids); - SLIST_REMOVE_HEAD(&cd->mids, entry); - if (!devctl_add(d, cm->path, MODE_MIDIMASK)) - errx(1, "%s: can't open port", cm->path); - free(cm); - } - - /* - * register files - */ - autostart = 0; - while (!SLIST_EMPTY(&cd->ins)) { - cs = SLIST_FIRST(&cd->ins); - SLIST_REMOVE_HEAD(&cd->ins, entry); - if (!cs->mmc) - autostart = 1; - if (strcmp(cs->path, "-") == 0) - cs->path = NULL; - if (!wav_new_in(&wav_ops, d, cs->mode & MODE_PLAY, - cs->path, cs->hdr, &cs->ipar, cs->xrun, - cs->vol, cs->mmc, cs->join)) - exit(1); - free(cs); - } - while (!SLIST_EMPTY(&cd->outs)) { - cs = SLIST_FIRST(&cd->outs); - SLIST_REMOVE_HEAD(&cd->outs, entry); - if (!cs->mmc) - autostart = 1; - if (strcmp(cs->path, "-") == 0) - cs->path = NULL; - if (!wav_new_out(&wav_ops, d, cs->mode & MODE_RECMASK, - cs->path, cs->hdr, &cs->opar, cs->xrun, - cs->mmc, cs->join)) - exit(1); - free(cs); - } - while (!SLIST_EMPTY(&cd->opts)) { - cs = SLIST_FIRST(&cd->opts); - SLIST_REMOVE_HEAD(&cd->opts, entry); - opt_new(cs->path, d, &cs->opar, &cs->ipar, - MIDI_TO_ADATA(cs->vol), cs->mmc, - cs->join, cs->mode | MODE_MIDIMASK); - free(cs); - } - free(cd); - if (autostart) { - /* - * inject artificial mmc start - */ + for (w = wav_list; w != NULL; w = w->next) { + if (!wav_init(w)) + exit(1); + } + for (d = dev_list; d != NULL; d = d->next) { + if (!dev_init(d)) + exit(1); + if (d->autostart && (d->mode & MODE_AUDIOMASK)) ctl_start(d->midi); - } } - if (nsock > 0) { - snprintf(path, sizeof(path), "%s/%s%u", base, - AUCAT_PATH, unit); - listen_new_un(path); - while (!SLIST_EMPTY(&cfnets)) { - cn = SLIST_FIRST(&cfnets); - SLIST_REMOVE_HEAD(&cfnets, entry); - listen_new_tcp(cn->addr, AUCAT_PORT + unit); - } + for (l = listen_list; l != NULL; l = l->next) { + if (!listen_init(l)) + exit(1); } - if (geteuid() == 0) - privdrop(); - if (l_flag) { + if (background) { #ifdef DEBUG debug_level = 0; dbg_flush(); @@ -835,18 +606,20 @@ aucat_main(int argc, char **argv) dnext = d->next; if (!dev_run(d)) goto fatal; - if (d->pstate != DEV_CLOSED && !ctl_idle(d->midi)) + if ((d->mode & MODE_THRU) || + (d->pstate != DEV_CLOSED && !ctl_idle(d->midi))) active = 1; } if (dev_list == NULL) break; - if (nsock == 0 && !active) + if (!server && !active) break; if (!file_poll()) break; } fatal: - listen_closeall(); + while (listen_list != NULL) + file_close(&listen_list->file); /* * give a chance to drain @@ -859,296 +632,10 @@ aucat_main(int argc, char **argv) while (dev_list) dev_del(dev_list); filelist_done(); - if (nsock > 0) { + if (server) { if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) warn("rmdir(\"%s\")", base); } unsetsig(); return 0; } - -void -midicat_usage(void) -{ - (void)fputs("usage: " PROG_MIDICAT " [-dl] [-a flag] " - "[-i file] [-L addr] [-o file] [-q port]\n\t" - "[-s name] [-U unit]\n", - stderr); -} - -int -midicat_main(int argc, char **argv) -{ - struct cfdevlist cfdevs; - struct cfnetlist cfnets; - struct cfmid *cm; - struct cfstr *cs; - struct cfdev *cd; - struct cfnet *cn; - int c, d_flag, l_flag, unit, fd; - char base[PATH_MAX], path[PATH_MAX]; - struct file *stdx; - struct aproc *p; - struct abuf *buf; - const char *str; - struct dev *d, *dnext; - unsigned nsock; - - /* - * global options defaults - */ - unit = -1; - d_flag = 0; - l_flag = 0; - SLIST_INIT(&cfdevs); - SLIST_INIT(&cfnets); - nsock = 0; - - /* - * default device and stream - */ - cs = cfstr_new(NULL); - cd = cfdev_new(NULL); - - while ((c = getopt(argc, argv, "di:o:ls:a:q:U:L:")) != -1) { - switch (c) { - case 'd': -#ifdef DEBUG - if (d_flag) - debug_level++; -#endif - d_flag = 1; - break; - case 'i': - cfstr_add(&cd->ins, cs, optarg); - cs = cfstr_new(cs); - break; - case 'o': - cfstr_add(&cd->outs, cs, optarg); - cs = cfstr_new(cs); - break; - case 'a': - cd->hold = opt_onoff(); - break; - case 'q': - cfmid_add(&cd->mids, optarg); - break; - case 's': - cfstr_add(&cd->opts, cs, optarg); - cfdev_add(&cfdevs, cd, optarg); - cd = cfdev_new(cd); - cs = cfstr_new(NULL); - nsock++; - break; - case 'l': - l_flag = 1; - break; - case 'U': - unit = strtonum(optarg, 0, MIDI_MAXCTL, &str); - if (str) - errx(1, "%s: unit number is %s", optarg, str); - break; - case 'L': - cfnet_add(&cfnets, optarg); - break; - default: - midicat_usage(); - exit(1); - } - } - argc -= optind; - argv += optind; - -#ifdef DEBUG - if (debug_level == 0) - debug_level = 1; -#endif - if (argc > 0) { - midicat_usage(); - exit(1); - } - - /* - * If there's no device specified (-s), then create one with - * reasonable defaults: - * - * - if there are no streams (-ioq) defined, assume server mode - * and expose the "defaut" option - * - * - if there are files (-io) but no ports (-q) to send/receive - * from, add the default sndio(7) MIDI port - */ - if (SLIST_EMPTY(&cfdevs)) { - if (SLIST_EMPTY(&cd->mids)) { - if (SLIST_EMPTY(&cd->ins) && SLIST_EMPTY(&cd->outs)) { - cfstr_add(&cd->opts, cs, DEFAULT_OPT); - nsock++; - } else { - cfmid_add(&cd->mids, "default"); - free(cs); - } - } else - free(cs); - cfdev_add(&cfdevs, cd, "default"); - } else { - free(cs); - free(cd); - } - if (nsock > 0) { - getbasepath(base, sizeof(path)); - if (unit < 0) - unit = 0; - } - setsig(); - filelist_init(); - - while (!SLIST_EMPTY(&cfdevs)) { - cd = SLIST_FIRST(&cfdevs); - SLIST_REMOVE_HEAD(&cfdevs, entry); - - d = dev_new_thru(cd->hold); - if (d == NULL) - errx(1, "%s: can't open device", cd->path); - if (SLIST_EMPTY(&cd->opts) && APROC_OK(d->midi)) - d->midi->flags |= APROC_QUIT; - - /* - * register midi ports - */ - while (!SLIST_EMPTY(&cd->mids)) { - cm = SLIST_FIRST(&cd->mids); - SLIST_REMOVE_HEAD(&cd->mids, entry); - if (!devctl_add(d, cm->path, MODE_MIDIMASK)) - errx(1, "%s: can't open port", cm->path); - free(cm); - } - - /* - * register files - */ - while (!SLIST_EMPTY(&cd->ins)) { - cs = SLIST_FIRST(&cd->ins); - SLIST_REMOVE_HEAD(&cd->ins, entry); - if (strcmp(cs->path, "-") == 0) { - fd = STDIN_FILENO; - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - warn("stdin"); - } else { - fd = open(cs->path, O_RDONLY | O_NONBLOCK, 0666); - if (fd < 0) - err(1, "%s", cs->path); - } - stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path); - p = rfile_new(stdx); - buf = abuf_new(MIDI_BUFSZ, &aparams_none); - aproc_setout(p, buf); - dev_midiattach(d, buf, NULL); - free(cs); - } - while (!SLIST_EMPTY(&cd->outs)) { - cs = SLIST_FIRST(&cd->outs); - SLIST_REMOVE_HEAD(&cd->outs, entry); - if (strcmp(cs->path, "-") == 0) { - fd = STDOUT_FILENO; - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - warn("stdout"); - } else { - fd = open(cs->path, - O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666); - if (fd < 0) - err(1, "%s", cs->path); - } - stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path); - p = wfile_new(stdx); - buf = abuf_new(MIDI_BUFSZ, &aparams_none); - aproc_setin(p, buf); - dev_midiattach(d, NULL, buf); - free(cs); - } - while (!SLIST_EMPTY(&cd->opts)) { - cs = SLIST_FIRST(&cd->opts); - SLIST_REMOVE_HEAD(&cd->opts, entry); - opt_new(cs->path, d, NULL, NULL, 0, 0, 0, MODE_MIDIMASK); - free(cs); - } - free(cd); - } - if (nsock > 0) { - snprintf(path, sizeof(path), "%s/%s%u", base, - MIDICAT_PATH, unit); - listen_new_un(path); - while (!SLIST_EMPTY(&cfnets)) { - cn = SLIST_FIRST(&cfnets); - SLIST_REMOVE_HEAD(&cfnets, entry); - listen_new_tcp(cn->addr, MIDICAT_PORT + unit); - } - } - if (geteuid() == 0) - privdrop(); - if (l_flag) { -#ifdef DEBUG - debug_level = 0; - dbg_flush(); -#endif - if (daemon(0, 0) < 0) - err(1, "daemon"); - } - - /* - * loop, start processing - */ - for (;;) { - if (quit_flag) - break; - for (d = dev_list; d != NULL; d = dnext) { - dnext = d->next; - if (!dev_run(d)) - goto fatal; - } - if (!file_poll()) - break; - } - fatal: - listen_closeall(); - - /* - * give a chance to drain - */ - for (d = dev_list; d != NULL; d = d->next) - dev_drain(d); - while (file_poll()) - ; /* nothing */ - - while (dev_list) - dev_del(dev_list); - filelist_done(); - if (nsock > 0) { - if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) - warn("rmdir(\"%s\")", base); - } - unsetsig(); - return 0; -} - -int -main(int argc, char **argv) -{ - char *prog; - -#ifdef DEBUG - atexit(dbg_flush); -#endif - prog = strrchr(argv[0], '/'); - if (prog == NULL) - prog = argv[0]; - else - prog++; - if (strcmp(prog, PROG_AUCAT) == 0) { - return aucat_main(argc, argv); - } else if (strcmp(prog, PROG_MIDICAT) == 0) { - return midicat_main(argc, argv); - } else { - fprintf(stderr, "%s: can't determine program to run\n", prog); - } - return 1; -} diff --git a/usr.bin/aucat/conf.h b/usr.bin/aucat/conf.h index efb64439e29..ce32140ad74 100644 --- a/usr.bin/aucat/conf.h +++ b/usr.bin/aucat/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.22 2011/04/27 21:32:40 ratchov Exp $ */ +/* $OpenBSD: conf.h,v 1.23 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -52,8 +52,10 @@ extern volatile sig_atomic_t debug_level; #define MODE_MIDIIN 0x08 /* allowed to write midi */ #define MODE_MON 0x10 /* allowed to monitor */ #define MODE_LOOP 0x20 /* deviceless mode */ +#define MODE_THRU 0x40 /* pass thru insted of device control */ +#define MODE_PLAYREC (MODE_PLAY | MODE_REC) #define MODE_RECMASK (MODE_REC | MODE_MON) -#define MODE_AUDIOMASK (MODE_REC | MODE_MON | MODE_PLAY) +#define MODE_AUDIOMASK (MODE_PLAY | MODE_REC | MODE_MON) #define MODE_MIDIMASK (MODE_MIDIIN | MODE_MIDIOUT) /* diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c index d674f2454ac..449898b1078 100644 --- a/usr.bin/aucat/dev.c +++ b/usr.bin/aucat/dev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.c,v 1.66 2011/06/20 20:18:44 ratchov Exp $ */ +/* $OpenBSD: dev.c,v 1.67 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -113,8 +113,7 @@ struct dev *dev_list = NULL; * Create a sndio device */ struct dev * -dev_new_sio(char *path, - unsigned mode, struct aparams *dipar, struct aparams *dopar, +dev_new(char *path, unsigned mode, unsigned bufsz, unsigned round, unsigned hold, unsigned autovol) { struct dev *d; @@ -127,79 +126,51 @@ dev_new_sio(char *path, d->ctl_list = NULL; d->path = path; d->reqmode = mode; - if (mode & MODE_PLAY) - d->reqopar = *dopar; - if (mode & MODE_RECMASK) - d->reqipar = *dipar; + aparams_init(&d->reqopar, NCHAN_MAX, 0, 0); + aparams_init(&d->reqipar, NCHAN_MAX, 0, 0); d->reqbufsz = bufsz; d->reqround = round; d->hold = hold; d->autovol = autovol; + d->autostart = 0; d->pstate = DEV_CLOSED; d->next = dev_list; dev_list = d; - if (d->hold && !dev_open(d)) { - dev_del(d); - return NULL; - } return d; } /* - * Create a loopback synchronous device + * adjust device parameters and mode */ -struct dev * -dev_new_loop(struct aparams *dipar, struct aparams *dopar, unsigned bufsz) +void +dev_adjpar(struct dev *d, unsigned mode, + struct aparams *ipar, struct aparams *opar) { - struct aparams par; - unsigned cmin, cmax, rate; - struct dev *d; - - d = malloc(sizeof(struct dev)); - if (d == NULL) { - perror("malloc"); - exit(1); - } - d->ctl_list = NULL; - cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin; - cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax; - rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate; - aparams_init(&par, cmin, cmax, rate); - d->reqipar = par; - d->reqopar = par; - d->rate = rate; - d->reqround = (bufsz + 1) / 2; - d->reqbufsz = d->reqround * 2; - d->reqmode = MODE_PLAY | MODE_REC | MODE_LOOP | MODE_MIDIMASK; - d->pstate = DEV_CLOSED; - d->hold = 0; - d->path = "loop"; - d->next = dev_list; - dev_list = d; - return d; + d->reqmode |= (mode | MODE_MIDIMASK); + if (mode & MODE_REC) + aparams_grow(&d->reqipar, ipar); + if (mode & MODE_PLAY) + aparams_grow(&d->reqopar, opar); } /* - * Create a MIDI thru box device + * Initialize the device with the current parameters */ -struct dev * -dev_new_thru(int hold) +int +dev_init(struct dev *d) { - struct dev *d; - - d = malloc(sizeof(struct dev)); - if (d == NULL) { - perror("malloc"); - exit(1); + if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) { +#ifdef DEBUG + dbg_puts(d->path); + dbg_puts(": has no streams, skipped\n"); +#endif + return 1; } - d->ctl_list = NULL; - d->reqmode = MODE_MIDIMASK; - d->pstate = DEV_CLOSED; - d->hold = hold; - d->path = "midithru"; - d->next = dev_list; - dev_list = d; - return d; + if (d->hold && d->pstate == DEV_CLOSED && !dev_open(d)) { + dev_del(d); + return 0; + } + return 1; } /* @@ -219,10 +190,8 @@ devctl_add(struct dev *d, char *name, unsigned mode) c->mode = mode; c->next = d->ctl_list; d->ctl_list = c; - if (d->pstate != DEV_CLOSED) { - if (!devctl_open(d, c)) - return 0; - } + if (d->pstate != DEV_CLOSED && !devctl_open(d, c)) + return 0; return 1; } @@ -265,7 +234,7 @@ dev_open(struct dev *d) struct aparams par; struct aproc *conv; struct abuf *buf; - unsigned siomode; + unsigned siomode, cmin, cmax, rate; d->mode = d->reqmode; d->round = d->reqround; @@ -281,6 +250,24 @@ dev_open(struct dev *d) d->midi = NULL; d->rate = 0; + if (d->opar.cmin > d->opar.cmax) { + d->opar.cmin = 0; + d->opar.cmax = 1; + } + if (d->ipar.cmin > d->ipar.cmax) { + d->ipar.cmin = 0; + d->ipar.cmax = 1; + } + if (d->opar.rate > d->ipar.rate) + d->ipar.rate = d->opar.rate; + else + d->opar.rate = d->ipar.rate; + if (d->opar.rate == 0) + d->opar.rate = d->ipar.rate = 44100; /* XXX */ + + if (d->mode & MODE_THRU) + d->mode &= ~MODE_AUDIOMASK; + /* * If needed, open the device (ie create dev_rec and dev_play) */ @@ -316,39 +303,79 @@ dev_open(struct dev *d) return 0; } d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate; + if (d->mode & MODE_REC) { + d->rec = rsio_new(f); + d->rec->refs++; + } + if (d->mode & MODE_PLAY) { + d->play = wsio_new(f); + d->play->refs++; + } + } + if (d->mode & MODE_LOOP) { + if (d->mode & MODE_MON) { #ifdef DEBUG - if (debug_level >= 2) { - if (d->mode & MODE_REC) { - dbg_puts(d->path); - dbg_puts(": recording "); - aparams_dbg(&d->ipar); - dbg_puts("\n"); + if (debug_level >= 1) { + dbg_puts("monitoring not allowed " + "in loopback mode\n"); } - if (d->mode & MODE_PLAY) { - dbg_puts(d->path); - dbg_puts(": playing "); - aparams_dbg(&d->opar); - dbg_puts("\n"); +#endif + return 0; + } + if ((d->mode & MODE_PLAYREC) != MODE_PLAYREC) { +#ifdef DEBUG + if (debug_level >= 1) { + dbg_puts("both play and record streams " + "required in loopback mode\n"); } +#endif + return 0; } + if (d->ctl_list) { +#ifdef DEBUG + if (debug_level >= 1) { + dbg_puts("MIDI control not allowed " + "in loopback mode\n"); + } #endif + return 0; + } + cmin = (d->ipar.cmin < d->opar.cmin) ? + d->ipar.cmin : d->opar.cmin; + cmax = (d->ipar.cmax > d->opar.cmax) ? + d->ipar.cmax : d->opar.cmax; + rate = (d->ipar.rate > d->opar.rate) ? + d->ipar.rate : d->opar.rate; + aparams_init(&par, cmin, cmax, rate); + d->ipar = par; + d->opar = par; + d->rate = rate; + d->round = rate; + d->bufsz = 2 * d->round; + } +#ifdef DEBUG + if (debug_level >= 2) { if (d->mode & MODE_REC) { - d->rec = rsio_new(f); - d->rec->refs++; + dbg_puts(d->path); + dbg_puts(": recording "); + aparams_dbg(&d->ipar); + dbg_puts("\n"); } if (d->mode & MODE_PLAY) { - d->play = wsio_new(f); - d->play->refs++; + dbg_puts(d->path); + dbg_puts(": playing "); + aparams_dbg(&d->opar); + dbg_puts("\n"); } } - +#endif /* * Create the midi control end, or a simple thru box * if there's no device */ if (d->mode & MODE_MIDIMASK) { - d->midi = (d->mode & (MODE_PLAY | MODE_RECMASK)) ? - ctl_new("ctl", d) : thru_new("thru"); + d->midi = (d->mode & MODE_THRU) ? + thru_new("thru") : ctl_new("ctl", d); d->midi->refs++; } @@ -379,7 +406,6 @@ dev_open(struct dev *d) d->mix->flags |= APROC_QUIT; d->sub->flags |= APROC_QUIT; - d->rate = d->opar.rate; } if (d->rec) { aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate); diff --git a/usr.bin/aucat/dev.h b/usr.bin/aucat/dev.h index 24ae338a0fe..e191a74fb57 100644 --- a/usr.bin/aucat/dev.h +++ b/usr.bin/aucat/dev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.h,v 1.29 2011/06/20 20:18:44 ratchov Exp $ */ +/* $OpenBSD: dev.h,v 1.30 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -35,6 +35,7 @@ struct dev { unsigned reqrate; /* sample rate */ unsigned hold; /* hold the device open ? */ unsigned autovol; /* auto adjust playvol ? */ + unsigned autostart; /* don't wait for MMC start */ unsigned refcnt; /* number of openers */ #define DEV_CLOSED 0 /* closed */ #define DEV_INIT 1 /* stopped */ @@ -61,17 +62,15 @@ struct dev { extern struct dev *dev_list; +int dev_init(struct dev *); int dev_run(struct dev *); int dev_ref(struct dev *); void dev_unref(struct dev *); void dev_del(struct dev *); void dev_wakeup(struct dev *); void dev_drain(struct dev *); -struct dev *dev_new_thru(int); -struct dev *dev_new_loop(struct aparams *, struct aparams *, unsigned); -struct dev *dev_new_sio(char *, unsigned, - struct aparams *, struct aparams *, - unsigned, unsigned, unsigned, unsigned); +struct dev *dev_new(char *, unsigned, unsigned, unsigned, unsigned, unsigned); +void dev_adjpar(struct dev *, unsigned, struct aparams *, struct aparams *); int devctl_add(struct dev *, char *, unsigned); void dev_midiattach(struct dev *, struct abuf *, struct abuf *); unsigned dev_roundof(struct dev *, unsigned); diff --git a/usr.bin/aucat/file.c b/usr.bin/aucat/file.c index 48136122884..fb9f7b44dbb 100644 --- a/usr.bin/aucat/file.c +++ b/usr.bin/aucat/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.27 2011/06/27 07:22:00 ratchov Exp $ */ +/* $OpenBSD: file.c,v 1.28 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -369,17 +369,16 @@ file_poll(void) delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec); delta_nsec += ts.tv_nsec - file_ts.tv_nsec; #ifdef DEBUG - if (delta_nsec < 0) { + if (delta_nsec < 0) dbg_puts("file_poll: negative time interval\n"); - dbg_panic(); - } #endif file_ts = ts; - if (delta_nsec < 1000000000LL) + if (delta_nsec >= 0 && delta_nsec < 1000000000LL) timo_update(delta_nsec / 1000); else { #ifdef DEBUG - dbg_puts("ignored huge clock delta\n"); + if (debug_level >= 1) + dbg_puts("ignored huge clock delta\n"); #endif } if (res <= 0) diff --git a/usr.bin/aucat/headers.c b/usr.bin/aucat/headers.c index f53f3ef8b54..777ff24bfd8 100644 --- a/usr.bin/aucat/headers.c +++ b/usr.bin/aucat/headers.c @@ -1,4 +1,4 @@ -/* $OpenBSD: headers.c,v 1.19 2010/11/05 15:23:18 ratchov Exp $ */ +/* $OpenBSD: headers.c,v 1.20 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -240,7 +240,7 @@ wav_writehdr(int fd, struct aparams *par, off_t *startpos, off_t datasz) struct wavchunk fmt_hdr; struct wavfmt fmt; struct wavchunk data_hdr; - } hdr; + } __packed hdr; /* * Check that encoding is supported by .wav file format. @@ -273,8 +273,8 @@ wav_writehdr(int fd, struct aparams *par, off_t *startpos, off_t datasz) hdr.fmt.nch = htole16(nch); hdr.fmt.rate = htole32(par->rate); hdr.fmt.byterate = htole32(par->rate * par->bps * nch); - hdr.fmt.bits = htole16(par->bits); hdr.fmt.blkalign = par->bps * nch; + hdr.fmt.bits = htole16(par->bits); memcpy(hdr.data_hdr.id, wav_id_data, 4); hdr.data_hdr.size = htole32(datasz); diff --git a/usr.bin/aucat/listen.c b/usr.bin/aucat/listen.c index f151d0169a2..2a635939718 100644 --- a/usr.bin/aucat/listen.c +++ b/usr.bin/aucat/listen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: listen.c,v 1.16 2011/05/03 08:00:54 ratchov Exp $ */ +/* $OpenBSD: listen.c,v 1.17 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -36,6 +36,7 @@ #include "conf.h" #include "listen.h" #include "sock.h" +#include "dbg.h" struct fileops listen_ops = { "listen", @@ -50,6 +51,8 @@ struct fileops listen_ops = { listen_revents }; +struct listen *listen_list = NULL; + void listen_new_un(char *path) { @@ -75,10 +78,6 @@ listen_new_un(char *path) goto bad_close; } umask(oldumask); - if (listen(sock, 1) < 0) { - perror("listen"); - goto bad_close; - } f = (struct listen *)file_new(&listen_ops, path, 1); if (f == NULL) goto bad_close; @@ -88,6 +87,8 @@ listen_new_un(char *path) exit(1); } f->fd = sock; + f->next = listen_list; + listen_list = f; return; bad_close: close(sock); @@ -136,10 +137,6 @@ listen_new_tcp(char *addr, unsigned port) perror("bind"); goto bad_close; } - if (listen(s, 1) < 0) { - perror("listen"); - goto bad_close; - } f = (struct listen *)file_new(&listen_ops, addr, 1); if (f == NULL) { bad_close: @@ -148,6 +145,8 @@ listen_new_tcp(char *addr, unsigned port) } f->path = NULL; f->fd = s; + f->next = listen_list; + listen_list = f; n++; } freeaddrinfo(ailist); @@ -156,6 +155,16 @@ listen_new_tcp(char *addr, unsigned port) } int +listen_init(struct listen *f) +{ + if (listen(f->fd, 1) < 0) { + perror("listen"); + return 0; + } + return 1; +} + +int listen_nfds(struct file *f) { return 1; } @@ -211,23 +220,20 @@ listen_revents(struct file *file, struct pollfd *pfd) void listen_close(struct file *file) { - struct listen *f = (struct listen *)file; + struct listen *f = (struct listen *)file, **pf; if (f->path != NULL) { unlink(f->path); free(f->path); } close(f->fd); -} - -void -listen_closeall(void) -{ - struct file *f, *fnext; - - for (f = LIST_FIRST(&file_list); f != NULL; f = fnext) { - fnext = LIST_NEXT(f, entry); - if (f->ops == &listen_ops) - file_close(f); + for (pf = &listen_list; *pf != f; pf = &(*pf)->next) { +#ifdef DEBUG + if (*pf == NULL) { + dbg_puts("listen_close: not on list\n"); + dbg_panic(); + } +#endif } + *pf = f->next; } diff --git a/usr.bin/aucat/listen.h b/usr.bin/aucat/listen.h index 638ad65d1ce..aa36f8df612 100644 --- a/usr.bin/aucat/listen.h +++ b/usr.bin/aucat/listen.h @@ -1,4 +1,4 @@ -/* $OpenBSD: listen.h,v 1.7 2011/04/28 06:19:57 ratchov Exp $ */ +/* $OpenBSD: listen.h,v 1.8 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -24,12 +24,16 @@ struct listen { struct file file; + struct listen *next; char *path; int fd; }; +extern struct listen *listen_list; + void listen_new_un(char *); void listen_new_tcp(char *, unsigned); +int listen_init(struct listen *); int listen_nfds(struct file *); int listen_pollfd(struct file *, struct pollfd *, int); int listen_revents(struct file *, struct pollfd *); diff --git a/usr.bin/aucat/midi.c b/usr.bin/aucat/midi.c index da00d80bfdf..a717a470c42 100644 --- a/usr.bin/aucat/midi.c +++ b/usr.bin/aucat/midi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: midi.c,v 1.36 2011/06/27 07:57:38 ratchov Exp $ */ +/* $OpenBSD: midi.c,v 1.37 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -784,7 +784,7 @@ ctl_trystart(struct aproc *p, int caller) * allocate a new slot and register the given call-backs */ int -ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr) +ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int mmc) { int idx; struct ctl_slot *s; @@ -792,7 +792,7 @@ ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr) if (!APROC_OK(p)) { #ifdef DEBUG - if (debug_level >= 1) { + if (debug_level >= 2) { dbg_puts(who); dbg_puts(": MIDI control not available\n"); } @@ -806,7 +806,7 @@ ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr) s = p->u.ctl.slot + idx; s->ops = ops; s->arg = arg; - s->tstate = tr ? CTL_STOP : CTL_OFF; + s->tstate = mmc ? CTL_STOP : CTL_OFF; s->ops->vol(s->arg, s->vol); ctl_msg_info(p, idx, msg); ctl_sendmsg(p, NULL, msg, SYSEX_SIZE(mixinfo)); diff --git a/usr.bin/aucat/midicat.1 b/usr.bin/aucat/midicat.1 index 761cfd7ab1c..ac8ca9d5495 100644 --- a/usr.bin/aucat/midicat.1 +++ b/usr.bin/aucat/midicat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: midicat.1,v 1.17 2011/06/20 20:18:44 ratchov Exp $ +.\" $OpenBSD: midicat.1,v 1.18 2011/10/12 07:20:04 ratchov Exp $ .\" .\" Copyright (c) 2006 Alexandre Ratchov <alex@caoua.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 20 2011 $ +.Dd $Mdocdate: October 12 2011 $ .Dt MIDICAT 1 .Os .Sh NAME @@ -22,7 +22,7 @@ .Nd MIDI server and manipulation tool .Sh SYNOPSIS .Nm midicat -.Op Fl dl +.Op Fl dlM .Op Fl a Ar flag .Op Fl i Ar file .Op Fl L Ar addr @@ -90,23 +90,25 @@ If the option argument is then .Nm will accept connections from any address. +.It Fl M +Create a MIDI thru box. +It merges any number of MIDI inputs and broadcasts the result +to any number of MIDI outputs, similarly to a hardware MIDI thru box. +Following MIDI ports +.Pq Fl q +and MIDI files +.Pq Fl io +will be subscribed to this thru box. +If sub-devices are exposed +.Pq Fl s +they behave like software MIDI ports, +allowing any MIDI-capable application to send MIDI messages to +MIDI hardware or to another application in a uniform way. .It Fl l Detach and become a daemon. -.It Fl o Ar file -Write received data into this file. -If the option argument is -.Sq - -then standard output will be used. -.It Fl q Ar port -Send and receive data from this -.Xr sndio 7 -MIDI port. .It Fl s Ar name Expose a MIDI thru box to which MIDI programs can connect. -Preceding streams -.Pq Fl ioq -are subscribed to this thru box. The given .Ar name corresponds to the @@ -114,6 +116,15 @@ corresponds to the part of the .Xr sndio 7 device name string. +.It Fl o Ar file +Write received data into this file. +If the option argument is +.Sq - +then standard output will be used. +.It Fl q Ar port +Send and receive data from this +.Xr sndio 7 +MIDI port. .It Fl U Ar unit Unit number to use when running in server mode. Each @@ -123,6 +134,9 @@ used in .Xr sndio 7 device names. The default is 0. +The unit number must be set before any server-specific +options are used +.Pq Fl Ls . .El .Pp If files @@ -189,7 +203,7 @@ The following creates a MIDI thru box and subscribes the port, allowing multiple MIDI programs to use the port simultaneously: .Bd -literal -offset indent -$ midicat -q rmidi:5 -s default +$ midicat -q rmidi:5 .Ed .Sh SEE ALSO .Xr aucat 1 , diff --git a/usr.bin/aucat/opt.c b/usr.bin/aucat/opt.c index 4e14b81e391..d3a3e993a95 100644 --- a/usr.bin/aucat/opt.c +++ b/usr.bin/aucat/opt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: opt.c,v 1.10 2010/07/06 01:12:45 ratchov Exp $ */ +/* $OpenBSD: opt.c,v 1.11 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -25,13 +25,13 @@ #include "dbg.h" #endif -struct optlist opt_list = SLIST_HEAD_INITIALIZER(&opt_list); +struct opt *opt_list = NULL; -void -opt_new(char *name, struct dev *d, struct aparams *wpar, struct aparams *rpar, +struct opt * +opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, int maxweight, int mmc, int join, unsigned mode) { - struct opt *o; + struct opt *o, **po; unsigned len; char c; @@ -49,12 +49,6 @@ opt_new(char *name, struct dev *d, struct aparams *wpar, struct aparams *rpar, exit(1); } } - SLIST_FOREACH(o, &opt_list, entry) { - if (strcmp(name, o->name) == 0) { - fprintf(stderr, "%s: already defined\n", name); - exit(1); - } - } o = malloc(sizeof(struct opt)); if (o == NULL) { perror("opt_new: malloc"); @@ -69,20 +63,28 @@ opt_new(char *name, struct dev *d, struct aparams *wpar, struct aparams *rpar, o->mmc = mmc; o->join = join; o->mode = mode; - o->dev = d; + o->dev = dev; + for (po = &opt_list; *po != NULL; po = &(*po)->next) { + if (strcmp(o->name, (*po)->name) == 0) { + fprintf(stderr, "%s: already defined\n", o->name); + exit(1); + } + } + o->next = NULL; + *po = o; #ifdef DEBUG if (debug_level >= 2) { dbg_puts(o->name); dbg_puts("@"); dbg_puts(o->dev->path); dbg_puts(":"); - if (mode & MODE_REC) { + if (o->mode & MODE_REC) { dbg_puts(" rec="); dbg_putu(o->wpar.cmin); dbg_puts(":"); dbg_putu(o->wpar.cmax); } - if (mode & MODE_PLAY) { + if (o->mode & MODE_PLAY) { dbg_puts(" play="); dbg_putu(o->rpar.cmin); dbg_puts(":"); @@ -90,18 +92,26 @@ opt_new(char *name, struct dev *d, struct aparams *wpar, struct aparams *rpar, dbg_puts(" vol="); dbg_putu(o->maxweight); } - if (mode & MODE_MON) { + if (o->mode & MODE_MON) { dbg_puts(" mon="); dbg_putu(o->wpar.cmin); dbg_puts(":"); dbg_putu(o->wpar.cmax); } - if (o->mmc) - dbg_puts(" mmc"); + if (o->mode & (MODE_RECMASK | MODE_PLAY)) { + if (o->mmc) + dbg_puts(" mmc"); + if (o->join) + dbg_puts(" join"); + } + if (o->mode & MODE_MIDIIN) + dbg_puts(" midi/in"); + if (o->mode & MODE_MIDIOUT) + dbg_puts(" midi/out"); dbg_puts("\n"); } #endif - SLIST_INSERT_HEAD(&opt_list, o, entry); + return o; } struct opt * @@ -109,7 +119,7 @@ opt_byname(char *name) { struct opt *o; - SLIST_FOREACH(o, &opt_list, entry) { + for (o = opt_list; o != NULL; o = o->next) { if (strcmp(name, o->name) == 0) { #ifdef DEBUG if (debug_level >= 3) { diff --git a/usr.bin/aucat/opt.h b/usr.bin/aucat/opt.h index 8ef3fe1e40d..c904fbbb9fa 100644 --- a/usr.bin/aucat/opt.h +++ b/usr.bin/aucat/opt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: opt.h,v 1.9 2010/10/21 18:57:42 ratchov Exp $ */ +/* $OpenBSD: opt.h,v 1.10 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -23,7 +23,7 @@ struct dev; struct opt { - SLIST_ENTRY(opt) entry; + struct opt *next; #define OPT_NAMEMAX 11 char name[OPT_NAMEMAX + 1]; int maxweight; /* max dynamic range for clients */ @@ -35,10 +35,11 @@ struct opt { struct dev *dev; /* device to which we're attached */ }; -SLIST_HEAD(optlist,opt); +extern struct opt *opt_list; -void opt_new(char *, struct dev *, struct aparams *, struct aparams *, +struct opt *opt_new(char *, struct dev *, struct aparams *, struct aparams *, int, int, int, unsigned); +int opt_bind(struct opt *); struct opt *opt_byname(char *); #endif /* !defined(OPT_H) */ diff --git a/usr.bin/aucat/siofile.c b/usr.bin/aucat/siofile.c index f01a9490293..60ad391b5d6 100644 --- a/usr.bin/aucat/siofile.c +++ b/usr.bin/aucat/siofile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: siofile.c,v 1.7 2011/06/27 07:22:00 ratchov Exp $ */ +/* $OpenBSD: siofile.c,v 1.8 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -245,7 +245,7 @@ siofile_new(struct fileops *ops, char *path, unsigned *rmode, par.le = ipar->le; par.msb = ipar->msb; par.rate = ipar->rate; - par.rchan = ipar->cmax - ipar->cmin + 1; + par.rchan = ipar->cmax + 1; } else { par.bits = opar->bits; par.bps = opar->bps; @@ -255,9 +255,11 @@ siofile_new(struct fileops *ops, char *path, unsigned *rmode, par.rate = opar->rate; } if (mode & SIO_PLAY) - par.pchan = opar->cmax - opar->cmin + 1; - par.appbufsz = *bufsz; - par.round = *round; + par.pchan = opar->cmax + 1; + if (*bufsz) + par.appbufsz = *bufsz; + if (*round) + par.round = *round; if (!sio_setpar(hdl, &par)) goto bad_close; if (!sio_getpar(hdl, &par)) @@ -269,7 +271,8 @@ siofile_new(struct fileops *ops, char *path, unsigned *rmode, ipar->le = par.le; ipar->msb = par.msb; ipar->rate = par.rate; - ipar->cmax = ipar->cmin + par.rchan - 1; + ipar->cmin = 0; + ipar->cmax = par.rchan - 1; } if (mode & SIO_PLAY) { opar->bits = par.bits; @@ -278,7 +281,8 @@ siofile_new(struct fileops *ops, char *path, unsigned *rmode, opar->le = par.le; opar->msb = par.msb; opar->rate = par.rate; - opar->cmax = opar->cmin + par.pchan - 1; + opar->cmin = 0; + opar->cmax = par.pchan - 1; } *rmode = mode; *bufsz = par.bufsz; diff --git a/usr.bin/aucat/wav.c b/usr.bin/aucat/wav.c index 9be0ec4c18c..20c1dc78bf6 100644 --- a/usr.bin/aucat/wav.c +++ b/usr.bin/aucat/wav.c @@ -121,6 +121,8 @@ struct fileops wav_ops = { pipe_revents }; +struct wav *wav_list = NULL; + int rwav_in(struct aproc *, struct abuf *); int rwav_out(struct aproc *, struct abuf *); void rwav_eof(struct aproc *, struct abuf *); @@ -182,7 +184,7 @@ struct aproc_ops wwav_ops = { void wav_dbg(struct wav *f) { - static char *pstates[] = { "ini", "sta", "rdy", "run", "fai" }; + static char *pstates[] = { "cfg", "ini", "sta", "rdy", "run", "mid" }; struct aproc *midi = f->dev ? f->dev->midi : NULL; dbg_puts("wav("); @@ -287,7 +289,7 @@ wav_write(struct file *file, unsigned char *data, unsigned count) void wav_close(struct file *file) { - struct wav *f = (struct wav *)file; + struct wav *f = (struct wav *)file, **pf; if (f->mode & MODE_RECMASK) { pipe_trunc(&f->pipe.file, f->endpos); @@ -299,10 +301,17 @@ wav_close(struct file *file) } } pipe_close(file); - if (f->dev) { + if (f->pstate != WAV_CFG) dev_unref(f->dev); - f->dev = NULL; + for (pf = &wav_list; *pf != f; pf = &(*pf)->next) { +#ifdef DEBUG + if (*pf == NULL) { + dbg_puts("wav_close: not on list\n"); + dbg_panic(); + } +#endif } + *pf = f->next; } /* @@ -343,6 +352,26 @@ wav_attach(struct wav *f, int force) } /* + * allocate buffers, so client can start filling write-end. + */ +void +wav_midiattach(struct wav *f) +{ + struct abuf *rbuf = NULL, *wbuf = NULL; + + if (f->mode & MODE_MIDIOUT) { + rbuf = abuf_new(MIDI_BUFSZ, &aparams_none); + aproc_setout(f->pipe.file.rproc, rbuf); + } + if (f->mode & MODE_MIDIIN) { + wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); + aproc_setin(f->pipe.file.wproc, wbuf); + } + f->pstate = WAV_MIDI; + dev_midiattach(f->dev, rbuf, wbuf); +} + +/* * allocate the play (rec) abuf structure; if this is a * file to record, then attach it to the device * @@ -424,12 +453,13 @@ wav_reset(struct wav *f) /* PASSTHROUGH */ case WAV_RUN: wav_freebuf(f); - f->pstate = WAV_INIT; /* PASSTHROUGH */ case WAV_INIT: - case WAV_FAILED: /* nothing yet */ break; + case WAV_MIDI: + dbg_puts("wav_reset: in midi mode\n"); + dbg_panic(); } } @@ -440,14 +470,47 @@ void wav_exit(struct wav *f) { /* XXX: call file_close() ? */ - if (f->mode & MODE_PLAY) { + if (f->mode & (MODE_PLAY | MODE_MIDIOUT)) { aproc_del(f->pipe.file.rproc); - } else if (f->mode & MODE_RECMASK) { + } else if (f->mode & (MODE_RECMASK | MODE_MIDIIN)) { aproc_del(f->pipe.file.wproc); } } /* + * allocate the device + */ +int +wav_init(struct wav *f) +{ + if (!dev_ref(f->dev)) { + wav_exit(f); + return 0; + } + if (!f->mmc) + f->dev->autostart = 1; + if (f->mode & MODE_MIDIMASK) { + wav_midiattach(f); + return 1; + } + f->slot = ctl_slotnew(f->dev->midi, "wav", &ctl_wavops, f, 1); + f->pstate = WAV_INIT; + if ((f->mode & f->dev->mode) != f->mode) { +#ifdef DEBUG + if (debug_level >= 1) { + wav_dbg(f); + dbg_puts(": "); + dbg_puts(": operation not supported by device\n"); + } +#endif + wav_exit(f); + return 0; + } + wav_allocbuf(f); + return 1; +} + +/* * seek to f->mmcpos and prepare to start, close * the file on error. */ @@ -458,9 +521,8 @@ wav_seekmmc(struct wav *f) * don't go beyond the end-of-file, if so * put it in INIT state so it dosn't start */ - if (f->mmcpos > f->endpos) { + if (f->mmcpos > f->endpos && !(f->mode & MODE_RECMASK)) { wav_reset(f); - f->pstate = WAV_FAILED; /* * don't make other stream wait for us */ @@ -472,6 +534,8 @@ wav_seekmmc(struct wav *f) wav_exit(f); return 0; } + if (f->mode & MODE_RECMASK) + f->endpos = f->mmcpos; if (f->hdr == HDR_WAV) f->wbytes = WAV_DATAMAX - f->mmcpos; f->rbytes = f->endpos - f->mmcpos; @@ -506,9 +570,11 @@ wav_rdata(struct wav *f) if (ctl_slotstart(f->dev->midi, f->slot)) (void)wav_attach(f, 0); break; -#ifdef DEBUG case WAV_RUN: break; + case WAV_MIDI: + return 1; +#ifdef DEBUG default: wav_dbg(f); dbg_puts(": bad state\n"); @@ -572,7 +638,7 @@ wav_startreq(void *arg) struct wav *f = (struct wav *)arg; switch (f->pstate) { - case WAV_FAILED: + case WAV_INIT: #ifdef DEBUG if (debug_level >= 2) { wav_dbg(f); @@ -582,7 +648,7 @@ wav_startreq(void *arg) return; case WAV_READY: if (f->mode & MODE_RECMASK) - f->endpos = f->startpos; + f->endpos = f->mmcpos + f->startpos; (void)wav_attach(f, 0); break; #ifdef DEBUG @@ -607,7 +673,7 @@ wav_stopreq(void *arg) if (debug_level >= 2) { wav_dbg(f); dbg_puts(": stopping"); - if (f->pstate != WAV_FAILED && (f->mode & MODE_RECMASK)) { + if (f->pstate != WAV_INIT && (f->mode & MODE_RECMASK)) { dbg_puts(", "); dbg_putu(f->endpos); dbg_puts(" bytes recorded"); @@ -664,67 +730,74 @@ wav_quitreq(void *arg) /* * determine the header by the file name */ -unsigned -wav_autohdr(char *name, unsigned hdr) +int +wav_autohdr(char *name, struct dev *dev, unsigned *hdr, unsigned *mode) { - size_t len; - - if (hdr != HDR_AUTO) - return hdr; - if (name == NULL) - return HDR_RAW; - len = strlen(name); - if (len >= 4 && strcasecmp(name + len - 4, ".wav") == 0) - return HDR_WAV; - else - return HDR_RAW; + char *ext; + + if (dev->reqmode & MODE_THRU) + *mode &= MODE_MIDIMASK; + if (*hdr == HDR_AUTO) { + ext = strrchr(name, '.'); + if (ext != NULL) { + ext++; + if (strcasecmp(ext, "wav") == 0) { + *hdr = HDR_WAV; + *mode &= ~MODE_MIDIMASK; + } else if (strcasecmp(ext, "syx") == 0) { + *hdr = HDR_WAV; + *mode &= ~MODE_AUDIOMASK; + } + } else + *hdr = HDR_RAW; + } + if (*mode & MODE_AUDIOMASK) + *mode &= ~MODE_MIDIMASK; + if (*mode == 0) { +#ifdef DEBUG + if (debug_level >= 1) { + dbg_puts(name); + dbg_puts(": requested mode not supported\n"); + } +#endif + return 0; + } + return 1; } /* * create a file reader in the ``INIT'' state */ struct wav * -wav_new_in(struct fileops *ops, - struct dev *dev, unsigned mode, char *name, unsigned hdr, - struct aparams *par, unsigned xrun, unsigned volctl, int tr, int join) +wav_new_in(struct fileops *ops, struct dev *dev, + unsigned mode, char *name, unsigned hdr, + struct aparams *par, unsigned xrun, unsigned volctl, int mmc, int join) { int fd; struct wav *f; - hdr = wav_autohdr(name, hdr); - if (name != NULL) { + if (!wav_autohdr(name, dev, &hdr, &mode)) + return NULL; + if (strcmp(name, "-") == 0) { + fd = STDIN_FILENO; + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + perror(name); + } else { fd = open(name, O_RDONLY | O_NONBLOCK, 0666); if (fd < 0) { perror(name); return NULL; } - } else { - name = "stdin"; - fd = STDIN_FILENO; - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - perror(name); } f = (struct wav *)pipe_new(ops, fd, name); if (f == NULL) { close(fd); return NULL; } - if (!dev_ref(dev)) { - close(fd); - return NULL; - } - if (!(dev->mode & MODE_PLAY)) { -#ifdef DEBUG - dbg_puts(name); - dbg_puts(": device can't play\n"); -#endif - close(fd); - dev_unref(dev); - return NULL; - } - f->dev = dev; + f->pstate = WAV_CFG; if (hdr == HDR_WAV) { - if (!wav_readhdr(f->pipe.fd, par, &f->startpos, &f->rbytes, &f->map)) { + if (!wav_readhdr(f->pipe.fd, par, + &f->startpos, &f->rbytes, &f->map)) { file_del((struct file *)f); return NULL; } @@ -742,31 +815,37 @@ wav_new_in(struct fileops *ops, f->rbytes = -1; f->map = NULL; } - f->pstate = WAV_INIT; - f->mmc = tr; + f->dev = dev; + f->mmc = mmc; f->join = join; f->mode = mode; f->hpar = *par; f->hdr = hdr; f->xrun = xrun; f->maxweight = MIDI_TO_ADATA(volctl); - f->slot = ctl_slotnew(f->dev->midi, "play", &ctl_wavops, f, 1); + f->slot = -1; rwav_new((struct file *)f); - wav_allocbuf(f); #ifdef DEBUG if (debug_level >= 2) { dbg_puts(name); - dbg_puts(": playing "); - dbg_putu(f->startpos); - dbg_puts(".."); - dbg_putu(f->endpos); - dbg_puts(": playing "); - aparams_dbg(par); - if (f->mmc) - dbg_puts(", mmc"); + dbg_puts(":"); + if (f->mode & MODE_PLAY) { + dbg_puts(" playing "); + aparams_dbg(par); + dbg_puts(" "); + dbg_putu(f->startpos); + dbg_puts(".."); + dbg_putu(f->endpos); + if (f->mmc) + dbg_puts(", mmc"); + } + if (f->mode & MODE_MIDIOUT) + dbg_puts(" midi/out"); dbg_puts("\n"); } #endif + f->next = wav_list; + wav_list = f; return f; } @@ -774,16 +853,16 @@ wav_new_in(struct fileops *ops, * create a file writer in the ``INIT'' state */ struct wav * -wav_new_out(struct fileops *ops, - struct dev *dev, unsigned mode, char *name, unsigned hdr, - struct aparams *par, unsigned xrun, int tr, int join) +wav_new_out(struct fileops *ops, struct dev *dev, + unsigned mode, char *name, unsigned hdr, + struct aparams *par, unsigned xrun, int mmc, int join) { int fd; struct wav *f; - hdr = wav_autohdr(name, hdr); - if (name == NULL) { - name = "stdout"; + if (!wav_autohdr(name, dev, &hdr, &mode)) + return NULL; + if (strcmp(name, "-") == 0) { fd = STDOUT_FILENO; if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) perror(name); @@ -800,20 +879,7 @@ wav_new_out(struct fileops *ops, close(fd); return NULL; } - if (!dev_ref(dev)) { - close(fd); - return NULL; - } - if (!(dev->mode & MODE_RECMASK)) { -#ifdef DEBUG - dbg_puts(name); - dbg_puts(": device can't record\n"); -#endif - close(fd); - dev_unref(dev); - return NULL; - } - f->dev = dev; + f->pstate = WAV_CFG; if (hdr == HDR_WAV) { par->le = 1; par->sig = (par->bits <= 8) ? 0 : 1; @@ -828,24 +894,31 @@ wav_new_out(struct fileops *ops, f->wbytes = -1; f->startpos = f->endpos = 0; } - f->pstate = WAV_INIT; - f->mmc = tr; + f->dev = dev; + f->mmc = mmc; f->join = join; f->mode = mode; f->hpar = *par; f->hdr = hdr; f->xrun = xrun; - f->slot = ctl_slotnew(f->dev->midi, "rec", &ctl_wavops, f, 1); wwav_new((struct file *)f); - wav_allocbuf(f); #ifdef DEBUG if (debug_level >= 2) { dbg_puts(name); - dbg_puts(": recording "); - aparams_dbg(par); + dbg_puts(":"); + if (f->mode & MODE_RECMASK) { + dbg_puts(" recording "); + aparams_dbg(par); + if (f->mmc) + dbg_puts(", mmc"); + } + if (f->mode & MODE_MIDIIN) + dbg_puts(" midi/in"); dbg_puts("\n"); } #endif + f->next = wav_list; + wav_list = f; return f; } @@ -953,4 +1026,3 @@ wwav_new(struct file *f) f->wproc = p; return p; } - diff --git a/usr.bin/aucat/wav.h b/usr.bin/aucat/wav.h index 1734f2e8d45..6d721e1ac65 100644 --- a/usr.bin/aucat/wav.h +++ b/usr.bin/aucat/wav.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wav.h,v 1.11 2010/07/31 08:48:01 ratchov Exp $ */ +/* $OpenBSD: wav.h,v 1.12 2011/10/12 07:20:04 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -24,6 +24,7 @@ struct wav { struct pipe pipe; + struct wav *next; #define HDR_AUTO 0 /* guess by looking at the file name */ #define HDR_RAW 1 /* no headers, ie openbsd native ;-) */ #define HDR_WAV 2 /* microsoft riff wave */ @@ -41,17 +42,19 @@ struct wav { int join; /* join/expand channels */ unsigned vol; /* current volume */ unsigned maxweight; /* dynamic range when vol == 127 */ -#define WAV_INIT 0 /* not trying to do anything */ -#define WAV_START 1 /* buffer allocated */ -#define WAV_READY 2 /* buffer filled enough */ -#define WAV_RUN 3 /* buffer attached to device */ -#define WAV_FAILED 4 /* failed to seek */ +#define WAV_CFG 0 /* parameters read from headers */ +#define WAV_INIT 1 /* not trying to do anything */ +#define WAV_START 2 /* buffer allocated */ +#define WAV_READY 3 /* buffer filled enough */ +#define WAV_RUN 4 /* buffer attached to device */ +#define WAV_MIDI 5 /* midi "syx" file */ unsigned pstate; /* one of above */ unsigned mode; /* bitmap of MODE_* */ struct dev *dev; /* device playing or recording */ }; extern struct fileops wav_ops; +struct wav *wav_list; struct wav *wav_new_in(struct fileops *, struct dev *, unsigned, char *, unsigned, struct aparams *, unsigned, unsigned, int, int); @@ -63,6 +66,7 @@ void wav_close(struct file *); int wav_readhdr(int, struct aparams *, off_t *, off_t *, short **); int wav_writehdr(int, struct aparams *, off_t *, off_t); void wav_conv(unsigned char *, unsigned, short *); +int wav_init(struct wav *); extern short wav_ulawmap[256]; extern short wav_alawmap[256]; |