add -g and -p option to control device and file start position

This commit is contained in:
Alexandre Ratchov 2016-06-02 18:14:10 +02:00
parent a6fdc3b5ed
commit 2562fa7eb4
2 changed files with 73 additions and 8 deletions

View File

@ -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

View File

@ -16,6 +16,7 @@
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <sndio.h>
@ -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;