[xiph-cvs] cvs commit: vorbis-tools/oggenc audio.c audio.h oggenc.c

Michael Smith msmith at xiph.org
Mon Jan 15 05:27:33 PST 2001



msmith      01/01/15 05:27:32

  Modified:    oggenc   audio.c audio.h oggenc.c
  Log:
  AIFF/AIFC support! Based on Monty's old ogg application.
  Probably pretty limited, but it seems to work. My only test file was what sox
  output. AIFC is completely untested, actually.
  
  A bugfix or two elsewhere, as well (compiling with -Wall is highly recommended)
  And a new version number (mentioning beta4, so that official beta4 builds will
  actually say that.)

Revision  Changes    Path
1.8       +254 -37   vorbis-tools/oggenc/audio.c

Index: audio.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/oggenc/audio.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- audio.c	2000/12/30 05:04:41	1.7
+++ audio.c	2001/01/15 13:27:32	1.8
@@ -5,8 +5,7 @@
  **
  ** Copyright 2000, Michael Smith <msmith at labyrinth.net.au>
  **
- ** Portions from Vorbize, (c) Kenneth Arnold <kcarnold at yahoo.com>
- ** and libvorbis examples, (c) Monty <monty at xiph.org>
+ ** AIFF/AIFC support from OggSquish, (c) 1994-1996 Monty <xiphmont at xiph.org>
  **/
 
 
@@ -14,21 +13,29 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
+#include <math.h>
 #include "audio.h"
 #include "platform.h"
 
 #define WAV_HEADER_SIZE 44
 
 /* Macros to read header data */
-#define READ_U32(buf) \
+#define READ_U32_LE(buf) \
         (((buf)[3]<<24)|((buf)[2]<<16)|((buf)[1]<<8)|((buf)[0]&0xff));
 
-#define READ_U16(buf) \
+#define READ_U16_LE(buf) \
         (((buf)[1]<<8)|((buf)[0]&0xff));
 
+#define READ_U32_BE(buf) \
+	(((buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|((buf)[3]&0xff));
+
+#define READ_U16_BE(buf) \
+	(((buf)[0]<<8)|((buf)[1]&0xff));
+
 /* Define the supported formats here */
 input_format formats[] = {
         {wav_id, 12, wav_open, wav_close, "wav", "WAV file reader"},
+	{aiff_id, 12, aiff_open, wav_close, "aiff", "AIFF/AIFC file reader"},
         {NULL, 0, NULL, NULL, NULL, NULL}
 };
 
@@ -64,7 +71,7 @@
                 if(formats[j].id_func(buf, size))
                 {
                         /* ok, we now have something that can handle the file */
-			if(formats[j].open_func(in, opt))
+			if(formats[j].open_func(in, opt, buf, size))
                                 return &formats[j];
                 }
                 j++;
@@ -73,8 +80,27 @@
         return NULL;
 }
 
+static int seek_forward(FILE *in, int length)
+{
+	if(fseek(in, length, SEEK_CUR))
+	{
+		/* Failed. Do it the hard way. */
+		unsigned char buf[1024];
+		int seek_needed = length, seeked;
+		while(seek_needed > 0)
+		{
+			seeked = fread(buf, 1, seek_needed>1024?1024:seek_needed, in);
+			if(!seeked)
+				return 0; /* Couldn't read more, can't read file */
+			else
+				seek_needed -= seeked;
+		}
+	}
+	return 1;
+}
 
-static int find_chunk(FILE *in, char *type, unsigned int *len)
+
+static int find_wav_chunk(FILE *in, char *type, unsigned int *len)
 {
         unsigned char buf[8];
 
@@ -88,32 +114,207 @@
 
                 if(memcmp(buf, type, 4))
                 {
-			*len = READ_U32(buf+4);
-			if(fseek(in, *len, SEEK_CUR)) /* Skip the rest of the chunk */
-			{
-				/* seek failed. Do it the hard way */
-				unsigned char buf2[1024];
-				int seek_needed = *len, seeked;
-				while(seek_needed>0)
-				{
-					seeked = fread(buf2,1,seek_needed>1024?1024:seek_needed,in);
-					if(!seeked)
-						return 0; /* Couldn't read more, can't read file */
-					else
-						seek_needed -= seeked;
-				}
-			}
+			*len = READ_U32_LE(buf+4);
+			if(!seek_forward(in, *len))
+				return 0;
+
                         buf[4] = 0;
                         fprintf(stderr, "Skipping chunk of type \"%s\", length %d\n", buf, *len);
                 }
                 else
                 {
-			*len = READ_U32(buf+4);
+			*len = READ_U32_LE(buf+4);
                         return 1;
                 }
         }
 }
 
+static int find_aiff_chunk(FILE *in, char *type, unsigned int *len)
+{
+	unsigned char buf[8];
+
+	while(1)
+	{
+		if(fread(buf,1,8,in) <8)
+		{
+			fprintf(stderr, "Warning: Unexpected EOF in AIFF chunk\n");
+			return 0;
+		}
+
+		*len = READ_U32_BE(buf+4);
+
+		if(memcmp(buf,type,4))
+		{
+			if((*len) & 0x1)
+				(*len)++;
+
+			if(!seek_forward(in, *len))
+				return 0;
+		}
+		else
+			return 1;
+	}
+}
+
+
+
+double read_IEEE80(unsigned char *buf)
+{
+	int s=buf[0]&0xff;
+	int e=((buf[0]&0x7f)<<8)|(buf[1]&0xff);
+	double f=((unsigned long)(buf[2]&0xff)<<24)|
+		((buf[3]&0xff)<<16)|
+		((buf[4]&0xff)<<8) |
+		 (buf[5]&0xff);
+
+	if(e==32767)
+	{
+		if(buf[2]&0x80)
+			return HUGE_VAL; /* Really NaN, but this won't happen in reality */
+		else
+		{
+			if(s)
+				return -HUGE_VAL;
+			else
+				return HUGE_VAL;
+		}
+	}
+
+	f=ldexp(f,32);
+	f+= ((buf[6]&0xff)<<24)|
+		((buf[7]&0xff)<<16)|
+		((buf[8]&0xff)<<8) |
+		 (buf[9]&0xff);
+
+	return ldexp(f, e-16446);
+}
+
+/* AIFF/AIFC support adapted from the old OggSQUISH application */
+int aiff_id(unsigned char *buf, int len)
+{
+	if(len<12) return 0; /* Truncated file, probably */
+
+	if(memcmp(buf, "FORM", 4))
+		return 0;
+
+	if(memcmp(buf+8, "AIF",3))
+		return 0;
+
+	if(buf[11]!='C' && buf[11]!='F')
+		return 0;
+
+	return 1;
+}
+
+int aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen)
+{
+	int aifc; /* AIFC or AIFF? */
+	unsigned int len;
+	unsigned char *buffer;
+	unsigned char buf2[8];
+	aiff_fmt format;
+	aifffile *aiff = malloc(sizeof(aifffile));
+
+	if(buf[11]=='C')
+		aifc=1;
+	else
+		aifc=0;
+
+	if(!find_aiff_chunk(in, "COMM", &len))
+	{
+		fprintf(stderr, "Warning: No common chunk found in AIFF file\n");
+		return 0; /* EOF before COMM chunk */
+	}
+
+	if(len < 18) 
+	{
+		fprintf(stderr, "Warning: Truncated common chunk in AIFF header\n");
+		return 0; /* Weird common chunk */
+	}
+
+	buffer = alloca(len);
+
+	if(fread(buffer,1,len,in) < len)
+	{
+		fprintf(stderr, "Warning: Unexpected EOF in reading AIFF header\n");
+		return 0;
+	}
+
+	format.channels = READ_U16_BE(buffer);
+	format.totalframes = READ_U32_BE(buffer+2);
+	format.samplesize = READ_U16_BE(buffer+6);
+	format.rate = (int)read_IEEE80(buffer+8);
+
+	if(aifc)
+	{
+		if(len < 22)
+		{
+			fprintf(stderr, "Warning: AIFF-C header truncated.\n");
+			return 0;
+		}
+		else if(memcmp(buffer+18, "NONE", 4)) 
+		{
+			fprintf(stderr, "Warning: Can't handle compressed AIFF-C\n");
+			return 0; /* Compressed. Can't handle */
+		}
+	}
+
+	if(!find_aiff_chunk(in, "SSND", &len))
+	{
+		fprintf(stderr, "Warning: No SSND chunk found in AIFF file\n");
+		return 0; /* No SSND chunk -> no actual audio */
+	}
+
+	if(len < 8) 
+	{
+		fprintf(stderr, "Warning: Corrupted SSND chunk in AIFF header\n");
+		return 0; 
+	}
+
+	if(fread(buf2,1,8, in) < 8)
+	{
+		fprintf(stderr, "Warning: Unexpected EOF reading AIFF header\n");
+		return 0;
+	}
+
+	format.offset = READ_U32_BE(buf2);
+	format.blocksize = READ_U32_BE(buf2+4);
+
+	if( format.blocksize == 0 &&
+		format.samplesize == 16)
+	{
+		/* From here on, this is very similar to the wav code. Oh well. */
+		
+		if(format.rate != 44100)
+			fprintf(stderr,"Warning: Vorbis is currently untuned for input\n"
+					       "at other than 44.1kHz, quality may be degraded.\n");
+
+		opt->rate = format.rate;
+		opt->channels = format.channels;
+		opt->read_samples = wav_read; /* Similar enough, so we use the same */
+		opt->total_samples_per_channel = format.totalframes;
+
+		aiff->f = in;
+		aiff->samplesread = 0;
+		aiff->channels = format.channels;
+		aiff->totalsamples = format.totalframes;
+		aiff->bigendian = 1;
+
+		opt->readdata = (void *)aiff;
+
+		seek_forward(in, format.offset); /* Swallow some data */
+		return 1;
+	}
+	else
+	{
+		fprintf(stderr, 
+				"Warning: OggEnc does not support this type of AIFF/AIFC file\n"
+				" Must be 16 bit PCM.\n");
+		return 0;
+	}
+}
+
+
 int wav_id(unsigned char *buf, int len)
 {
         unsigned int flen;
@@ -123,7 +324,7 @@
         if(memcmp(buf, "RIFF", 4))
                 return 0; /* Not wave */
 
-	flen = READ_U32(buf+4); /* We don't use this */
+	flen = READ_U32_LE(buf+4); /* We don't use this */
 
         if(memcmp(buf+8, "WAVE",4))
                 return 0; /* RIFF, but not wave */
@@ -131,7 +332,7 @@
         return 1;
 }
 
-int wav_open(FILE *in, oe_enc_opt *opt)
+int wav_open(FILE *in, oe_enc_opt *opt, unsigned char *oldbuf, int buflen)
 {
         unsigned char buf[16];
         unsigned int len;
@@ -140,9 +341,11 @@
 
         /* Ok. At this point, we know we have a WAV file. Now we have to detect
          * whether we support the subtype, and we have to find the actual data
+	 * We don't (for the wav reader) need to use the buffer we used to id this
+	 * as a wav file (oldbuf)
          */
 
-	if(!find_chunk(in, "fmt ", &len))
+	if(!find_wav_chunk(in, "fmt ", &len))
                 return 0; /* EOF */
 
         if(len!=16) 
@@ -157,14 +360,14 @@
                 return 0;
         }
 
-	format.format =      READ_U16(buf); 
-	format.channels =    READ_U16(buf+2); 
-	format.samplerate =  READ_U32(buf+4);
-	format.bytespersec = READ_U32(buf+8);
-	format.align =       READ_U16(buf+12);
-	format.samplesize =  READ_U16(buf+14);
+	format.format =      READ_U16_LE(buf); 
+	format.channels =    READ_U16_LE(buf+2); 
+	format.samplerate =  READ_U32_LE(buf+4);
+	format.bytespersec = READ_U32_LE(buf+8);
+	format.align =       READ_U16_LE(buf+12);
+	format.samplesize =  READ_U16_LE(buf+14);
 
-	if(!find_chunk(in, "data", &len))
+	if(!find_wav_chunk(in, "data", &len))
                 return 0; /* EOF */
 
         if( format.format == 1 &&
@@ -183,6 +386,7 @@
 
                 wav->f = in;
                 wav->samplesread = 0;
+		wav->bigendian = 0;
                 wav->channels = format.channels; /* This is in several places. The price
                                                                                         of trying to abstract stuff. */
 
@@ -231,13 +435,26 @@
         realsamples = bytes_read/(2*f->channels);
         f->samplesread += realsamples;
                 
-
-	for(i = 0; i < realsamples; i++)
+	if(!f->bigendian)
+	{
+		for(i = 0; i < realsamples; i++)
+		{
+			for(j=0; j < f->channels; j++)
+			{
+				buffer[j][i] = ((buf[i*2*f->channels + 2*j + 1]<<8) |
+						        (buf[i*2*f->channels + 2*j] & 0xff))/32768.0f;
+			}
+		}
+	}
+	else
         {
-		for(j=0; j < f->channels; j++)
+		for(i = 0; i < realsamples; i++)
                 {
-			buffer[j][i] = ((buf[i*2*f->channels + 2*j + 1]<<8) |
-					        (buf[i*2*f->channels + 2*j] & 0xff))/32768.0f;
+			for(j=0; j < f->channels; j++)
+			{
+				buffer[j][i]=((buf[i*2*f->channels + 2*j]<<8) |
+						      (buf[i*2*f->channels + 2*j + 1] & 0xff))/32768.0f;
+			}
                 }
         }
 

1.4       +17 -3     vorbis-tools/oggenc/audio.h

Index: audio.h
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/oggenc/audio.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- audio.h	2000/12/30 05:04:41	1.3
+++ audio.h	2001/01/15 13:27:32	1.4
@@ -9,7 +9,7 @@
 {
         int (*id_func)(unsigned char *buf, int len); /* Returns true if can load file */
         int id_data_len; /* Amount of data needed to id whether this can load the file */
-	int (*open_func)(FILE *in, oe_enc_opt *opt);
+	int (*open_func)(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
         void (*close_func)(void *);
         char *format;
         char *description;
@@ -26,17 +26,31 @@
 } wav_fmt;
 
 typedef struct {
-	int channels;
+	short channels;
         long totalsamples;
         long samplesread;
         FILE *f;
+	short bigendian;
 } wavfile;
 
+typedef struct {
+	short channels;
+	int totalframes;
+	short samplesize;
+	int rate;
+	int offset;
+	int blocksize;
+} aiff_fmt;
+
+typedef wavfile aifffile; /* They're the same */
+
 input_format *open_audio_file(FILE *in, oe_enc_opt *opt);
 
-int wav_open(FILE *in, oe_enc_opt *opt);
 int raw_open(FILE *in, oe_enc_opt *opt);
+int wav_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
+int aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
 int wav_id(unsigned char *buf, int len);
+int aiff_id(unsigned char *buf, int len);
 void wav_close(void *);
 void raw_close(void *);
 

1.10      +2 -2      vorbis-tools/oggenc/oggenc.c

Index: oggenc.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/oggenc/oggenc.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- oggenc.c	2000/12/24 06:34:44	1.9
+++ oggenc.c	2001/01/15 13:27:32	1.10
@@ -20,7 +20,7 @@
 #include "encode.h"
 #include "audio.h"
 
-#define VERSION_STRING "OggEnc v0.5 (libvorbis beta3)\n"
+#define VERSION_STRING "OggEnc v0.6 (libvorbis beta4)\n"
 #define COPYRIGHT "(c) 2000 Michael Smith <msmith at labyrinth.net.au)\n"
 #define CHUNK 4096 /* We do reads, etc. in multiples of this */
 
@@ -404,7 +404,7 @@
                         case 's':
                                 /* Would just use atoi(), but that doesn't deal with unsigned
                                  * ints. Damn */
-				if(sscanf(optarg, "%u", opt->serial) != 1)
+				if(sscanf(optarg, "%u", &opt->serial) != 1)
                                         opt->serial = 0; /* Failed, so just set to zero */
                                 break;
                         case 't':

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list