On Thu, May 12, 2011 at 12:36:43AM +0300, Sviatoslav Chagaev wrote:
> > >
> > > So, why is what I'm proposing better than what currently exists:
> > >
> > > * Resembles how sound behaves in real world more closely;
> > > * Doesn't violate the principle of least surprise;
> > > * No more annoying volume jumps up and down;
> > > * No need to use the -v option anymore / less stuff to remember / "it
> > > just works";
> > > * No more choosing between being annoyed by volume jumps or loosing
> > > dynamic range.
> > >
> >
> > I guess this works well with your recordings by accident, as it would
> > with mines. I bet they are pre-divided, so you almost never hit the
> > ADATA_MIN and ADATA_MAX bundary, and there's almost no clipping, is
> > it?
> >
>
> Before posting, I tested by playing, I don't remember exactly,
> either 2 either 3 files simultaneously. And honestly, I didn't notice
> any distortions. This is probably because of the fact that like you
> said, it's rare that all the waves have +/-ADATA_UNIT value at a given
> moment. After reading your replies, I tried playing ~8 files
> simultaneously and I indeed heard clearly sound distortion.
>
> > If so, for such streams you could do:
> >
> > int
> > adata_sadd(int x, int y)
> > {
> > return x + y;
> > }
> >
>
> The ADATA_MIN ADATA_MAX checks are needed because without them, you
> will start hearing distorions as soon as you play 2 files and this
> distortion is much worse sounding than the saturation distortion.
>
While discussing about what defaults are good for what, here's a diff
I plan to put in soon.
It's to add a switch to make automatic volume changes optional.
Sometimes I need this when I'm playing pre-scaled streams, or to mix
streams that fade in / fade out.
-- Alexandre
Index: aproc.c
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/aproc.c,v
retrieving revision 1.9
diff -u -p -r1.9 aproc.c
--- aproc.c 28 Apr 2011 07:17:18 -0000 1.9
+++ aproc.c 13 May 2011 10:20:37 -0000
@@ -1016,7 +1016,7 @@ struct aproc_ops mix_ops = {
};
struct aproc *
-mix_new(char *name, int maxlat, unsigned round)
+mix_new(char *name, int maxlat, unsigned round, unsigned autovol)
{
struct aproc *p;
@@ -1027,6 +1027,7 @@ mix_new(char *name, int maxlat, unsigned
p->u.mix.maxlat = maxlat;
p->u.mix.ctl = NULL;
p->u.mix.mon = NULL;
+ p->u.mix.autovol = autovol;
return p;
}
@@ -1039,6 +1040,9 @@ mix_setmaster(struct aproc *p)
unsigned n;
struct abuf *i, *j;
int weight;
+
+ if (!p->u.mix.autovol)
+ return;
/*
* count the number of inputs. If a set of inputs
Index: aproc.h
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/aproc.h,v
retrieving revision 1.2
diff -u -p -r1.2 aproc.h
--- aproc.h 4 Nov 2010 17:56:52 -0000 1.2
+++ aproc.h 13 May 2011 10:20:37 -0000
@@ -140,6 +140,7 @@ struct aproc {
unsigned abspos; /* frames produced */
struct aproc *ctl; /* MIDI control/sync */
struct aproc *mon; /* snoop output */
+ unsigned autovol; /* adjust volume dynamically */
} mix;
struct {
unsigned idle; /* frames since idleing */
@@ -239,7 +240,7 @@ void aproc_opos(struct aproc *, struct a
struct aproc *rfile_new(struct file *);
struct aproc *wfile_new(struct file *);
-struct aproc *mix_new(char *, int, unsigned);
+struct aproc *mix_new(char *, int, unsigned, unsigned);
struct aproc *sub_new(char *, int, unsigned);
struct aproc *resamp_new(char *, unsigned, unsigned);
struct aproc *enc_new(char *, struct aparams *);
Index: aucat.1
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/aucat.1,v
retrieving revision 1.10
diff -u -p -r1.10 aucat.1
--- aucat.1 3 May 2011 19:36:51 -0000 1.10
+++ aucat.1 13 May 2011 10:20:37 -0000
@@ -42,6 +42,7 @@
.Op Fl t Ar mode
.Op Fl U Ar unit
.Op Fl v Ar volume
+.Op Fl w Ar flag
.Op Fl x Ar policy
.Op Fl z Ar nframes
.Ek
@@ -114,7 +115,7 @@ Preceding streams
control MIDI ports
.Pq Fl q ,
and per-device options
-.Pq Fl abz
+.Pq Fl abwz
apply to this device.
Device mode and parameters are determined from streams
attached to it.
@@ -255,6 +256,22 @@ of clients as long as their number is sm
A good compromise is to use \-4dB attenuation (12 volume units)
for each additional client expected
(115 if 2 clients are expected, 103 for 3 clients, and so on).
+.It Fl w Ar flag
+Control whether the master volume resulting of all playback
+streams of the device is automatically adjusted.
+If the flag is
+.Va on ,
+then the master volume is lowered when necessary to ensure
+clipping never occurs.
+It should be set to
+.Va off
+to avoid lowering the volume twice if streams are already pre-scaled.
+Note that stream volumes can be manually set
+.Pq Fl v
+and if they are set correctly, the master volume doesn't need
+to be adjusted to avoid clipping.
+The default is
+.Va on .
.It Fl x Ar policy
Action when the output stream cannot accept
recorded data fast enough or the input stream
@@ -298,7 +315,7 @@ to a 400 frame block size.
.Pp
On the command line,
per-device parameters
-.Pq Fl abz
+.Pq Fl abwz
must precede the device definition
.Pq Fl f ,
and per-stream parameters
Index: aucat.c
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/aucat.c,v
retrieving revision 1.16
diff -u -p -r1.16 aucat.c
--- aucat.c 10 May 2011 09:49:54 -0000 1.16
+++ aucat.c 13 May 2011 10:20:37 -0000
@@ -251,6 +251,7 @@ struct cfdev {
struct aparams ipar; /* input (read) parameters */
struct aparams opar; /* output (write) parameters */
unsigned hold; /* open immediately */
+ unsigned autovol; /* adjust volumes */
unsigned bufsz; /* par.bufsz for sio device */
unsigned round; /* par.round for sio device */
unsigned mode; /* bitmap of MODE_XXX */
@@ -443,7 +444,7 @@ aucat_usage(void)
"[-o file]\n\t"
"[-q device] [-r rate] [-s name] [-t mode] [-U unit] "
"[-v volume]\n\t"
- "[-x policy] [-z nframes]\n",
+ "[-w flag] [-x policy] [-z nframes]\n",
stderr);
}
@@ -512,8 +513,9 @@ aucat_main(int argc, char **argv)
cd->bufsz = 0;
cd->round = 0;
cd->hold = 1;
+ cd->autovol = 1;
- while ((c = getopt(argc, argv,
"a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:L:t:j:z:")) != -1) {
+ while ((c = getopt(argc, argv,
"a:w:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:L:t:j:z:")) != -1) {
switch (c) {
case 'd':
#ifdef DEBUG
@@ -593,6 +595,9 @@ aucat_main(int argc, char **argv)
case 'a':
cd->hold = opt_onoff();
break;
+ case 'w':
+ cd->autovol = opt_onoff();
+ break;
case 'q':
cfmid_add(&cd->mids, optarg);
break;
@@ -731,7 +736,7 @@ aucat_main(int argc, char **argv)
} else {
d = dev_new_sio(cd->path, cd->mode | MODE_MIDIMASK,
&cd->ipar, &cd->opar, cd->bufsz, cd->round,
- cd->hold);
+ cd->hold, cd->autovol);
}
if (d == NULL)
errx(1, "%s: can't open device", cd->path);
Index: dev.c
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/dev.c,v
retrieving revision 1.2
diff -u -p -r1.2 dev.c
--- dev.c 29 Sep 2010 13:54:31 -0000 1.2
+++ dev.c 13 May 2011 10:20:37 -0000
@@ -114,7 +114,7 @@ struct dev *dev_list = NULL;
struct dev *
dev_new_sio(char *path,
unsigned mode, struct aparams *dipar, struct aparams *dopar,
- unsigned bufsz, unsigned round, unsigned hold)
+ unsigned bufsz, unsigned round, unsigned hold, unsigned autovol)
{
struct dev *d;
@@ -132,6 +132,7 @@ dev_new_sio(char *path,
d->reqbufsz = bufsz;
d->reqround = round;
d->hold = hold;
+ d->autovol = autovol;
d->pstate = DEV_CLOSED;
d->next = dev_list;
dev_list = d;
@@ -299,7 +300,7 @@ dev_open(struct dev *d)
* Create mixer, demuxer and monitor
*/
if (d->mode & MODE_PLAY) {
- d->mix = mix_new("play", d->bufsz, d->round);
+ d->mix = mix_new("play", d->bufsz, d->round, d->autovol);
d->mix->refs++;
d->mix->u.mix.ctl = d->midi;
}
Index: dev.h
===================================================================
RCS file: /home/alex/sndio/cvs/sndio/aucat/dev.h,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 dev.h
--- dev.h 19 Aug 2010 20:51:16 -0000 1.1.1.2
+++ dev.h 13 May 2011 10:20:37 -0000
@@ -34,6 +34,7 @@ struct dev {
unsigned reqround; /* block size */
unsigned reqrate; /* sample rate */
unsigned hold; /* hold the device open ? */
+ unsigned autovol; /* auto adjust playvol ? */
unsigned refcnt; /* number of openers */
#define DEV_CLOSED 0 /* closed */
#define DEV_INIT 1 /* stopped */
@@ -64,7 +65,8 @@ void dev_drain(struct dev *);
struct dev *dev_new_thru(void);
struct dev *dev_new_loop(struct aparams *, struct aparams *, unsigned);
struct dev *dev_new_sio(char *, unsigned,
- struct aparams *, struct aparams *, unsigned, unsigned, unsigned);
+ struct aparams *, struct aparams *,
+ unsigned, unsigned, unsigned, unsigned);
int dev_thruadd(struct dev *, char *, int, int);
void dev_midiattach(struct dev *, struct abuf *, struct abuf *);
unsigned dev_roundof(struct dev *, unsigned);