diff --git a/aucat/aucat.1 b/aucat/aucat.1 index 446311d..ed0b162 100644 --- a/aucat/aucat.1 +++ b/aucat/aucat.1 @@ -27,10 +27,12 @@ .Op Fl c Ar min : Ns Ar max .Op Fl e Ar enc .Op Fl f Ar device +.Op Fl g Ar position .Op Fl h Ar fmt .Op Fl i Ar file .Op Fl j Ar flag .Op Fl o Ar file +.Op Fl p Ar position .Op Fl q Ar port .Op Fl r Ar rate .Op Fl v Ar volume @@ -117,6 +119,11 @@ audio device. Device mode and parameters are determined from audio files. Default is .Pa default . +.It Fl g Ar position +Go to the given time position and start playback or recording there. +This option is equivalent to an incoming MMC relocate message +with the same position. +The position is expressed as the number of samples (at device sample rate). .It Fl h Ar fmt Audio file type. The following file types are supported: @@ -169,6 +176,11 @@ Record into this audio file. If the option argument is .Sq - then standard output will be used. +.It Fl p Ar position +Time offset where the beginning of the file belongs. +The first sample of the file will be played or recorded when the device +reaches the given postion. +The position is expressed as the number of samples (at device sample rate). .It Fl q Ar port Control audio device properties through this MIDI port. This includes per-stream volumes and the ability to diff --git a/aucat/aucat.c b/aucat/aucat.c index 2b7b48d..caaf9a2 100644 --- a/aucat/aucat.c +++ b/aucat/aucat.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -91,6 +92,8 @@ struct slot { #define SLOT_RUN 2 /* playing/recording */ #define SLOT_STOP 3 /* draining (play only) */ int pstate; /* one of above */ + long long skip; /* frames to skip at the beginning */ + long long pos; /* start position (at device rate) */ struct afile afile; /* file desc & friends */ }; @@ -135,8 +138,9 @@ unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; char usagestr[] = "usage: aucat [-dn] [-b size] " - "[-c min:max] [-e enc] [-f device] [-h fmt]\n\t" - "[-i file] [-j flag] [-o file] [-q port] [-r rate] [-v volume]\n"; + "[-c min:max] [-e enc] [-f device] [-g position]\n\t" + "[-h fmt] [-i file] [-j flag] [-o file] [-p position] [-q port]\n\t" + "[-r rate] [-v volume]\n"; static void slot_log(struct slot *s) @@ -203,7 +207,7 @@ slot_fill(struct slot *s) static int slot_new(char *path, int mode, struct aparams *par, int hdr, - int cmin, int cmax, int rate, int dup, int vol) + int cmin, int cmax, int rate, int dup, int vol, long long pos) { struct slot *s; @@ -220,6 +224,7 @@ slot_new(char *path, int mode, struct aparams *par, int hdr, s->vol = MIDI_TO_ADATA(vol); s->mode = mode; s->pstate = SLOT_CFG; + s->pos = pos; if (log_level >= 2) { slot_log(s); log_puts(": "); @@ -360,6 +365,13 @@ slot_start(struct slot *s, long long pos) panic(); } #endif + pos -= s->pos; + if (pos < 0) { + s->skip = -pos; + pos = 0; + } else + s->skip = 0; + /* * convert pos to slot sample rate * @@ -506,6 +518,15 @@ slot_mix_badd(struct slot *s, adata_t *odata) odone = 0; otodo = dev_round; + if (s->skip > 0) { + ocnt = otodo; + if (ocnt > s->skip) + ocnt = s->skip; + s->skip -= ocnt; + odata += dev_pchan * ocnt; + otodo -= ocnt; + odone += ocnt; + } while (otodo > 0) { idata = (adata_t *)abuf_rgetblk(&s->buf, &len); @@ -575,6 +596,15 @@ slot_sub_bcopy(struct slot *s, adata_t *idata, int itodo) adata_t *odata; int len, icnt, ocnt; + if (s->skip > 0) { + icnt = itodo; + if (icnt > s->skip) + icnt = s->skip; + s->skip -= icnt; + idata += dev_rchan * icnt; + itodo -= icnt; + } + while (itodo > 0) { odata = (adata_t *)abuf_wgetblk(&s->buf, &len); @@ -667,7 +697,6 @@ dev_open(char *dev, int mode, int bufsz, char *port) dev_rchan = par.rchan; dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round); } - dev_pos = 0; dev_pstate = DEV_STOP; if (log_level >= 2) { log_puts(dev_name); @@ -1027,7 +1056,6 @@ offline(void) dev_pchan = dev_rchan = cmax + 1; dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round); dev_pstate = DEV_STOP; - dev_pos = 0; for (s = slot_list; s != NULL; s = s->next) slot_init(s); for (s = slot_list; s != NULL; s = s->next) @@ -1296,6 +1324,20 @@ opt_num(char *s, int min, int max, int *num) return 1; } +static int +opt_pos(char *s, long long *pos) +{ + const char *errstr; + + *pos = strtonum(s, 0, LLONG_MAX, &errstr); + if (errstr) { + log_puts(s); + log_puts(": positive number of samples expected\n"); + return 0; + } + return 1; +} + int main(int argc, char **argv) { @@ -1303,6 +1345,7 @@ main(int argc, char **argv) char *port, *dev; struct aparams par; int n_flag, c; + long long pos; vol = 127; dup = 0; @@ -1316,8 +1359,10 @@ main(int argc, char **argv) port = NULL; dev = NULL; mode = 0; + pos = 0; - while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) { + while ((c = getopt(argc, argv, + "b:c:de:f:g:h:i:j:no:p:q:r:t:v:")) != -1) { switch (c) { case 'b': if (!opt_num(optarg, 1, RATE_MAX, &bufsz)) @@ -1337,13 +1382,17 @@ main(int argc, char **argv) case 'f': dev = optarg; break; + case 'g': + if (!opt_pos(optarg, &dev_pos)) + return 1; + break; case 'h': if (!opt_hdr(optarg, &hdr)) return 1; break; case 'i': if (!slot_new(optarg, SIO_PLAY, - &par, hdr, cmin, cmax, rate, dup, vol)) + &par, hdr, cmin, cmax, rate, dup, vol, pos)) return 1; mode |= SIO_PLAY; break; @@ -1356,10 +1405,14 @@ main(int argc, char **argv) break; case 'o': if (!slot_new(optarg, SIO_REC, - &par, hdr, cmin, cmax, rate, dup, 0)) + &par, hdr, cmin, cmax, rate, dup, 0, pos)) return 1; mode |= SIO_REC; break; + case 'p': + if (!opt_pos(optarg, &pos)) + return 1; + break; case 'q': port = optarg; break;