00001 #include "alutInternal.h"
00002 #include <ctype.h>
00003
00004
00005
00006 typedef enum
00007 {
00008 LittleEndian,
00009 BigEndian,
00010 UnknwonEndian
00011 } Endianess;
00012
00013
00014 static Endianess
00015 endianess (void)
00016 {
00017 union
00018 {
00019 long l;
00020 char c[sizeof (long)];
00021 } u;
00022
00023 u.l = 1;
00024 return (u.c[0] == 1) ? LittleEndian :
00025 ((u.c[sizeof (long) - 1] == 1) ? BigEndian : UnknwonEndian);
00026 }
00027
00028
00029
00030 static int
00031 safeToLower (int c)
00032 {
00033 return isupper (c) ? tolower (c) : c;
00034 }
00035
00036 static int
00037 hasSuffixIgnoringCase (const wchar_t *string, const wchar_t *suffix)
00038 {
00039 const wchar_t *stringPointer = string;
00040 const wchar_t *suffixPointer = suffix;
00041
00042 if (suffix[0] == '\0')
00043 {
00044 return 1;
00045 }
00046
00047 while (*stringPointer != '\0')
00048 {
00049 stringPointer++;
00050 }
00051
00052 while (*suffixPointer != '\0')
00053 {
00054 suffixPointer++;
00055 }
00056
00057 if (stringPointer - string < suffixPointer - suffix)
00058 {
00059 return 0;
00060 }
00061
00062 while (safeToLower (*--suffixPointer) == safeToLower (*--stringPointer))
00063 {
00064 if (suffixPointer == suffix)
00065 {
00066 return 1;
00067 }
00068 }
00069
00070 return 0;
00071 }
00072
00073 static BufferData *
00074 loadWavFile (InputStream *stream)
00075 {
00076 ALboolean found_header = AL_FALSE;
00077 UInt32LittleEndian chunkLength;
00078 Int32BigEndian magic;
00079 UInt16LittleEndian audioFormat;
00080 UInt16LittleEndian numChannels;
00081 UInt32LittleEndian sampleFrequency;
00082 UInt32LittleEndian byteRate;
00083 UInt16LittleEndian blockAlign;
00084 UInt16LittleEndian bitsPerSample;
00085 Codec *codec = _alutCodecLinear;
00086
00087 if (!_alutInputStreamReadUInt32LE (stream, &chunkLength) ||
00088 !_alutInputStreamReadInt32BE (stream, &magic))
00089 {
00090 return NULL;
00091 }
00092
00093 if (magic != 0x57415645)
00094 {
00095 _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
00096 return NULL;
00097 }
00098
00099 while (1)
00100 {
00101 if (!_alutInputStreamReadInt32BE (stream, &magic) ||
00102 !_alutInputStreamReadUInt32LE (stream, &chunkLength))
00103 {
00104 return NULL;
00105 }
00106
00107 if (magic == 0x666d7420)
00108 {
00109 found_header = AL_TRUE;
00110
00111 if (chunkLength < 16)
00112 {
00113 _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
00114 return NULL;
00115 }
00116
00117 if (!_alutInputStreamReadUInt16LE (stream, &audioFormat) ||
00118 !_alutInputStreamReadUInt16LE (stream, &numChannels) ||
00119 !_alutInputStreamReadUInt32LE (stream, &sampleFrequency) ||
00120 !_alutInputStreamReadUInt32LE (stream, &byteRate) ||
00121 !_alutInputStreamReadUInt16LE (stream, &blockAlign) ||
00122 !_alutInputStreamReadUInt16LE (stream, &bitsPerSample))
00123 {
00124 return NULL;
00125 }
00126
00127 if (!_alutInputStreamSkip (stream, chunkLength - 16))
00128 {
00129 return NULL;
00130 }
00131
00132 switch (audioFormat)
00133 {
00134 case 1:
00135 codec = (bitsPerSample == 8
00136 || endianess () ==
00137 LittleEndian) ? _alutCodecLinear : _alutCodecPCM16;
00138 break;
00139 case 7:
00140 bitsPerSample *= 2;
00141 codec = _alutCodecULaw;
00142 break;
00143 default:
00144 _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
00145 return NULL;
00146 }
00147 }
00148 else if (magic == 0x64617461)
00149 {
00150 ALvoid *data;
00151 if (!found_header)
00152 {
00153
00154 _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
00155 return NULL;
00156 }
00157 data = _alutInputStreamRead (stream, chunkLength);
00158 if (data == NULL)
00159 {
00160 return NULL;
00161 }
00162 return (BufferData*)codec (data, chunkLength, numChannels, bitsPerSample,
00163 (ALfloat) sampleFrequency);
00164 }
00165 else
00166 {
00167 if (!_alutInputStreamSkip (stream, chunkLength))
00168 {
00169 return NULL;
00170 }
00171 }
00172
00173 if ((chunkLength & 1) && !_alutInputStreamEOF (stream)
00174 && !_alutInputStreamSkip (stream, 1))
00175 {
00176 return NULL;
00177 }
00178 }
00179 }
00180
00181 static BufferData *
00182 loadAUFile (InputStream *stream)
00183 {
00184 Int32BigEndian dataOffset;
00185 Int32BigEndian len;
00186 Int32BigEndian encoding;
00187 Int32BigEndian sampleFrequency;
00188 Int32BigEndian numChannels;
00189 size_t length;
00190 Codec *codec;
00191 char *data;
00192 ALint bitsPerSample;
00193
00194 if (!_alutInputStreamReadInt32BE (stream, &dataOffset) ||
00195 !_alutInputStreamReadInt32BE (stream, &len) ||
00196 !_alutInputStreamReadInt32BE (stream, &encoding) ||
00197 !_alutInputStreamReadInt32BE (stream, &sampleFrequency) ||
00198 !_alutInputStreamReadInt32BE (stream, &numChannels))
00199 {
00200 return AL_FALSE;
00201 }
00202
00203 length = (len == -1) ?
00204 (_alutInputStreamGetRemainingLength (stream) - AU_HEADER_SIZE -
00205 dataOffset) : (size_t) len;
00206
00207 if (!
00208 (dataOffset >= AU_HEADER_SIZE && length > 0 && sampleFrequency >= 1
00209 && numChannels >= 1))
00210 {
00211 _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
00212 return AL_FALSE;
00213 }
00214
00215 if (!_alutInputStreamSkip (stream, dataOffset - AU_HEADER_SIZE))
00216 {
00217 return AL_FALSE;
00218 }
00219
00220 switch (encoding)
00221 {
00222 case AU_ULAW_8:
00223 bitsPerSample = 16;
00224 codec = _alutCodecULaw;
00225 break;
00226 case AU_PCM_8:
00227 bitsPerSample = 8;
00228 codec = _alutCodecPCM8s;
00229 break;
00230 case AU_PCM_16:
00231 bitsPerSample = 16;
00232 codec =
00233 (endianess () == BigEndian) ? _alutCodecLinear : _alutCodecPCM16;
00234 break;
00235 case AU_ALAW_8:
00236 bitsPerSample = 16;
00237 codec = _alutCodecALaw;
00238 break;
00239 default:
00240 _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
00241 return AL_FALSE;
00242 }
00243
00244 data = (char*)_alutInputStreamRead (stream, length);
00245 if (data == NULL)
00246 {
00247 return NULL;
00248 }
00249 return (BufferData*)codec (data, length, numChannels, bitsPerSample,
00250 (ALfloat) sampleFrequency);
00251 }
00252
00253 static BufferData *
00254 loadRawFile (InputStream *stream)
00255 {
00256 size_t length = _alutInputStreamGetRemainingLength (stream);
00257 ALvoid *data = _alutInputStreamRead (stream, length);
00258 if (data == NULL)
00259 {
00260 return NULL;
00261 }
00262
00263 return (BufferData*)_alutCodecLinear (data, length, 1, 8, 8000);
00264 }
00265
00266 static BufferData *
00267 loadFile (InputStream *stream)
00268 {
00269 const wchar_t *fileName;
00270 Int32BigEndian magic;
00271
00272
00273
00274 fileName = _alutInputStreamGetFileName (stream);
00275 if (fileName != NULL && hasSuffixIgnoringCase (fileName, L".raw"))
00276 {
00277 return loadRawFile (stream);
00278 }
00279
00280
00281 if (!_alutInputStreamReadInt32BE (stream, &magic))
00282 {
00283 return AL_FALSE;
00284 }
00285
00286
00287 if (magic == 0x52494646)
00288 {
00289 return loadWavFile (stream);
00290 }
00291
00292
00293 if (magic == 0x2E736E64)
00294 {
00295 return loadAUFile (stream);
00296 }
00297
00298 _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_TYPE);
00299 return AL_FALSE;
00300 }
00301
00302 ALuint
00303 _alutCreateBufferFromInputStream (InputStream *stream)
00304 {
00305 BufferData *bufferData;
00306 ALuint buffer;
00307
00308 if (stream == NULL)
00309 {
00310 return AL_NONE;
00311 }
00312
00313 bufferData = loadFile (stream);
00314 _alutInputStreamDestroy (stream);
00315 if (bufferData == NULL)
00316 {
00317 return AL_NONE;
00318 }
00319
00320 buffer = _alutPassBufferData (bufferData);
00321 _alutBufferDataDestroy (bufferData);
00322
00323 return buffer;
00324 }
00325
00326 ALuint
00327 alutCreateBufferFromFile (const rchar *fileName)
00328 {
00329 InputStream *stream;
00330 if (!_alutSanityCheck ())
00331 {
00332 return AL_NONE;
00333 }
00334 stream = _alutInputStreamConstructFromFile (fileName);
00335 return _alutCreateBufferFromInputStream (stream);
00336 }
00337
00338 ALuint
00339 alutCreateBufferFromFileImage (const ALvoid *data, ALsizei length)
00340 {
00341 InputStream *stream;
00342 if (!_alutSanityCheck ())
00343 {
00344 return AL_NONE;
00345 }
00346 stream = _alutInputStreamConstructFromMemory (data, length);
00347 return _alutCreateBufferFromInputStream (stream);
00348 }
00349
00350 void *
00351 _alutLoadMemoryFromInputStream (InputStream *stream, ALenum *format,
00352 ALsizei *size, ALfloat *frequency)
00353 {
00354 BufferData *bufferData;
00355 ALenum fmt;
00356 void *data;
00357
00358 if (stream == NULL)
00359 {
00360 return NULL;
00361 }
00362
00363 bufferData = loadFile (stream);
00364 if (bufferData == NULL)
00365 {
00366 _alutInputStreamDestroy (stream);
00367 return NULL;
00368 }
00369 _alutInputStreamDestroy (stream);
00370
00371 if (!_alutGetFormat (bufferData, &fmt))
00372 {
00373 _alutBufferDataDestroy (bufferData);
00374 return NULL;
00375 }
00376
00377 if (size != NULL)
00378 {
00379 *size = (ALsizei) _alutBufferDataGetLength (bufferData);
00380 }
00381
00382 if (format != NULL)
00383 {
00384 *format = fmt;
00385 }
00386
00387 if (frequency != NULL)
00388 {
00389 *frequency = _alutBufferDataGetSampleFrequency (bufferData);
00390 }
00391
00392 data = _alutBufferDataGetData (bufferData);
00393 _alutBufferDataDetachData (bufferData);
00394 _alutBufferDataDestroy (bufferData);
00395 return data;
00396 }
00397
00398 ALvoid *
00399 alutLoadMemoryFromFile (const rchar *fileName, ALenum *format,
00400 ALsizei *size, ALfloat *frequency)
00401 {
00402 InputStream *stream;
00403 if (!_alutSanityCheck ())
00404 {
00405 return NULL;
00406 }
00407 stream = _alutInputStreamConstructFromFile (fileName);
00408 return _alutLoadMemoryFromInputStream (stream, format, size, frequency);
00409 }
00410
00411 ALvoid *
00412 alutLoadMemoryFromFileImage (const ALvoid *data, ALsizei length,
00413 ALenum *format, ALsizei *size,
00414 ALfloat *frequency)
00415 {
00416 InputStream *stream;
00417 if (!_alutSanityCheck ())
00418 {
00419 return NULL;
00420 }
00421 stream = _alutInputStreamConstructFromMemory (data, length);
00422 return _alutLoadMemoryFromInputStream (stream, format, size, frequency);
00423 }
00424
00425
00426
00427
00428
00429 void
00430 alutLoadWAVFile (const rchar *fileName, ALenum *format, void **data, ALsizei *size,
00431 ALsizei *frequency
00432 #if !defined(__APPLE__)
00433 , ALboolean *loop
00434 #endif
00435 )
00436 {
00437 InputStream *stream;
00438 ALfloat freq;
00439
00440
00441
00442 stream = _alutInputStreamConstructFromFile (fileName);
00443 *data = _alutLoadMemoryFromInputStream (stream, format, size, &freq);
00444 if (*data == NULL)
00445 {
00446 return;
00447 }
00448
00449 if (frequency)
00450 {
00451 *frequency = (ALsizei) freq;
00452 }
00453
00454 #if !defined(__APPLE__)
00455 if (loop)
00456 {
00457 *loop = AL_FALSE;
00458 }
00459 #endif
00460 }
00461
00462 void
00463 alutLoadWAVMemory (ALbyte *buffer, ALenum *format, void **data, ALsizei *size,
00464 ALsizei *frequency
00465 #if !defined(__APPLE__)
00466 , ALboolean *loop
00467 #endif
00468 )
00469 {
00470 InputStream *stream;
00471 ALfloat freq;
00472
00473
00474
00475
00476 stream = _alutInputStreamConstructFromMemory (buffer, 0x7FFFFFFF);
00477 _alutLoadMemoryFromInputStream (stream, format, size, &freq);
00478 if (*data == NULL)
00479 {
00480 return;
00481 }
00482
00483 if (frequency)
00484 {
00485 *frequency = (ALsizei) freq;
00486 }
00487
00488 #if !defined(__APPLE__)
00489 if (loop)
00490 {
00491 *loop = AL_FALSE;
00492 }
00493 #endif
00494 }
00495
00496 void
00497 alutUnloadWAV (ALenum UNUSED (format), ALvoid *data, ALsizei UNUSED (size),
00498 ALsizei UNUSED (frequency))
00499 {
00500
00501
00502 free (data);
00503 }
00504
00505 const char *
00506 alutGetMIMETypes (ALenum loader)
00507 {
00508 if (!_alutSanityCheck ())
00509 {
00510 return NULL;
00511 }
00512
00513
00514 switch (loader)
00515 {
00516 case ALUT_LOADER_BUFFER:
00517 return "audio/basic,audio/x-raw,audio/x-wav";
00518
00519 case ALUT_LOADER_MEMORY:
00520 return "audio/basic,audio/x-raw,audio/x-wav";
00521
00522 default:
00523 _alutSetError (ALUT_ERROR_INVALID_ENUM);
00524 return NULL;
00525 }
00526 }