mirror of
https://github.com/ericonr/sndio.git
synced 2024-02-18 04:45:21 -06:00
merge introduction of resamp_getcnt
This commit is contained in:
parent
8ceee9aeff
commit
74cb9d0038
@ -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
|
||||
|
162
aucat/aucat.c
162
aucat/aucat.c
@ -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 */
|
||||
};
|
||||
|
||||
@ -103,7 +106,7 @@ unsigned int dev_round; /* device block size */
|
||||
int dev_rate; /* device sample rate (Hz) */
|
||||
unsigned int dev_pchan, dev_rchan; /* play & rec channels count */
|
||||
adata_t *dev_pbuf, *dev_rbuf; /* play & rec buffers */
|
||||
unsigned int dev_mmcpos; /* last MMC position */
|
||||
long long dev_pos; /* last MMC position in frames */
|
||||
#define DEV_STOP 0 /* stopped */
|
||||
#define DEV_START 1 /* started */
|
||||
unsigned int dev_pstate; /* one of above */
|
||||
@ -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(": ");
|
||||
@ -351,10 +356,8 @@ slot_init(struct slot *s)
|
||||
}
|
||||
|
||||
static void
|
||||
slot_start(struct slot *s, unsigned int mmc)
|
||||
slot_start(struct slot *s, long long pos)
|
||||
{
|
||||
off_t mmcpos;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (s->pstate != SLOT_INIT) {
|
||||
slot_log(s);
|
||||
@ -362,8 +365,22 @@ slot_start(struct slot *s, unsigned int mmc)
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
mmcpos = ((off_t)mmc * s->afile.rate / MTC_SEC) * s->bpf;
|
||||
if (!afile_seek(&s->afile, mmcpos)) {
|
||||
pos -= s->pos;
|
||||
if (pos < 0) {
|
||||
s->skip = -pos;
|
||||
pos = 0;
|
||||
} else
|
||||
s->skip = 0;
|
||||
|
||||
/*
|
||||
* convert pos to slot sample rate
|
||||
*
|
||||
* At this stage, we could adjust s->resamp.diff to get
|
||||
* sub-frame accuracy.
|
||||
*/
|
||||
pos = pos * s->afile.rate / dev_rate;
|
||||
|
||||
if (!afile_seek(&s->afile, pos * s->bpf)) {
|
||||
s->pstate = SLOT_INIT;
|
||||
return;
|
||||
}
|
||||
@ -422,16 +439,18 @@ slot_del(struct slot *s)
|
||||
xfree(s);
|
||||
}
|
||||
|
||||
static int
|
||||
slot_ocnt(struct slot *s, int icnt)
|
||||
static void
|
||||
slot_getcnt(struct slot *s, int *icnt, int *ocnt)
|
||||
{
|
||||
return s->resampbuf ? resamp_ocnt(&s->resamp, icnt) : icnt;
|
||||
}
|
||||
int cnt;
|
||||
|
||||
static int
|
||||
slot_icnt(struct slot *s, int ocnt)
|
||||
{
|
||||
return s->resampbuf ? resamp_icnt(&s->resamp, ocnt) : ocnt;
|
||||
if (s->resampbuf)
|
||||
resamp_getcnt(&s->resamp, icnt, ocnt);
|
||||
else {
|
||||
cnt = (*icnt < *ocnt) ? *icnt : *ocnt;
|
||||
*icnt = cnt;
|
||||
*ocnt = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -501,15 +520,20 @@ 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);
|
||||
|
||||
icnt = len / s->bpf;
|
||||
ocnt = slot_ocnt(s, icnt);
|
||||
if (ocnt > otodo) {
|
||||
ocnt = otodo;
|
||||
icnt = slot_icnt(s, ocnt);
|
||||
}
|
||||
ocnt = otodo;
|
||||
slot_getcnt(s, &icnt, &ocnt);
|
||||
if (icnt == 0)
|
||||
break;
|
||||
play_filt_dec(s, idata, odata, icnt, ocnt);
|
||||
@ -570,15 +594,20 @@ 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);
|
||||
|
||||
ocnt = len / s->bpf;
|
||||
icnt = slot_icnt(s, ocnt);
|
||||
if (icnt > itodo) {
|
||||
icnt = itodo;
|
||||
ocnt = slot_ocnt(s, icnt);
|
||||
}
|
||||
icnt = itodo;
|
||||
slot_getcnt(s, &icnt, &ocnt);
|
||||
if (ocnt == 0)
|
||||
break;
|
||||
rec_filt_enc(s, idata, odata, icnt, ocnt);
|
||||
@ -662,7 +691,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_mmcpos = 0;
|
||||
dev_pstate = DEV_STOP;
|
||||
if (log_level >= 2) {
|
||||
log_puts(dev_name);
|
||||
@ -753,7 +781,7 @@ dev_mmcstart(void)
|
||||
if (dev_pstate == DEV_STOP) {
|
||||
dev_pstate = DEV_START;
|
||||
for (s = slot_list; s != NULL; s = s->next)
|
||||
slot_start(s, dev_mmcpos);
|
||||
slot_start(s, dev_pos);
|
||||
dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0;
|
||||
sio_start(dev_sh);
|
||||
if (log_level >= 2)
|
||||
@ -793,21 +821,32 @@ dev_mmcstop(void)
|
||||
* relocate all slots simultaneously
|
||||
*/
|
||||
static void
|
||||
dev_mmcloc(unsigned int mmc)
|
||||
dev_mmcloc(int hr, int min, int sec, int fr, int cent, int fps)
|
||||
{
|
||||
if (dev_mmcpos == mmc)
|
||||
long long pos;
|
||||
|
||||
pos = dev_rate * hr * 3600 +
|
||||
dev_rate * min * 60 +
|
||||
dev_rate * sec +
|
||||
dev_rate * fr / fps +
|
||||
dev_rate * cent / (100 * fps);
|
||||
if (dev_pos == pos)
|
||||
return;
|
||||
dev_mmcpos = mmc;
|
||||
dev_pos = pos;
|
||||
if (log_level >= 2) {
|
||||
log_puts("relocated to ");
|
||||
log_putu((dev_mmcpos / (MTC_SEC * 3600)) % 24);
|
||||
log_putu(hr);
|
||||
log_puts(":");
|
||||
log_putu((dev_mmcpos / (MTC_SEC * 60)) % 60);
|
||||
log_putu(min);
|
||||
log_puts(":");
|
||||
log_putu((dev_mmcpos / (MTC_SEC)) % 60);
|
||||
log_putu(sec);
|
||||
log_puts(".");
|
||||
log_putu((dev_mmcpos / (MTC_SEC / 100)) % 100);
|
||||
log_puts("\n");
|
||||
log_putu(fr);
|
||||
log_puts(".");
|
||||
log_putu(cent);
|
||||
log_puts(" at ");
|
||||
log_putu(fps);
|
||||
log_puts("fps\n");
|
||||
}
|
||||
if (dev_pstate == DEV_START) {
|
||||
dev_mmcstop();
|
||||
@ -870,11 +909,12 @@ dev_imsg(unsigned char *msg, unsigned int len)
|
||||
dev_mmcstop();
|
||||
return;
|
||||
}
|
||||
dev_mmcloc((x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
|
||||
x->u.loc.min * 60 * MTC_SEC +
|
||||
x->u.loc.sec * MTC_SEC +
|
||||
x->u.loc.fr * (MTC_SEC / fps) +
|
||||
x->u.loc.cent * (MTC_SEC / 100 / fps));
|
||||
dev_mmcloc(x->u.loc.hr & 0x1f,
|
||||
x->u.loc.min,
|
||||
x->u.loc.sec,
|
||||
x->u.loc.fr,
|
||||
x->u.loc.cent,
|
||||
fps);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1010,7 +1050,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_mmcpos = 0;
|
||||
for (s = slot_list; s != NULL; s = s->next)
|
||||
slot_init(s);
|
||||
for (s = slot_list; s != NULL; s = s->next)
|
||||
@ -1279,6 +1318,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)
|
||||
{
|
||||
@ -1286,6 +1339,7 @@ main(int argc, char **argv)
|
||||
char *port, *dev;
|
||||
struct aparams par;
|
||||
int n_flag, c;
|
||||
long long pos;
|
||||
|
||||
vol = 127;
|
||||
dup = 0;
|
||||
@ -1299,8 +1353,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))
|
||||
@ -1320,13 +1376,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;
|
||||
@ -1339,10 +1399,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;
|
||||
@ -1372,7 +1436,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
if (mode != (SIO_PLAY | SIO_REC)) {
|
||||
log_puts("both -i and -o required\n");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (!offline())
|
||||
return 1;
|
||||
|
@ -17,11 +17,6 @@
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
|
||||
/*
|
||||
* units used for MTC clock.
|
||||
*/
|
||||
#define MTC_SEC 2400 /* 1 second is 2400 ticks */
|
||||
|
||||
/*
|
||||
* limits
|
||||
*/
|
||||
|
55
aucat/dsp.c
55
aucat/dsp.c
@ -268,35 +268,50 @@ aparams_native(struct aparams *par)
|
||||
}
|
||||
|
||||
/*
|
||||
* return the number of output frames resamp_do() would produce with
|
||||
* the given number of input frames
|
||||
* return the number of input and output frame that would
|
||||
* be consumed
|
||||
*/
|
||||
int
|
||||
resamp_ocnt(struct resamp *p, int icnt)
|
||||
void
|
||||
resamp_getcnt(struct resamp *p, int *icnt, int *ocnt)
|
||||
{
|
||||
return ((long long)p->oblksz * icnt + p->diff) / p->iblksz;
|
||||
}
|
||||
int diff, ifr, ofr;
|
||||
|
||||
/*
|
||||
* return the number of input frames resamp_do() needs in order to
|
||||
* produce the given number of output frames
|
||||
*/
|
||||
int
|
||||
resamp_icnt(struct resamp *p, int ocnt)
|
||||
{
|
||||
return ((long long)p->iblksz * ocnt - p->diff +
|
||||
p->oblksz - 1) / p->oblksz;
|
||||
diff = p->diff;
|
||||
ifr = *icnt;
|
||||
ofr = *ocnt;
|
||||
|
||||
for (;;) {
|
||||
if (diff < 0) {
|
||||
if (ifr == 0)
|
||||
break;
|
||||
diff += p->oblksz;
|
||||
ifr--;
|
||||
} else if (diff > 0) {
|
||||
if (ofr == 0)
|
||||
break;
|
||||
diff -= p->iblksz;
|
||||
ofr--;
|
||||
} else {
|
||||
if (ifr == 0 || ofr == 0)
|
||||
break;
|
||||
diff -= p->iblksz;
|
||||
diff += p->oblksz;
|
||||
ifr--;
|
||||
ofr--;
|
||||
}
|
||||
}
|
||||
*icnt -= ifr;
|
||||
*ocnt -= ofr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resample the given number of frames. The number of output frames
|
||||
* must match the coresponding number the input frames. Either
|
||||
* use:
|
||||
* must match the coresponding number the input frames. Either always
|
||||
* use icnt and ocnt such that:
|
||||
*
|
||||
* icnt * orate = ocnt * irate
|
||||
* icnt * oblksz = ocnt * iblksz
|
||||
*
|
||||
* or use resamp_icnt() or resamp_ocnt() to calculate the proper
|
||||
* numbers.
|
||||
* or use resamp_getcnt() to calculate the proper numbers.
|
||||
*/
|
||||
void
|
||||
resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt)
|
||||
|
@ -147,8 +147,7 @@ int aparams_strtoenc(struct aparams *, char *);
|
||||
int aparams_enctostr(struct aparams *, char *);
|
||||
int aparams_native(struct aparams *);
|
||||
|
||||
int resamp_ocnt(struct resamp *, int);
|
||||
int resamp_icnt(struct resamp *, int);
|
||||
void resamp_getcnt(struct resamp *, int *, int *);
|
||||
void resamp_do(struct resamp *, adata_t *, adata_t *, int, int);
|
||||
void resamp_init(struct resamp *, unsigned int, unsigned int, int);
|
||||
void enc_do(struct conv *, unsigned char *, unsigned char *, int);
|
||||
|
Loading…
Reference in New Issue
Block a user