1
0
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:
Alexandre Ratchov 2016-06-07 13:22:31 +02:00
parent 8ceee9aeff
commit 74cb9d0038
5 changed files with 161 additions and 76 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 */
};
@ -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;

View File

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

View File

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

View File

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