[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