7 #include "portableio.h"
8 #include "audio_read.h"
11 /************************************************************************
15 * PURPOSE: reads the PCM samples from a file to the buffer
18 * Reads #samples_read# number of shorts from #musicin# filepointer
19 * into #sample_buffer[]#. Returns the number of samples read.
21 ************************************************************************/
24 read_samples (FILE * musicin
, short sample_buffer
[2304],
25 unsigned long num_samples
, unsigned long frame_size
)
27 unsigned long samples_read
;
28 static unsigned long samples_to_read
;
29 static char init
= TRUE
;
32 samples_to_read
= num_samples
;
35 if (samples_to_read
>= frame_size
)
36 samples_read
= frame_size
;
38 samples_read
= samples_to_read
;
41 * fread (sample_buffer, sizeof (short), (int) samples_read,
44 if((samples_read
= toolame_buffer_read((char*)sample_buffer
,
47 fprintf (stderr
, "Hit end of audio data\n");
49 Samples are big-endian. If this is a little-endian machine
52 if (NativeByteOrder
== order_unknown
) {
53 NativeByteOrder
= DetermineByteOrder ();
54 if (NativeByteOrder
== order_unknown
) {
55 fprintf (stderr
, "byte order not determined\n");
59 if (NativeByteOrder
!= order_littleEndian
|| (glopts
.byteswap
== TRUE
))
60 SwapBytesInWords (sample_buffer
, samples_read
);
62 if (num_samples
!= MAX_U_32_NUM
)
63 samples_to_read
-= samples_read
;
65 if (samples_read
< frame_size
&& samples_read
> 0) {
66 /* fill out frame with zeros */
67 for (; samples_read
< frame_size
; sample_buffer
[samples_read
++] = 0);
69 samples_read
= frame_size
;
71 return (samples_read
);
74 /************************************************************************
78 * PURPOSE: reads a frame of audio data from a file to the buffer,
79 * aligns the data for future processing, and separates the
80 * left and right channels
83 ************************************************************************/
85 get_audio (FILE * musicin
, short buffer
[2][1152], unsigned long num_samples
,
86 int nch
, frame_header
*header
)
90 unsigned long samples_read
;
92 if (nch
== 2) { /* stereo */
94 read_samples (musicin
, insamp
, num_samples
, (unsigned long) 2304);
95 if (glopts
.channelswap
== TRUE
) {
96 for (j
= 0; j
< 1152; j
++) {
97 buffer
[1][j
] = insamp
[2 * j
];
98 buffer
[0][j
] = insamp
[2 * j
+ 1];
101 for (j
= 0; j
< 1152; j
++) {
102 buffer
[0][j
] = insamp
[2 * j
];
103 buffer
[1][j
] = insamp
[2 * j
+ 1];
106 } else if (glopts
.downmix
== TRUE
) {
108 read_samples (musicin
, insamp
, num_samples
, (unsigned long) 2304);
109 for (j
= 0; j
< 1152; j
++) {
110 buffer
[0][j
] = 0.5 * (insamp
[2 * j
] + insamp
[2 * j
+ 1]);
114 read_samples (musicin
, insamp
, num_samples
, (unsigned long) 1152);
115 for (j
= 0; j
< 1152; j
++) {
116 buffer
[0][j
] = insamp
[j
];
117 /* buffer[1][j] = 0; don't bother zeroing this buffer. MFC Nov 99 */
120 return (samples_read
);
124 /*****************************************************************************
126 * Routines to determine byte order and swap bytes
128 *****************************************************************************/
130 enum byte_order
DetermineByteOrder (void)
132 char s
[sizeof (long) + 1];
135 char charval
[sizeof (long)];
137 probe
.longval
= 0x41424344L
; /* ABCD in ASCII */
138 strncpy (s
, probe
.charval
, sizeof (long));
139 s
[sizeof (long)] = '\0';
140 /* fprintf( stderr, "byte order is %s\n", s ); */
141 if (strcmp (s
, "ABCD") == 0)
142 return order_bigEndian
;
143 else if (strcmp (s
, "DCBA") == 0)
144 return order_littleEndian
;
146 return order_unknown
;
149 void SwapBytesInWords (short *loc
, int words
)
154 src
= (char *) &thisval
;
155 for (i
= 0; i
< words
; i
++) {
157 dst
= (char *) loc
++;
163 /*****************************************************************************
165 * Read Audio Interchange File Format (AIFF) headers.
167 *****************************************************************************/
169 int aiff_read_headers (FILE * file_ptr
, IFF_AIFF
* aiff_ptr
)
171 int chunkSize
, subSize
, sound_position
;
173 if (fseek (file_ptr
, 0, SEEK_SET
) != 0)
176 if (Read32BitsHighLow (file_ptr
) != IFF_ID_FORM
)
179 chunkSize
= Read32BitsHighLow (file_ptr
);
181 if (Read32BitsHighLow (file_ptr
) != IFF_ID_AIFF
)
185 while (chunkSize
> 0) {
187 switch (Read32BitsHighLow (file_ptr
)) {
190 chunkSize
-= subSize
= Read32BitsHighLow (file_ptr
);
191 aiff_ptr
->numChannels
= Read16BitsHighLow (file_ptr
);
193 aiff_ptr
->numSampleFrames
= Read32BitsHighLow (file_ptr
);
195 aiff_ptr
->sampleSize
= Read16BitsHighLow (file_ptr
);
197 aiff_ptr
->sampleRate
= ReadIeeeExtendedHighLow (file_ptr
);
199 while (subSize
> 0) {
206 chunkSize
-= subSize
= Read32BitsHighLow (file_ptr
);
207 aiff_ptr
->blkAlgn
.offset
= Read32BitsHighLow (file_ptr
);
209 aiff_ptr
->blkAlgn
.blockSize
= Read32BitsHighLow (file_ptr
);
211 sound_position
= ftell (file_ptr
) + aiff_ptr
->blkAlgn
.offset
;
212 if (fseek (file_ptr
, (long) subSize
, SEEK_CUR
) != 0)
214 aiff_ptr
->sampleType
= IFF_ID_SSND
;
218 chunkSize
-= subSize
= Read32BitsHighLow (file_ptr
);
219 while (subSize
> 0) {
226 return sound_position
;
229 /*****************************************************************************
231 * Seek past some Audio Interchange File Format (AIFF) headers to sound data.
233 *****************************************************************************/
235 int aiff_seek_to_sound_data (FILE * file_ptr
)
238 (file_ptr
, AIFF_FORM_HEADER_SIZE
+ AIFF_SSND_HEADER_SIZE
,
244 /************************************************************
246 * Determine the type of sound file. (stdin, wav, aiff, raw pcm)
247 * Determine Sampling Frequency
249 * whether the new sample is stereo or mono.
251 * If file is coming from /dev/stdin assume it is raw PCM. (it's what I use. YMMV)
253 * This is just a hacked together function. The aiff parsing comes from the ISO code.
254 * The WAV code comes from Nick Burch
255 * The ugly /dev/stdin hack comes from me.
257 **************************************************************/
259 parse_input_file (FILE * musicin
, char inPath
[MAX_NAME_SIZE
], frame_header
*header
,
260 unsigned long *num_samples
)
263 IFF_AIFF pcm_aiff_data
;
266 unsigned char wave_header_buffer
[40]; //HH fixed
267 int wave_header_read
= 0;
268 int wave_header_stereo
= -1;
269 int wave_header_16bit
= -1;
270 unsigned long samplerate
;
272 /*************************** STDIN ********************************/
273 /* check if we're reading from stdin. Assume it's a raw PCM file. */
274 /* Of course, you could be piping a WAV file into stdin. Not done in this code */
275 /* this code is probably very dodgy and was written to suit my needs. MFC Dec 99 */
277 * if ((strcmp (inPath, "/dev/stdin") == 0)) {
278 * fprintf (stderr, "Reading from stdin\n");
279 * fprintf (stderr, "Remember to set samplerate with '-s'.\n");
280 * *num_samples = MAX_U_32_NUM;
284 *num_samples
= MAX_U_32_NUM
;
287 /**************************** AIFF ********************************/
288 if ((soundPosition
= aiff_read_headers (musicin
, &pcm_aiff_data
)) != -1) {
289 fprintf (stderr
, ">>> Using Audio IFF sound file headers\n");
290 aiff_check (inPath
, &pcm_aiff_data
, &header
->version
);
291 if (fseek (musicin
, soundPosition
, SEEK_SET
) != 0) {
292 fprintf (stderr
, "Could not seek to PCM sound data in \"%s\".\n",
296 fprintf (stderr
, "Parsing AIFF audio file \n");
297 header
->sampling_frequency
=
298 toolame_SmpFrqIndex ((long) pcm_aiff_data
.sampleRate
, &header
->version
);
299 fprintf (stderr
, ">>> %f Hz sampling frequency selected\n",
300 pcm_aiff_data
.sampleRate
);
302 /* Determine number of samples in sound file */
303 *num_samples
= pcm_aiff_data
.numChannels
* pcm_aiff_data
.numSampleFrames
;
305 if (pcm_aiff_data
.numChannels
== 1) {
306 header
->mode
= MPG_MD_MONO
;
307 header
->mode_ext
= 0;
312 /**************************** WAVE *********************************/
313 /* Nick Burch <The_Leveller@newmail.net> */
314 /*********************************/
315 /* Wave File Headers: (Dec) */
317 /* 22 = Stereo / Mono */
318 /* 01 = mono, 02 = stereo */
319 /* 24 = Sampling Frequency */
321 /* 01 = x1 (8bit Mono) */
322 /* 02 = x2 (8bit Stereo or */
324 /* 04 = x4 (16bit Stereo) */
325 /*********************************/
327 fseek (musicin
, 0, SEEK_SET
);
328 fread (wave_header_buffer
, 1, 40, musicin
);
330 if (wave_header_buffer
[8] == 'W' && wave_header_buffer
[9] == 'A'
331 && wave_header_buffer
[10] == 'V' && wave_header_buffer
[11] == 'E') {
332 fprintf (stderr
, "Parsing Wave File Header\n");
333 if (NativeByteOrder
== order_unknown
) {
334 NativeByteOrder
= DetermineByteOrder ();
335 if (NativeByteOrder
== order_unknown
) {
336 fprintf (stderr
, "byte order not determined\n");
340 if (NativeByteOrder
== order_littleEndian
) {
341 samplerate
= *(unsigned long *) (&wave_header_buffer
[24]);
343 samplerate
= wave_header_buffer
[27] +
344 (wave_header_buffer
[26] << 8) +
345 (wave_header_buffer
[25] << 16) + (wave_header_buffer
[24] << 24);
348 wave_header_read
= 1;
349 switch (samplerate
) {
356 fprintf (stderr
, ">>> %ld Hz sampling freq selected\n", samplerate
);
359 /* Unknown Unsupported Frequency */
360 fprintf (stderr
, ">>> Unknown samp freq %ld Hz in Wave Header\n",
362 fprintf (stderr
, ">>> Default 44.1 kHz samp freq selected\n");
366 if ((header
->sampling_frequency
=
367 toolame_SmpFrqIndex ((long) samplerate
, &header
->version
)) < 0) {
368 fprintf (stderr
, "invalid sample rate\n");
372 if ((long) wave_header_buffer
[22] == 1) {
373 fprintf (stderr
, ">>> Input Wave File is Mono\n");
374 wave_header_stereo
= 0;
375 header
->mode
= MPG_MD_MONO
;
376 header
->mode_ext
= 0;
378 if ((long) wave_header_buffer
[22] == 2) {
379 fprintf (stderr
, ">>> Input Wave File is Stereo\n");
380 wave_header_stereo
= 1;
382 if ((long) wave_header_buffer
[32] == 1) {
383 fprintf (stderr
, ">>> Input Wave File is 8 Bit\n");
384 wave_header_16bit
= 0;
385 fprintf (stderr
, "Input File must be 16 Bit! Please Re-sample");
388 if ((long) wave_header_buffer
[32] == 2) {
389 if (wave_header_stereo
== 1) {
390 fprintf (stderr
, ">>> Input Wave File is 8 Bit\n");
391 wave_header_16bit
= 0;
392 fprintf (stderr
, "Input File must be 16 Bit! Please Re-sample");
395 /* fprintf(stderr, ">>> Input Wave File is 16 Bit\n" ); */
396 wave_header_16bit
= 1;
399 if ((long) wave_header_buffer
[32] == 4) {
400 /* fprintf(stderr, ">>> Input Wave File is 16 Bit\n" ); */
401 wave_header_16bit
= 1;
403 /* should probably use the wave header to determine size here FIXME MFC Feb 2003 */
404 *num_samples
= MAX_U_32_NUM
;
405 if (fseek (musicin
, 44, SEEK_SET
) != 0) { /* there's a way of calculating the size of the
406 wave header. i'll just jump 44 to start with */
407 fprintf (stderr
, "Could not seek to PCM sound data in \"%s\".\n",
414 /*************************** PCM **************************/
415 fprintf (stderr
, "No header found. Assuming Raw PCM sound file\n");
416 /* Raw PCM. No header. Reset the input file to read from the start */
417 fseek (musicin
, 0, SEEK_SET
);
418 /* Assume it is a huge sound file since there's no real info available */
419 /* FIXME: Could always fstat the file? Probably not worth it. MFC Feb 2003 */
420 *num_samples
= MAX_U_32_NUM
;
425 /************************************************************************
429 * PURPOSE: Checks AIFF header information to make sure it is valid.
432 ************************************************************************/
434 void aiff_check (char *file_name
, IFF_AIFF
* pcm_aiff_data
, int *version
)
436 if (pcm_aiff_data
->sampleType
!= IFF_ID_SSND
) {
437 fprintf (stderr
, "Sound data is not PCM in \"%s\".\n", file_name
);
441 if (toolame_SmpFrqIndex ((long) pcm_aiff_data
->sampleRate
, version
) < 0) {
442 fprintf (stderr
, "in \"%s\".\n", file_name
);
446 if (pcm_aiff_data
->sampleSize
!= sizeof (short) * BITS_IN_A_BYTE
) {
447 fprintf (stderr
, "Sound data is not %d bits in \"%s\".\n",
448 sizeof (short) * BITS_IN_A_BYTE
, file_name
);
452 if (pcm_aiff_data
->numChannels
!= MONO
453 && pcm_aiff_data
->numChannels
!= STEREO
) {
454 fprintf (stderr
, "Sound data is not mono or stereo in \"%s\".\n",
459 if (pcm_aiff_data
->blkAlgn
.blockSize
!= 0) {
460 fprintf (stderr
, "Block size is not %d bytes in \"%s\".\n", 0, file_name
);
464 if (pcm_aiff_data
->blkAlgn
.offset
!= 0) {
465 fprintf (stderr
, "Block offset is not %d bytes in \"%s\".\n", 0,