Subject: Re: es1371.o sound module on a IBM405 gp walnut

From: David Blythe <[email-masked]>
Date: Mon, 19 Mar 2001 17:08:53 -0800

Ralph Blach wrote:
>
> Brad,
>
> Well it was endian problems.  I ran an mp3 to wav conversion that sox
> recomended.  I then had to do a word swap on the 16 bit data and it
> sounded fine.  Is there anyway to tell the driver that the samples are
> byte reversed?
>

I repeat the problem is in sox not the driver since sox is sending big
endian samples while telling the driver it is little endian.  Attached
is a patch to sox-12.17.1 oss.c that fixes sox.

cd sox-12.17.1; patch -p0 < sox.patch

	david

--- oss.c	Sun Aug 13 11:04:30 2000
+++ ../../sox-12.17.1/oss.c	Sun Jan 28 15:44:19 2001
@@ -5,9 +5,8 @@
  * any purpose.  This copyright notice must be maintained.
  * Chris Bagwell And Sundry Contributors are not
  * responsible for the consequences of using this software.
- */
-
-/* Direct to Open Sound System (OSS) sound driver
+ *
+ * Direct to Open Sound System (OSS) sound driver
  * OSS is a popular unix sound driver for Intel x86 unices (eg. Linux)
  * and several other unixes (such as SunOS/Solaris).
  * This driver is compatible with OSS original source that was called
@@ -44,12 +43,13 @@
 static int ossdspinit(ft)
 ft_t ft;
 {
-    int samplesize = 8, dsp_stereo;
-    int tmp;
+    int sampletype, samplesize, dsp_stereo;
+    int tmp, rc;

     if (ft->info.rate == 0.0) ft->info.rate = 8000;
     if (ft->info.size == -1) ft->info.size = ST_SIZE_BYTE;
     if (ft->info.size == ST_SIZE_BYTE) {
+	sampletype = AFMT_U8;
 	samplesize = 8;
 	if (ft->info.encoding == -1)
 	    ft->info.encoding = ST_ENCODING_UNSIGNED;
@@ -60,6 +60,7 @@
 	}
     }
     else if (ft->info.size == ST_SIZE_WORD) {
+	sampletype = (ST_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
 	samplesize = 16;
 	if (ft->info.encoding == -1)
 	    ft->info.encoding = ST_ENCODING_SIGN2;
@@ -70,6 +71,8 @@
 	}
     }
     else {
+	sampletype = (ST_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
+	samplesize = 16;
         ft->info.size = ST_SIZE_WORD;
 	ft->info.encoding = ST_ENCODING_SIGN2;
 	st_report("OSS driver only supports bytes and words");
@@ -84,26 +87,61 @@
 	st_fail("Unable to reset OSS driver.  Possibly accessing an invalid file/device");
 	return(ST_EOF);
     }
-    ft->file.size = 0;
-    ioctl (fileno(ft->fp), SNDCTL_DSP_GETBLKSIZE, &ft->file.size);
-    if (ft->file.size < 4 || ft->file.size > 65536) {
-	    st_fail("Invalid audio buffer size %d", ft->file.size);
-	    return (ST_EOF);
-    }
-    ft->file.count = 0;
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-	st_fail("Unable to allocate input/output buffer of size %d", ft->file.size);
-	return (ST_EOF);
-    }

     if (ioctl(fileno(ft->fp), SNDCTL_DSP_SYNC, NULL) < 0) {
 	st_fail("Unable to sync dsp");
 	return (ST_EOF);
     }

+#if defined(SNDCTL_DSP_SETFMT) && defined(SNDCTL_DSP_GETFMTS)
+    /* Query the supported formats and find the best match
+     */
+    rc = ioctl(fileno(ft->fp), SNDCTL_DSP_GETFMTS, &tmp);
+    if (rc == 0) {
+    	if ((tmp & sampletype) == 0)
+	{
+	    /* is 16-bit supported? */
+	    if (samplesize == 16 && (tmp & (AFMT_S16_LE|AFMT_S16_BE)) == 0)
+	    {
+		/* Must not like 16-bits, try 8-bits */
+		ft->info.size = ST_SIZE_BYTE;
+		ft->info.encoding = ST_ENCODING_UNSIGNED;
+		st_report("OSS driver doesn't like signed words");
+		st_report("Forcing to unsigned bytes");
+		tmp = sampletype = AFMT_U8;
+		samplesize = 8;
+	    }
+	    /* is 8-bit supported */
+	    else if (samplesize == 8 && (tmp & AFMT_U8) == 0)
+	    {
+		ft->info.size = ST_SIZE_WORD;
+		ft->info.encoding = ST_ENCODING_SIGN2;
+		st_report("OSS driver doesn't like unsigned bytes");
+		st_report("Forcing to signed words");
+		sampletype = (ST_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
+		samplesize = 16;
+	    }
+	    /* determine which 16-bit format to use */
+	    if (samplesize == 16)
+	    {
+	    	if ((tmp & sampletype) == 0)
+		{
+		    sampletype = (ST_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE;
+		    ft->swap = ft->swap ? 0 : 1;
+		}
+	    }
+	}
+	tmp = sampletype;
+	rc = ioctl(fileno(ft->fp), SNDCTL_DSP_SETFMT, &tmp);
+    }
+    /* Give up and exit */
+    if (rc < 0 || tmp != sampletype)
+    {
+	st_fail("Unable to set the sample size to %d", samplesize);
+	return (ST_EOF);
+    }
+#else
+    /* Odd dumb interface */
     tmp = samplesize;
     if (ioctl(fileno(ft->fp), SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
     {
@@ -115,7 +153,7 @@
     {
 	if (tmp == 16)
 	{
-	    st_warn("Sound card appears to only support singled word samples.  Overriding format");
+	    st_warn("Sound card appears to only support signed word samples.  Overriding format");
 	    ft->info.size = ST_SIZE_WORD;
 	    ft->info.encoding = ST_ENCODING_SIGN2;
 	}
@@ -126,6 +164,7 @@
 	    ft->info.encoding = ST_ENCODING_UNSIGNED;
 	}
     }
+#endif

     if (ft->info.channels == 2) dsp_stereo = 1;
     else dsp_stereo = 0;
@@ -160,6 +199,24 @@
 		     ft->info.rate, tmp);
 	    ft->info.rate = tmp;
 	}
+    }
+
+    /* Find out block size to use last because the driver could compute
+     * its size based on specific rates/formats.
+     */
+    ft->file.size = 0;
+    ioctl (fileno(ft->fp), SNDCTL_DSP_GETBLKSIZE, &ft->file.size);
+    if (ft->file.size < 4 || ft->file.size > 65536) {
+	    st_fail("Invalid audio buffer size %d", ft->file.size);
+	    return (ST_EOF);
+    }
+    ft->file.count = 0;
+    ft->file.pos = 0;
+    ft->file.eof = 0;
+
+    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
+	st_fail("Unable to allocate input/output buffer of size %d", ft->file.size);
+	return (ST_EOF);
     }

     /* Change to non-buffered I/O */