ref: 4dbbf99a5abb379e99fd27ad8d337bb794ee6f4e
parent: 313e4bf78ea365ad29ef9c42b359b7994c566b6d
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Mon Jun 12 18:08:16 EDT 2023
mixfs: add "volume" file with "mix" control to set the output volume of the mixed inputs
--- a/sys/man/1/audio
+++ b/sys/man/1/audio
@@ -346,8 +346,13 @@
.B /mnt/mix
and then binds
.B /mnt/mix/audio
+and
+.B /mnt/mix/volume
over
.BR /dev .
+.B /dev/volume
+from the parent namespace is proxied with an additional control "mix"
+which is used to set the output volume of the mixer.
A alternative mountpoint
.I mtpt
can be specified with the
--- a/sys/src/cmd/audio/mixfs/mixfs.c
+++ b/sys/src/cmd/audio/mixfs/mixfs.c
@@ -11,6 +11,9 @@
FREQ = 44100,
};
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
typedef struct Stream Stream;
struct Stream
{
@@ -33,6 +36,10 @@
Stream streams[16];
+int volfd;
+int volume[2] = {100, 100};
+int vol64k[2] = {65536, 65536};
+
int
s16(uchar *p)
{
@@ -101,10 +108,9 @@
{
Stream *s;
- if(f->file != nil && strcmp(f->file->name, "audio") == 0 && (s = f->aux) != nil){
- f->aux = nil;
+ if(f->file != nil && strcmp(f->file->name, "audio") == 0 && (s = f->aux) != nil)
s->used = 0;
- }
+ f->aux = nil;
}
void
@@ -179,7 +185,7 @@
rp = mixrp;
for(i=0; i<m; i++){
for(j=0; j<NCHAN; j++){
- v = clip16(mixbuf[rp % NBUF][j]);
+ v = clip16(mixbuf[rp % NBUF][j])*vol64k[j] / 65536;
lbbuf[rp % NBUF][j] = v;
mixbuf[rp % NBUF][j] = 0;
*p++ = v & 0xFF;
@@ -205,6 +211,18 @@
Stream *s;
uchar *p;
+ if(r->fid->file->aux == &volfd){
+ static char svol[4096];
+ if(r->ifcall.offset == 0){
+ m = snprint(svol, sizeof(svol), "mix %d %d\n", volume[0], volume[1]);
+ if((n = pread(volfd, svol+m, sizeof(svol)-m-1, 0)) > 0)
+ svol[m+n] = 0;
+ }
+ readstr(r, svol);
+ respond(r, nil);
+ return;
+ }
+
p = (uchar*)r->ofcall.data;
n = r->ifcall.count;
n &= ~(NCHAN*2 - 1);
@@ -260,6 +278,39 @@
Stream *s;
uchar *p;
+ if(r->fid->file->aux == &volfd){
+ char msg[64], *f[5];
+ int x[2], nf;
+
+ r->ofcall.count = r->ifcall.count;
+ snprint(msg, sizeof(msg), "%.*s",
+ utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data);
+ nf = tokenize(msg, f, nelem(f));
+ if(nf > 1 && strcmp(f[0], "mix") == 0){
+ x[0] = atoi(f[1]);
+ x[1] = nf < 3 ? x[0] : atoi(f[2]);
+ if(f[1][0] == '+' || f[1][0] == '-'){
+ x[0] += volume[0];
+ x[1] += volume[1];
+ }
+ volume[0] = MIN(MAX(0, x[0]), 100);
+ volume[1] = MIN(MAX(0, x[1]), 100);
+ /* ≈60dB dynamic range; [0-100] → [0-65536] */
+ vol64k[0] = 65.536 * (exp(volume[0] * 0.0690876) - 1.0);
+ vol64k[1] = 65.536 * (exp(volume[1] * 0.0690876) - 1.0);
+ }else if(volfd >= 0){
+ if(write(volfd, r->ifcall.data, r->ifcall.count) < 0){
+ responderror(r);
+ return;
+ }
+ }else{
+ respond(r, "bad msg");
+ return;
+ }
+ respond(r, nil);
+ return;
+ }
+
p = (uchar*)r->ifcall.data;
n = r->ifcall.count;
r->ofcall.count = n;
@@ -313,17 +364,12 @@
{
Stream *s;
- if(r->fid->file == nil){
- respond(r, "bug");
- return;
- }
- if(strcmp(r->fid->file->name, "audio") == 0 && (s = r->fid->aux) != nil){
+ r->d.length = 0;
+ if(r->fid->file != nil && strcmp(r->fid->file->name, "audio") == 0 && (s = r->fid->aux) != nil){
qlock(s);
if(s->run){
r->d.length = (long)(s->wp - mixrp);
r->d.length *= NCHAN*2;
- } else {
- r->d.length = 0;
}
qunlock(s);
}
@@ -362,7 +408,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-D] [-s srvname] [-m mtpt]\n", argv0);
+ fprint(2, "usage: %s [-D] [-v] [-s srvname] [-m mtpt]\n", argv0);
exits("usage");
}
@@ -370,7 +416,7 @@
threadmain(int argc, char **argv)
{
char *srv = nil;
- char *mtpt = "/mnt/mix";
+ char *m, *mtpt = "/mnt/mix";
ARGBEGIN{
case 'D':
@@ -389,14 +435,23 @@
if(argc)
usage();
+ volfd = open("/dev/volume", ORDWR);
fs.tree = alloctree(nil, nil, DMDIR|0777, nil);
createfile(fs.tree->root, "audio", nil, 0666, nil);
+ createfile(fs.tree->root, "volume", nil, 0666, &volfd);
threadpostmountsrv(&fs, srv, mtpt, MREPL);
- mtpt = smprint("%s/audio", mtpt);
- if(bind(mtpt, "/dev/audio", MREPL) < 0)
+ m = smprint("%s/audio", mtpt);
+ if(bind(m, "/dev/audio", MREPL) < 0)
sysfatal("bind: %r");
- free(mtpt);
+ free(m);
+
+ if(volfd >= 0){
+ m = smprint("%s/volume", mtpt);
+ if(bind(m, "/dev/volume", MREPL) < 0)
+ sysfatal("bind: %r");
+ free(m);
+ }
threadexits(0);
}