shithub: pplay

Download patch

ref: 6d4ecd6bb7c46e508d89ae2bab911f5f3b206d94
parent: e68cc1702b1f63f540deafb5567f7dd347e3fe89
author: qwx <qwx@sciops.net>
date: Sun Feb 19 10:43:34 EST 2023

add audio/pcmmix: mix multiple pcm files and scale global volume

--- a/mkfile
+++ b/mkfile
@@ -1,7 +1,10 @@
 </$objtype/mkfile
 BIN=/$objtype/bin/audio
 MAN=/sys/man/1
-TARG=pplay
+TARG=\
+	pcmmix\
+	pplay\
+
 OFILES=\
 	chunk.$O\
 	cmd.$O\
@@ -10,4 +13,7 @@
 	util.$O\
 
 HFILES=dat.h fns.h
-</sys/src/cmd/mkone
+</sys/src/cmd/mkmany
+
+$O.pcmmix: pcmmix.$O
+	$LD $LDFLAGS -o $target pcmmix.$O
--- /dev/null
+++ b/pcmmix.c
@@ -1,0 +1,82 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct File File;
+struct File{
+	int fd;
+	char *path;
+	int n;
+	uchar buf[8192];
+};
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-f] [FILE..]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int n;
+	double f;
+	uchar u[8192], *p, *q;
+	s32int v;
+	int nf;
+	File *ftab, *fp;
+	Dir *d;
+
+	f = 1.0;
+	ARGBEGIN{
+	case 'f': f = strtod(EARGF(usage()), nil); break;
+	default: usage();
+	}ARGEND
+	nf = argc + 1;
+	if((ftab = mallocz(nf * sizeof *ftab, 1)) == nil)
+		sysfatal("mallocz: %r");
+	fp = ftab;
+	fp->path = "stdin";
+	if((d = dirfstat(0)) == nil)
+		sysfatal("dirfstat: %r");
+	fp->fd = d->length > 0 ? 0 : -1;
+	free(d);
+	fp++;
+	while(*argv != nil){
+		if((fp->fd = open(*argv, OREAD)) < 0)
+			sysfatal("open: %r");
+		fp->path = *argv++;
+		fp++;
+	}
+	for(;;){
+		n = 0;
+		for(fp=ftab; fp<ftab+nf; fp++){
+			if(fp->fd < 0)
+				continue;
+			if((fp->n = read(fp->fd, fp->buf, sizeof fp->buf)) > 0)
+				continue;
+			fp->fd = -1;
+			if(fp->n < 0)
+				fprint(2, "file %s: read: %r\n", fp->path);
+		}
+		memset(u, 0, sizeof u);
+		for(fp=ftab; fp<ftab+nf; fp++){
+			for(p=u, q=fp->buf; q<fp->buf+fp->n; p+=2, q+=2){
+				v = (s16int)(q[1] << 8 | q[0]);
+				v *= f;
+				v += (s16int)(p[1] << 8 | p[0]);
+				if(v > 32767)
+					v = 32767;
+				else if(v < -32768)
+					v = -32768;
+				p[0] = v;
+				p[1] = v >> 8;
+			}
+			if(fp->n > n)
+				n = fp->n;
+		}
+		if(n == 0)
+			break;
+		write(1, u, n);
+	}
+	exits(nil);
+}