[xiph-commits] r16830 - trunk/ao/src

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Tue Jan 26 22:51:21 PST 2010


Author: xiphmont
Date: 2010-01-26 22:51:21 -0800 (Tue, 26 Jan 2010)
New Revision: 16830

Modified:
   trunk/ao/src/ao_wav.c
Log:
Update wav output driver to WAVEFORMATEXTENSIBLE, add full channel 
mapping support.



Modified: trunk/ao/src/ao_wav.c
===================================================================
--- trunk/ao/src/ao_wav.c	2010-01-27 05:59:19 UTC (rev 16829)
+++ trunk/ao/src/ao_wav.c	2010-01-27 06:51:21 UTC (rev 16830)
@@ -42,7 +42,7 @@
 #define IBM_FORMAT_ADPCM        0x0103
 #define WAVE_FORMAT_EXTENSIBLE  0xfffe
 
-#define WAV_HEADER_MAXLEN 68
+#define WAV_HEADER_LEN 68
 
 #define WRITE_U32(buf, x) *(buf)     = (unsigned char)(x&0xff);\
 						  *((buf)+1) = (unsigned char)((x>>8)&0xff);\
@@ -76,6 +76,7 @@
 	unsigned short wBlockAlign;
 	unsigned short wBitsPerSample;
         unsigned short cbSize;
+	unsigned short wValidBitsPerSample;
         unsigned int   dwChannelMask;
         unsigned short subFormat;
 };
@@ -143,7 +144,51 @@
 	return 1; /* No options! */
 }
 
+static char *map[]={
+  "L","R","C","LFE","BL","BR","CL","CR","BC","SL","SR",NULL
+};
+#define SPEAKER_RESERVED               0x80000000
 
+static unsigned int _matrix_to_channelmask(char *matrix){
+  unsigned int ret=0;
+  char *p=matrix;
+  while(1){
+    char *h=p;
+    int m=0;
+
+    /* search for seperator */
+    while(*h && *h!=',')h++;
+
+    while(map[m]){
+      if(h-p && !strncmp(map[m],p,h-p) &&
+         strlen(map[m])==h-p)
+        break;
+      m++;
+    }
+    if(map[m])
+      ret |= (1<<m);
+    if(!*h)break;
+    p=h+1;
+  }
+  return ret;
+}
+
+static char *_channelmask_to_matrix(unsigned int mask){
+  int m=0;
+  int count=0;
+  char buffer[80]={0};
+  while(map[m]){
+    if(mask & (1<<m)){
+      if(count)
+        strcat(buffer,",");
+      strcat(buffer,map[m]);
+      count++;
+    }
+    m++;
+  }
+  return strdup(buffer);
+}
+
 static int ao_wav_open(ao_device *device, ao_sample_format *format)
 {
 	ao_wav_internal *internal = (ao_wav_internal *) device->internal;
@@ -152,7 +197,8 @@
 
 	/* Store information */
 	internal->wave.common.wChannels = format->channels;
-	internal->wave.common.wBitsPerSample = format->bits;
+	internal->wave.common.wBitsPerSample = ((format->bits+7)>>3)<<3;
+	internal->wave.common.wValidBitsPerSample = format->bits;
 	internal->wave.common.dwSamplesPerSec = format->rate;
 
 	memset(buf, 0, WAV_HEADER_LEN);
@@ -163,9 +209,9 @@
 	strncpy(internal->wave.riff.wave_id, "WAVE",4);
 
 	strncpy(internal->wave.format.id, "fmt ",4);
-	internal->wave.format.len = 16;
+	internal->wave.format.len = 40;
 
-	internal->wave.common.wFormatTag = WAVE_FORMAT_PCM;
+	internal->wave.common.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 	internal->wave.common.dwAvgBytesPerSec =
 		internal->wave.common.wChannels *
 		internal->wave.common.dwSamplesPerSec *
@@ -174,10 +220,25 @@
 	internal->wave.common.wBlockAlign =
 		internal->wave.common.wChannels *
 		(internal->wave.common.wBitsPerSample >> 3);
+	internal->wave.common.cbSize = 22;
+	internal->wave.common.subFormat = WAVE_FORMAT_PCM;
 
+        /* contruct channel mask; WAV is capable of expressing any
+           channel format currently representable in libao */
+        if(format->matrix){
+          if(device->output_matrix){
+            internal->wave.common.dwChannelMask=_matrix_to_channelmask(device->output_matrix);
+          }else{
+            internal->wave.common.dwChannelMask=_matrix_to_channelmask(format->matrix);
+            device->output_matrix = _channelmask_to_matrix(internal->wave.common.dwChannelMask);
+          }
+        }else{
+          internal->wave.common.dwChannelMask=0;
+        }
+
 	strncpy(internal->wave.data.id, "data",4);
 
-	internal->wave.data.len = size - 44;
+	internal->wave.data.len = size - WAV_HEADER_LEN;
 
 	strncpy(buf, internal->wave.riff.id, 4);
 	WRITE_U32(buf+4, internal->wave.riff.len);
@@ -190,8 +251,13 @@
 	WRITE_U32(buf+28, internal->wave.common.dwAvgBytesPerSec);
 	WRITE_U16(buf+32, internal->wave.common.wBlockAlign);
 	WRITE_U16(buf+34, internal->wave.common.wBitsPerSample);
-	strncpy(buf+36, internal->wave.data.id, 4);
-	WRITE_U32(buf+40, internal->wave.data.len);
+	WRITE_U16(buf+36, internal->wave.common.cbSize);
+	WRITE_U16(buf+38, internal->wave.common.wValidBitsPerSample);
+	WRITE_U32(buf+40, internal->wave.common.dwChannelMask);
+	WRITE_U16(buf+44, internal->wave.common.subFormat);
+        memcpy(buf+46,"\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71",14);
+	strncpy(buf+60, internal->wave.data.id, 4);
+	WRITE_U32(buf+64, internal->wave.data.len);
 
 	if (fwrite(buf, sizeof(char), WAV_HEADER_LEN, device->file)
 	    != WAV_HEADER_LEN) {
@@ -235,7 +301,7 @@
 	/* Go back and set correct length info */
 
 	internal->wave.riff.len = size - 8;
-	internal->wave.data.len = size - 44;
+	internal->wave.data.len = size - WAV_HEADER_LEN;
 
 	/* Rewind to riff len and write it */
 	if (fseek(device->file, 4, SEEK_SET) < 0)
@@ -247,7 +313,7 @@
 
 
 	/* Rewind to data len and write it */
-	if (fseek(device->file, 40, SEEK_SET) < 0)
+	if (fseek(device->file, 64, SEEK_SET) < 0)
 		return 0; /* Wav header corrupt */
 
 	WRITE_U32(buf, internal->wave.data.len);



More information about the commits mailing list