Module Name:    src
Committed By:   mrg
Date:           Sat Nov  9 12:46:44 UTC 2019

Modified Files:
        src/usr.bin/audio/common: audio.c libaudio.h sun.c wav.c
        src/usr.bin/audio/play: audioplay.1 play.c

Log Message:
add support for playing IEEE float32 and float64 RIFF WAVE
samples on platforms that have these types natively, and
can handle signed linear 32 bit samples.  explicitly
disabled on vax, run-or-compile-time sizeof() check
disabled for everyone else

now i can play a float32 .wav file i found.
float64 not tested.

copyright maint, update HISTORY, update audio drivers list.


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/usr.bin/audio/common/audio.c
cvs rdiff -u -r1.20 -r1.21 src/usr.bin/audio/common/libaudio.h
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/audio/common/sun.c
cvs rdiff -u -r1.14 -r1.15 src/usr.bin/audio/common/wav.c
cvs rdiff -u -r1.26 -r1.27 src/usr.bin/audio/play/audioplay.1
cvs rdiff -u -r1.57 -r1.58 src/usr.bin/audio/play/play.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/audio/common/audio.c
diff -u src/usr.bin/audio/common/audio.c:1.25 src/usr.bin/audio/common/audio.c:1.26
--- src/usr.bin/audio/common/audio.c:1.25	Wed Aug  5 06:54:39 2015
+++ src/usr.bin/audio/common/audio.c	Sat Nov  9 12:46:44 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: audio.c,v 1.25 2015/08/05 06:54:39 mrg Exp $	*/
+/*	$NetBSD: audio.c,v 1.26 2019/11/09 12:46:44 mrg Exp $	*/
 
 /*
- * Copyright (c) 1999 Matthew R. Green
+ * Copyright (c) 1999, 2013, 2015, 2019 Matthew R. Green
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: audio.c,v 1.25 2015/08/05 06:54:39 mrg Exp $");
+__RCSID("$NetBSD: audio.c,v 1.26 2019/11/09 12:46:44 mrg Exp $");
 #endif
 
 
@@ -110,6 +110,8 @@ static const struct {
 	{ AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
 	{ AudioEmpeg_l2_system,	AUDIO_ENCODING_MPEG_L2_SYSTEM },
 	{ AudioEac3,		AUDIO_ENCODING_AC3 },
+	{ "ieee_float32",	AUDIO_ENCODING_LIBAUDIO_FLOAT32 },
+	{ "ieee_float64",	AUDIO_ENCODING_LIBAUDIO_FLOAT64 },
 	{ NULL, -1 }
 };
 

Index: src/usr.bin/audio/common/libaudio.h
diff -u src/usr.bin/audio/common/libaudio.h:1.20 src/usr.bin/audio/common/libaudio.h:1.21
--- src/usr.bin/audio/common/libaudio.h:1.20	Wed Aug  5 06:54:39 2015
+++ src/usr.bin/audio/common/libaudio.h	Sat Nov  9 12:46:44 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: libaudio.h,v 1.20 2015/08/05 06:54:39 mrg Exp $	*/
+/*	$NetBSD: libaudio.h,v 1.21 2019/11/09 12:46:44 mrg Exp $	*/
 
 /*
- * Copyright (c) 1999, 2009 Matthew R. Green
+ * Copyright (c) 1999, 2009, 2013, 2015, 2019 Matthew R. Green
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,17 @@
 int	audio_format_from_str (char *);
 
 /*
+ * Audio encoding formats; this is a additional to those set
+ * in sys/audioio.h, but with a large offset to avoid future
+ * conflicts (additional ones are libaudio-software only.)
+ *
+ * This is to support floating-point WAV files.  These require
+ * software conversion to a supported format.
+ */
+#define	AUDIO_ENCODING_LIBAUDIO_FLOAT32    1001	/* 32-bit IEEE FP. */
+#define	AUDIO_ENCODING_LIBAUDIO_FLOAT64    1002	/* 64-bit IEEE FP. */
+
+/*
  * We copy the Sun/NeXT on-disk audio header format and document what
  * we know of it here.
  *
@@ -107,10 +118,11 @@ int	audio_encoding_to_sun (int, int, int
 #define	WAVAUDIO_FILE_MAGIC_FMT		((u_int32_t)0x666d7420)
 #define	WAVAUDIO_FILE_MAGIC_DATA	((u_int32_t)0x64617461)
 
-/* purloined from public Microsoft RIFF docs via sox or mplayer */
+/* purloined from public Microsoft RIFF docs via sox, mplayer, or directly */
 #define WAVE_FORMAT_UNKNOWN		(0x0000)
 #define WAVE_FORMAT_PCM			(0x0001)
 #define WAVE_FORMAT_ADPCM		(0x0002)
+#define WAVE_FORMAT_IEEE_FLOAT		(0x0003)
 #define WAVE_FORMAT_ALAW		(0x0006)
 #define WAVE_FORMAT_MULAW		(0x0007)
 #define WAVE_FORMAT_OKI_ADPCM		(0x0010)

Index: src/usr.bin/audio/common/sun.c
diff -u src/usr.bin/audio/common/sun.c:1.9 src/usr.bin/audio/common/sun.c:1.10
--- src/usr.bin/audio/common/sun.c:1.9	Wed Aug  5 06:54:39 2015
+++ src/usr.bin/audio/common/sun.c	Sat Nov  9 12:46:44 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: sun.c,v 1.9 2015/08/05 06:54:39 mrg Exp $	*/
+/*	$NetBSD: sun.c,v 1.10 2019/11/09 12:46:44 mrg Exp $	*/
 
 /*
- * Copyright (c) 2002 Matthew R. Green
+ * Copyright (c) 2002, 2013, 2015 Matthew R. Green
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: sun.c,v 1.9 2015/08/05 06:54:39 mrg Exp $");
+__RCSID("$NetBSD: sun.c,v 1.10 2019/11/09 12:46:44 mrg Exp $");
 #endif
 
 

Index: src/usr.bin/audio/common/wav.c
diff -u src/usr.bin/audio/common/wav.c:1.14 src/usr.bin/audio/common/wav.c:1.15
--- src/usr.bin/audio/common/wav.c:1.14	Sat Nov 25 17:18:15 2017
+++ src/usr.bin/audio/common/wav.c	Sat Nov  9 12:46:44 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: wav.c,v 1.14 2017/11/25 17:18:15 jdolecek Exp $	*/
+/*	$NetBSD: wav.c,v 1.15 2019/11/09 12:46:44 mrg Exp $	*/
 
 /*
- * Copyright (c) 2002, 2009 Matthew R. Green
+ * Copyright (c) 2002, 2009, 2013, 2015, 2019 Matthew R. Green
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: wav.c,v 1.14 2017/11/25 17:18:15 jdolecek Exp $");
+__RCSID("$NetBSD: wav.c,v 1.15 2019/11/09 12:46:44 mrg Exp $");
 #endif
 
 
@@ -60,6 +60,7 @@ static const struct {
 	{ WAVE_FORMAT_UNKNOWN, 	"Microsoft Official Unknown" },
 	{ WAVE_FORMAT_PCM,	"Microsoft PCM" },
 	{ WAVE_FORMAT_ADPCM,	"Microsoft ADPCM" },
+	{ WAVE_FORMAT_IEEE_FLOAT,"Microsoft IEEE Floating-Point" },
 	{ WAVE_FORMAT_ALAW,	"Microsoft A-law" },
 	{ WAVE_FORMAT_MULAW,	"Microsoft mu-law" },
 	{ WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" },
@@ -188,6 +189,20 @@ audio_wav_parse_hdr(void *hdr, size_t sz
 		newenc = AUDIO_ENCODING_ULAW;
 		newprec = 8;
 		break;
+	case WAVE_FORMAT_IEEE_FLOAT:
+		switch (getle16(fmt.bits_per_sample)) {
+		case 32:
+			newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT32;
+			newprec = 32;
+			break;
+		case 64:
+			newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT64;
+			newprec = 32;
+			break;
+		default:
+			return (AUDIO_EWAVBADPCM);
+		}
+		break;
 	}
 
 	do {

Index: src/usr.bin/audio/play/audioplay.1
diff -u src/usr.bin/audio/play/audioplay.1:1.26 src/usr.bin/audio/play/audioplay.1:1.27
--- src/usr.bin/audio/play/audioplay.1:1.26	Tue Mar 18 18:20:44 2014
+++ src/usr.bin/audio/play/audioplay.1	Sat Nov  9 12:46:44 2019
@@ -1,6 +1,6 @@
-.\"	$NetBSD: audioplay.1,v 1.26 2014/03/18 18:20:44 riastradh Exp $
+.\"	$NetBSD: audioplay.1,v 1.27 2019/11/09 12:46:44 mrg Exp $
 .\"
-.\" Copyright (c) 1998, 1999, 2002, 2010 Matthew R. Green
+.\" Copyright (c) 1998, 1999, 2002, 2010, 2019 Matthew R. Green
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 30, 2010
+.Dd November 8, 2019
 .Dt AUDIOPLAY 1
 .Os
 .Sh NAME
@@ -172,6 +172,15 @@ can be used to play Sun/NeXT audio files
 can be configured in the
 .Dq Netscape
 web browser as the program to use when playing audio files.
+.Pp
+In addition to the audio driver encodings list in the EXAMPLES section,
+.Nm
+supports playing IEEE floating point data in RIFF WAVE audio files
+(with one caveat that the flaoting point size must be native.)
+In this case
+.Nm
+converts the floating point data into signed linear samples before
+they are passed to the chosen audio device.
 .Sh ERRORS
 If the audio device or the control device can not be opened, and error is
 returned.
@@ -182,29 +191,55 @@ hardware driver.
 .Sh SEE ALSO
 .Xr audioctl 1 ,
 .Xr audiorecord 1 ,
+.Xr aica 4 ,
+.Xr arcofi 4 ,
 .Xr aria 4 ,
 .Xr audio 4 ,
 .Xr audioamd 4 ,
 .Xr auich 4 ,
+.Xr auixp 4 ,
+.Xr ausoc 4 ,
 .Xr autri 4 ,
 .Xr auvia 4 ,
+.Xr awacs 4 ,
+.Xr bba 4 ,
+.Xr btsco 4 ,
 .Xr clcs 4 ,
 .Xr clct 4 ,
 .Xr cmpci 4 ,
+.Xr dbri 4 ,
 .Xr eap 4 ,
 .Xr emuxki 4 ,
 .Xr esm 4 ,
 .Xr eso 4 ,
 .Xr ess 4 ,
 .Xr fms 4 ,
+.Xr gcscaudio 4 ,
 .Xr gus 4 ,
 .Xr guspnp 4 ,
+.Xr haltwo 4 ,
+.Xr harmony 4 ,
+.Xr hdafg 4 ,
+.Xr mavb 4 ,
 .Xr neo 4 ,
+.Xr pad 4 ,
+.Xr pas 4 ,
+.Xr paud 4 ,
+.Xr repluse 4 ,
 .Xr sb 4 ,
+.Xr snapper 4 ,
 .Xr sv 4 ,
+.Xr toccata 4 ,
+.Xr uaudio 4 ,
+.Xr vaudio 4 ,
+.Xr vcaudio 4 ,
+.Xr vraiu 4 ,
+.Xr vs 4 ,
+.Xr vsaudio 4 ,
 .Xr wss 4 ,
 .Xr yds 4 ,
-.Xr ym 4
+.Xr ym 4 ,
+.Xr zaudio 4
 .Sh HISTORY
 The
 .Nm
@@ -214,6 +249,10 @@ The
 .Nm
 was first made available in
 .Nx 1.4 .
+Support for RIFF WAVE recording was introduced in
+.Nx 1.6 .
+Support for RIFF WAVE IEEE floating point data was introduced in
+.Nx 10.0 .
 .Sh AUTHORS
 The
 .Nm

Index: src/usr.bin/audio/play/play.c
diff -u src/usr.bin/audio/play/play.c:1.57 src/usr.bin/audio/play/play.c:1.58
--- src/usr.bin/audio/play/play.c:1.57	Sat May  4 08:27:30 2019
+++ src/usr.bin/audio/play/play.c	Sat Nov  9 12:46:44 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: play.c,v 1.57 2019/05/04 08:27:30 isaki Exp $	*/
+/*	$NetBSD: play.c,v 1.58 2019/11/09 12:46:44 mrg Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000, 2001, 2002, 2010 Matthew R. Green
@@ -28,10 +28,9 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: play.c,v 1.57 2019/05/04 08:27:30 isaki Exp $");
+__RCSID("$NetBSD: play.c,v 1.58 2019/11/09 12:46:44 mrg Exp $");
 #endif
 
-
 #include <sys/param.h>
 #include <sys/audioio.h>
 #include <sys/ioctl.h>
@@ -51,10 +50,14 @@ __RCSID("$NetBSD: play.c,v 1.57 2019/05/
 
 #include "libaudio.h"
 
+typedef size_t (*convert)(void *inbuf, void *outbuf, size_t len);
+
 static void usage(void) __dead;
 static void play(char *);
 static void play_fd(const char *, int);
-static ssize_t audioctl_write_fromhdr(void *, size_t, int, off_t *, const char *);
+static ssize_t audioctl_write_fromhdr(void *, size_t, int,
+				      off_t *, const char *,
+				      convert *);
 static void cleanup(int) __dead;
 
 static audio_info_t	info;
@@ -214,9 +217,90 @@ cleanup(int signo)
 	exit(exitstatus);
 }
 
+#ifndef __vax__
+static size_t
+float32_to_linear32(void *inbuf, void *outbuf, size_t len)
+{
+	uint8_t *inbuf8 = inbuf, *end = inbuf8 + len;
+	uint8_t *outbuf8 = outbuf;
+	float f;
+	int32_t i;
+
+	while (inbuf8 + sizeof f <= end) {
+		memcpy(&f, inbuf8, sizeof f);
+
+		/* saturate */
+		if (f < -1.0)
+			f = -1.0;
+		if (f > 1.0)
+			f = 1.0;
+
+		/* Convert -1.0 to +1.0 into a 32 bit signed value */
+		i = f * ((1u << 31) - 1);
+
+		memcpy(outbuf8, &i, sizeof i);
+
+		inbuf8 += sizeof f;
+		outbuf8 += sizeof i;
+	}
+
+	return len;
+}
+
+static size_t
+float64_to_linear32(void *inbuf, void *outbuf, size_t len)
+{
+	uint8_t *inbuf8 = inbuf, *end = inbuf8 + len;
+	uint8_t *outbuf8 = outbuf;
+	double f;
+	int32_t i;
+
+	while (inbuf8 + sizeof f <= end) {
+		memcpy(&f, inbuf8, sizeof f);
+
+		/* saturate */
+		if (f < -1.0)
+			f = -1.0;
+		if (f > 1.0)
+			f = 1.0;
+
+		/* Convert -1.0 to +1.0 into a 32 bit signed value */
+		i = f * ((1u << 31) - 1);
+
+		memcpy(outbuf8, &i, sizeof i);
+
+		inbuf8 += sizeof f;
+		outbuf8 += sizeof i;
+	}
+
+	return len / 2;
+}
+#endif /* __vax__ */
+
+static size_t
+audio_write(int fd, void *buf, size_t len, convert conv)
+{
+	static void *convert_buffer;
+	static size_t convert_buffer_size;
+
+	if (conv == NULL)
+		return write(fd, buf, len);
+
+	if (convert_buffer == NULL || convert_buffer_size < len) {
+		free(convert_buffer);
+		convert_buffer = malloc(len);
+		if (convert_buffer == NULL)
+			err(1, "malloc of convert buffer failed");
+		convert_buffer_size = len;
+	}
+	len = conv(buf, convert_buffer, len);
+	return write(fd, convert_buffer, len);
+}
+
 static void
 play(char *file)
 {
+	convert conv = NULL;
 	struct stat sb;
 	void *addr, *oaddr;
 	off_t	filesize;
@@ -265,10 +349,11 @@ play(char *file)
 	madvise(addr, sizet_filesize, MADV_SEQUENTIAL);
 
 	/*
-	 * get the header length and set up the audio device
+	 * get the header length and set up the audio device, and
+	 * determine any conversion needed.
 	 */
 	if ((hdrlen = audioctl_write_fromhdr(addr,
-	    sizet_filesize, audiofd, &datasize, file)) < 0) {
+	    sizet_filesize, audiofd, &datasize, file, &conv)) < 0) {
 		if (play_errstring)
 			errx(1, "%s: %s", play_errstring, file);
 		else
@@ -284,7 +369,7 @@ play(char *file)
 	}
 
 	while ((uint64_t)datasize > bufsize) {
-		nw = write(audiofd, addr, bufsize);
+		nw = audio_write(audiofd, addr, bufsize, conv);
 		if (nw == -1)
 			err(1, "write failed");
 		if ((size_t)nw != bufsize)
@@ -292,7 +377,7 @@ play(char *file)
 		addr = (char *)addr + bufsize;
 		datasize -= bufsize;
 	}
-	nw = write(audiofd, addr, datasize);
+	nw = audio_write(audiofd, addr, datasize, conv);
 	if (nw == -1)
 		err(1, "final write failed");
 	if ((off_t)nw != datasize)
@@ -312,6 +397,7 @@ play(char *file)
 static void
 play_fd(const char *file, int fd)
 {
+	convert conv = NULL;
 	char    *buffer = malloc(bufsize);
 	ssize_t hdrlen;
 	int     nr, nw;
@@ -331,7 +417,7 @@ play_fd(const char *file, int fd)
 		}
 		err(1, "unexpected EOF");
 	}
-	hdrlen = audioctl_write_fromhdr(buffer, nr, audiofd, &datasize, file);
+	hdrlen = audioctl_write_fromhdr(buffer, nr, audiofd, &datasize, file, &conv);
 	if (hdrlen < 0) {
 		if (play_errstring)
 			errx(1, "%s: %s", play_errstring, file);
@@ -347,7 +433,7 @@ play_fd(const char *file, int fd)
 	while (datasize == 0 || dataout < datasize) {
 		if (datasize != 0 && dataout + nr > datasize)
 			nr = datasize - dataout;
-		nw = write(audiofd, buffer, nr);
+		nw = audio_write(audiofd, buffer, nr, conv);
 		if (nw == -1)
 			err(1, "audio device write failed");
 		if (nw != nr)
@@ -374,11 +460,13 @@ read_error:
  * uses the local "info" variable. blah... fix me!
  */
 static ssize_t
-audioctl_write_fromhdr(void *hdr, size_t fsz, int fd, off_t *datasize, const char *file)
+audioctl_write_fromhdr(void *hdr, size_t fsz, int fd, off_t *datasize, const char *file, convert *conv)
 {
 	sun_audioheader	*sunhdr;
 	ssize_t	hdr_len = 0;
 
+	*conv = NULL;
+
 	AUDIO_INITINFO(&info);
 	sunhdr = hdr;
 	if (ntohl(sunhdr->magic) == AUDIO_FILE_MAGIC) {
@@ -457,6 +545,32 @@ set_audio_mode:
 		   enc ? enc : "");
 	}
 
+#ifndef __vax__
+	if (info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT32 ||
+	    info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT64) {
+		const char *msg;
+
+		if (info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT32) {
+			if (sizeof(float) * CHAR_BIT != 32)
+				return -1;
+			*conv = float32_to_linear32;
+			msg = "32";
+		} else {
+			if (sizeof(double) * CHAR_BIT != 64)
+				return -1;
+			*conv = float64_to_linear32;
+			msg = "32";
+		}
+		info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
+		info.play.precision = 32;
+		if (verbose)
+			printf("%s: converting IEEE float%s to precision=%d "
+			       "encoding=%s\n", file, msg,
+			       info.play.precision,
+			       audio_enc_from_val(info.play.encoding));
+	}
+#endif /* __vax__ */
+
 	if (ioctl(fd, AUDIO_SETINFO, &info) < 0)
 		err(1, "failed to set audio info");
 

Reply via email to