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

Reply via email to