• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/audio/src/util/alutLoader.cpp

Go to the documentation of this file.
00001 #include "alutInternal.h"
00002 #include <ctype.h>
00003 
00004 /****************************************************************************/
00005 
00006 typedef enum
00007 {
00008   LittleEndian,
00009   BigEndian,
00010   UnknwonEndian                 /* has anybody still a PDP11? :-) */
00011 } Endianess;
00012 
00013 /* test from Harbison & Steele, "C - A Reference Manual", section 6.1.2 */
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)      /* "WAVE" */
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)  /* "fmt " */
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:            /* PCM */
00135               codec = (bitsPerSample == 8
00136                        || endianess () ==
00137                        LittleEndian) ? _alutCodecLinear : _alutCodecPCM16;
00138               break;
00139             case 7:            /* uLaw */
00140               bitsPerSample *= 2;       /* ToDo: ??? */
00141               codec = _alutCodecULaw;
00142               break;
00143             default:
00144               _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
00145               return NULL;
00146             }
00147         }
00148       else if (magic == 0x64617461)     /* "data" */
00149         {
00150           ALvoid *data;
00151           if (!found_header)
00152             {
00153               /* ToDo: A bit wrong to check here, fmt chunk could come later... */
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;    /* byte offset to data part, minimum 24 */
00185   Int32BigEndian len;           /* number of bytes in the data part, -1 = not known */
00186   Int32BigEndian encoding;      /* encoding of the data part, see AUEncoding */
00187   Int32BigEndian sampleFrequency;       /* number of samples per second */
00188   Int32BigEndian numChannels;   /* number of interleaved channels */
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   /* Guesses */
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   /* Raw files have no magic number - so use the fileName extension */
00273 
00274   fileName = _alutInputStreamGetFileName (stream);
00275   if (fileName != NULL && hasSuffixIgnoringCase (fileName, L".raw"))
00276     {
00277       return loadRawFile (stream);
00278     }
00279 
00280   /* For other file formats, read the quasi-standard four byte magic number */
00281   if (!_alutInputStreamReadInt32BE (stream, &magic))
00282     {
00283       return AL_FALSE;
00284     }
00285 
00286   /* Magic number 'RIFF' == Microsoft '.wav' format */
00287   if (magic == 0x52494646)
00288     {
00289       return loadWavFile (stream);
00290     }
00291 
00292   /* Magic number '.snd' == Sun & Next's '.au' format */
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   Yukky backwards compatibility crap.
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   /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
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   /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
00474 
00475   /* ToDo: Can we do something less insane than passing 0x7FFFFFFF? */
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   /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
00501 
00502   free (data);
00503 }
00504 
00505 const char *
00506 alutGetMIMETypes (ALenum loader)
00507 {
00508   if (!_alutSanityCheck ())
00509     {
00510       return NULL;
00511     }
00512 
00513   /* We do not distinguish the loaders yet... */
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 }

Generated on Fri Jun 18 2010 17:48:39 for Cannonball by  doxygen 1.7.0