Home | History | Annotate | Download | only in src
      1 /*---------------------------------------------------------------------------*
      2  *  riff.c  *
      3  *                                                                           *
      4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
      5  *                                                                           *
      6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
      7  *  you may not use this file except in compliance with the License.         *
      8  *                                                                           *
      9  *  You may obtain a copy of the License at                                  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
     11  *                                                                           *
     12  *  Unless required by applicable law or agreed to in writing, software      *
     13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
     15  *  See the License for the specific language governing permissions and      *
     16  *  limitations under the License.                                           *
     17  *                                                                           *
     18  *---------------------------------------------------------------------------*/
     19 
     20 #include "plog.h"
     21 #include "riff.h"
     22 
     23 #define MTAG NULL
     24 
     25 typedef struct ChunkContext_t
     26 {
     27   char tag[4];
     28   long  start;
     29   int  length;
     30 }
     31 ChunkContext;
     32 
     33 typedef enum
     34 {
     35   FIND_RIFF,
     36   FIND_CHUNK,
     37   FIND_LIST
     38 } DescendType;
     39 
     40 int isLittleEndian()
     41 {
     42   char b[4];
     43 
     44   *(int *)b = 1;
     45   return (int)b[0];
     46 }
     47 
     48 /* waveReadFunc
     49  * - converts data to an array of signed shorts
     50  * - fills in *length with the number of samples converted
     51  * - allocates memory for *samples
     52  * - returns GS_OK if conversion was successful or GS_ERROR and an error
     53  *    message in res if not.  If the conversion fails the function must free
     54  *    all the memory it had allocated before returning.
     55  * On entry
     56  *  wf   - points to the WaveFormat structure that describes the data format
     57  *  cb   - data read from the RIFF file
     58  *  data - descriptor for the "data" chunk
     59  */
     60 typedef ESR_ReturnCode(waveReadFunc)(WaveFormat *wf, ChunkContext *data,
     61                                      char *cb, short **samples, int *length, int doSwap);
     62 
     63 static ESR_ReturnCode readPCMWave(WaveFormat *wf, ChunkContext *data,
     64                                   char *cb, short **samples, int *length, int doSwap);
     65 static ESR_ReturnCode readMulawWave(WaveFormat *wf, ChunkContext *data,
     66                                     char *cb, short **samples, int *length, int doSwap);
     67 static ESR_ReturnCode readAlawWave(WaveFormat *wf, ChunkContext *data,
     68                                    char *cb, short **samples, int *length, int doSwap);
     69 
     70 static struct
     71 {
     72   int id;
     73   waveReadFunc *func;
     74 }
     75 WaveCodecs[] = {
     76                  {WAVEFORMAT_PCM, readPCMWave},
     77                  {WAVEFORMAT_MULAW, readMulawWave},
     78                  {WAVEFORMAT_ALAW, readAlawWave},
     79                  {0, 0},
     80                };
     81 
     82 /************* FIXME: regroup all swap routines outahere;
     83  *                    ditto for audio conversion routines
     84  */
     85 
     86 static void swapInt(int *i)
     87 {
     88   char *a = (char *)i, t;
     89   t = a[0];
     90   a[0] = a[3];
     91   a[3] = t;
     92   t = a[1];
     93   a[1] = a[2];
     94   a[2] = t;
     95 }
     96 
     97 static void swapShort(short *s)
     98 {
     99   char *a = (char *)s, t;
    100   t = a[0];
    101   a[0] = a[1];
    102   a[1] = t;
    103 }
    104 
    105 static int swapConstInt(const int value)
    106 {
    107   int converted = value;
    108   unsigned char *cp = (unsigned char *) & converted;
    109 
    110   *cp ^= *(cp + 3);
    111   *(cp + 3) ^= *cp;
    112   *cp ^= *(cp + 3);
    113   *(cp + 1) ^= *(cp + 2);
    114   *(cp + 2) ^= *(cp + 1);
    115   *(cp + 1) ^= *(cp + 2);
    116 
    117   return converted;
    118 }
    119 
    120 static short swapConstShort(const short value)
    121 {
    122   short converted = value;
    123   unsigned char *cp = (unsigned char *) & converted;
    124   unsigned char tmp = *cp;
    125 
    126   *cp = *(cp + 1);
    127   *++cp = tmp;
    128 
    129   return converted;
    130 }
    131 
    132 /* len == number of bytes to swap
    133  */
    134 static void short_byte_swap(short *buf, int len)
    135 {
    136   char *cp, *end, tmp;
    137 
    138   end = ((char *)buf) + (len << 1);
    139   for (cp = (char *)buf; cp < end; cp++)
    140   {
    141     tmp = *cp;
    142     *cp = *(cp + 1);
    143     *++cp = tmp;
    144   }
    145 }
    146 
    147 /* len == number of bytes to swap
    148  */
    149 static void int_byte_swap(int *buf, int len)
    150 {
    151   char *cp, *end;
    152 
    153   end = ((char *)buf) + (len << 2);
    154   for (cp = (char *)buf; cp < end; cp += 4)
    155   {
    156     *cp ^= *(cp + 3);
    157     *(cp + 3) ^= *cp;
    158     *cp ^= *(cp + 3);
    159     *(cp + 1) ^= *(cp + 2);
    160     *(cp + 2) ^= *(cp + 1);
    161     *(cp + 1) ^= *(cp + 2);
    162   }
    163 }
    164 
    165 static void swapWaveFormat(WaveFormat *wf)
    166 {
    167   swapShort(&wf->nFormatTag);
    168   swapShort(&wf->nChannels);
    169   swapInt(&wf->nSamplesPerSec);
    170   swapInt(&wf->nAvgBytesPerSec);
    171   swapShort(&wf->nBlockAlign);
    172   swapShort(&wf->wBitsPerSample);
    173   //swapShort(&wf->cbSize);
    174 }
    175 
    176 static int ulaw2linear(unsigned char ulawbyte)
    177 {
    178   static int exp_lut[8] =
    179     {
    180       0, 132, 396, 924, 1980, 4092, 8316, 16764
    181     };
    182   int sign, exponent, mantissa, sample;
    183 
    184   ulawbyte = ~ulawbyte;
    185   sign = (ulawbyte & 0x80);
    186   exponent = (ulawbyte >> 4) & 0x07;
    187   mantissa = ulawbyte & 0x0F;
    188   sample = exp_lut[exponent] + (mantissa << (exponent + 3));
    189   if (sign != 0) sample = -sample;
    190   return sample;
    191 }
    192 
    193 static int alaw2linear(unsigned char alawbyte)
    194 {
    195 
    196   int sign, achord, astep, delta, sample;
    197   unsigned char alawcode;
    198   static int exp_lut[8] =
    199     {
    200       1, 1, 2, 4, 8, 16, 32, 64
    201     };
    202   alawcode = alawbyte ^ 0x55;
    203   sign = (alawcode & 0x80);
    204   achord = (alawcode >> 4) & 0x07;
    205   astep = alawcode & 0x0F;
    206   delta = ((achord == 0) ? 1 : 0);
    207   sample = ((2 * astep + 33) * exp_lut[achord]) - 32 * delta;
    208   if (sign != 0) sample = -sample;
    209   sample = sample * 8;
    210 
    211   return sample;
    212 }
    213 
    214 /* Converts PCM wave data
    215  *  cb: input :1
    216 
    217  */
    218 static ESR_ReturnCode readPCMWave(WaveFormat *wf, ChunkContext *data,
    219                                   char *cb, short **samples, int *length, int doSwap)
    220 {
    221   int i;
    222   if (wf->nChannels != 1)
    223   {
    224     //GS_SetResult(res,"PCM WAVE file contains more than one data channel",
    225     //GS_STATIC);
    226     return ESR_FATAL_ERROR;
    227   }
    228   if (wf->wBitsPerSample != 16 && wf->wBitsPerSample != 8)
    229   {
    230     //GS_SetResult(res,GS_Spf(0,"%d bits per sample PCM format not supported",
    231     //wf->wBitsPerSample),GS_VOLATILE);
    232     return ESR_FATAL_ERROR;
    233   }
    234   *length = data->length * 8 / wf->wBitsPerSample;
    235   *samples = MALLOC(*length * sizeof(short), MTAG);
    236   if (wf->wBitsPerSample == 16)
    237   {
    238     memcpy(*samples, cb, *length*sizeof(short));
    239     if (doSwap)
    240       for (i = 0;i < *length;i++) swapShort(*samples + i);
    241   }
    242   else
    243   {
    244     for (i = 0;i < *length;i++)(*samples)[i] = (short)((unsigned)(cb[i]) - 128) << 8;
    245   }
    246   return ESR_SUCCESS;
    247 }
    248 
    249 /* Converts CCITT u-law wave data
    250  */
    251 static ESR_ReturnCode readMulawWave(WaveFormat *wf, ChunkContext *data,
    252                                     char *cb, short **samples, int *length, int doSwap)
    253 {
    254   int i;
    255   if (wf->nChannels != 1)
    256   {
    257     //GS_SetResult(res,"u-law WAVE file contains more than one data channel",
    258     //GS_STATIC);
    259     return ESR_FATAL_ERROR;
    260   }
    261   if (wf->wBitsPerSample != 8)
    262   {
    263     //GS_SetResult(res,GS_Spf(0,"%d bits per sample u-law format not supported",
    264     //wf->wBitsPerSample),GS_VOLATILE);
    265     return ESR_FATAL_ERROR;
    266   }
    267   *length = data->length;
    268   *samples = MALLOC(*length * sizeof(short), MTAG);
    269   for (i = 0;i < *length;i++)
    270     (*samples)[i] = (short) ulaw2linear(cb[i]);
    271   return ESR_SUCCESS;
    272 }
    273 
    274 /* Converts a-law wave data
    275  */
    276 static ESR_ReturnCode readAlawWave(WaveFormat *wf, ChunkContext *data,
    277                                    char *cb, short **samples, int *length, int doSwap)
    278 {
    279   int i;
    280   if (wf->nChannels != 1)
    281   {
    282     //GS_SetResult(res,"u-law WAVE file contains more than one data channel",
    283     //GS_STATIC);
    284     return ESR_FATAL_ERROR;
    285   }
    286   if (wf->wBitsPerSample != 8)
    287   {
    288     //GS_SetResult(res,GS_Spf(0,"%d bits per sample u-law format not supported",
    289     //wf->wBitsPerSample),GS_VOLATILE);
    290     return ESR_FATAL_ERROR;
    291   }
    292   *length = data->length;
    293   samples = MALLOC(*length * sizeof(short), MTAG);
    294   for (i = 0;i < *length;i++)(*samples)[i] = alaw2linear(cb[i]);
    295   return ESR_SUCCESS;
    296 }
    297 
    298 /* ------------------------------------------------------------------------- */
    299 
    300 /* RIFF INTERFACE UTILS  */
    301 
    302 void free_swiRiff(SwiRiffStruct *swichunk)
    303 {
    304   if (swichunk->segs.num_tuples)
    305   {
    306     FREE(swichunk->segs.tuples);
    307     swichunk->segs.num_tuples = 0;
    308   }
    309   if (swichunk->kvals.num_pairs)
    310   {
    311     FREE(swichunk->kvals.kvpairs[0].key);
    312     FREE(swichunk->kvals.kvpairs);
    313     swichunk->kvals.num_pairs = 0;
    314   }
    315 }
    316 
    317 char *getSwiRiffKVal(SwiRiffStruct *swichunk, char *key)
    318 {
    319   int i;
    320 
    321   for (i = 0; i < swichunk->kvals.num_pairs; i++)
    322     if (! strcmp(swichunk->kvals.kvpairs[i].key, key))
    323       return swichunk->kvals.kvpairs[i].value;
    324 
    325   return NULL;
    326 }
    327 
    328 /* ------------------------------------------------------------------------- */
    329 
    330 static int riffDescend(FILE *f, ChunkContext *c, ChunkContext *parent, DescendType t, int doSwap)
    331 {
    332   char form[4], tag[4];
    333   int len;
    334   long start, end;
    335 
    336   end = 0;
    337   if (!parent) start = 0;
    338   else
    339   {
    340     start = parent->start;
    341     end = start + parent->length;
    342   }
    343   if (fseek(f, start, SEEK_SET) < 0)
    344   {
    345     //GS_SetResult(res,"seek failed",GS_STATIC);
    346     return ESR_FATAL_ERROR;
    347   }
    348 
    349   switch (t)
    350   {
    351 
    352     case FIND_RIFF:
    353       while (1)
    354       {
    355         if (fread(form, 1, 4, f) != 4) break;
    356         if (fread(&len, sizeof(int), 1, f) != 1)
    357           return ESR_FATAL_ERROR;
    358         if (doSwap)
    359           swapInt(&len);
    360         if (strncmp(form, "RIFF", 4))
    361         {  /* skip this non-RIFF chunk */
    362           if (fseek(f, (long)len, SEEK_CUR) < 0) break;
    363           start += len + 8;
    364           if (end && start >= end)
    365           {
    366             //GS_SetResult(res,"RIFF form type not found",GS_STATIC);
    367             return ESR_FATAL_ERROR;
    368           }
    369           continue;
    370         }
    371         if (fread(tag, 1, 4, f) != 4) break;
    372         if (!strncmp(tag, c->tag, 4))
    373         {
    374           c->start = start + 12;
    375           c->length = len - 4;
    376           return ESR_SUCCESS;
    377         }
    378       }
    379       //if(feof(f)) GS_SetResult(res,"RIFF form type not found",GS_STATIC);
    380       //else GS_SetResult(res,"Corrupt RIFF file",GS_STATIC);
    381       return ESR_FATAL_ERROR;
    382 
    383     case FIND_CHUNK:
    384       while (1)
    385       {
    386         if (fread(tag, 1, 4, f) != 4) break;
    387         if (fread(&len, sizeof(int), 1, f) != 1)
    388           return ESR_FATAL_ERROR;
    389         if (doSwap)
    390           swapInt(&len);
    391         if (!strncmp(tag, c->tag, 4))
    392         {
    393           c->start = start + 8;
    394           c->length = len;
    395           return ESR_SUCCESS;
    396         }
    397         if (fseek(f, (long)len, SEEK_CUR) < 0) break;
    398         start += len + 8;
    399         if (end && start >= end)
    400         {
    401           //GS_SetResult(res,"RIFF chunk not found",GS_STATIC);
    402           return ESR_FATAL_ERROR;
    403         }
    404       }
    405       //if(feof(f)) GS_SetResult(res,"RIFF chunk not found",GS_STATIC);
    406       //else GS_SetResult(res,"corrupt RIFF file",GS_STATIC);
    407       return ESR_FATAL_ERROR;
    408 
    409     case FIND_LIST:
    410       while (1)
    411       {
    412         if (fread(form, 1, 4, f) != 4) break;
    413         if (fread(&len, sizeof(int), 1, f) != 1)
    414           return ESR_FATAL_ERROR;
    415         if (doSwap)
    416           swapInt(&len);
    417         if (strncmp(form, "LIST", 4))
    418         {  /* skip this non-LIST chunk */
    419           if (fseek(f, (long)len, SEEK_CUR) < 0) break;
    420           start += len + 8;
    421           if (end && start >= end)
    422           {
    423             //GS_SetResult(res,"RIFF form type not found",GS_STATIC);
    424             return ESR_FATAL_ERROR;
    425           }
    426           continue;
    427         }
    428         if (fread(tag, 1, 4, f) != 4) break;
    429         if (!strncmp(tag, c->tag, 4))
    430         {
    431           c->start = start + 12;
    432           c->length = len - 4;
    433           return ESR_SUCCESS;
    434         }
    435       }
    436 
    437       //if(feof(f)) GS_SetResult(res,"RIFF form type not found",GS_STATIC);
    438       //else GS_SetResult(res,"Corrupt RIFF file",GS_STATIC);
    439       return ESR_FATAL_ERROR;
    440   }
    441 
    442   //GS_AppendResult(res,"bad search flag",GS_STATIC);
    443   return ESR_FATAL_ERROR;
    444 }
    445 
    446 static int riffAscend(FILE *f, ChunkContext *c)
    447 {
    448   if (fseek(f, c->start + c->length, SEEK_SET) < 0)
    449   {
    450     //GS_SetResult(res,"seek failed",GS_STATIC);
    451     return ESR_FATAL_ERROR;
    452   }
    453   return ESR_SUCCESS;
    454 }
    455 
    456 
    457 static ESR_ReturnCode readSwiChunk(FILE *f,  ChunkContext *parent, SwiRiffStruct *swichunk, int doSwap)
    458 {
    459   ESR_ReturnCode rc = ESR_SUCCESS;
    460   ChunkContext chunk, list_chunk;
    461   int sub_length;
    462   swichunk->segs.num_tuples = 0;
    463   swichunk->kvals.num_pairs = 0;
    464 
    465   strncpy(chunk.tag, "swi ", 4);
    466   if (riffDescend(f, &chunk, parent, FIND_LIST, doSwap) == ESR_SUCCESS)
    467   {
    468     /* is it as "swi " list? */
    469     strncpy(list_chunk.tag, "segs", 4);
    470     if (riffDescend(f, &list_chunk, &chunk, FIND_CHUNK, doSwap) == ESR_SUCCESS)
    471     {
    472       fread(&swichunk->segs.num_tuples, 1, sizeof(int), f);
    473       if (doSwap) swapInt(&swichunk->segs.num_tuples);
    474 
    475       sub_length = list_chunk.length - sizeof(int);
    476       if (sub_length)
    477       {
    478         swichunk->segs.tuples = MALLOC(sub_length, MTAG);
    479         if (!swichunk->segs.tuples)
    480         {
    481           swichunk->segs.num_tuples = 0;  /* so that the free routine will work */
    482           rc = ESR_OUT_OF_MEMORY;
    483         }
    484         else if (fread(swichunk->segs.tuples, 1, sub_length, f) != (size_t)sub_length)
    485         {
    486           rc = ESR_FATAL_ERROR;
    487         }
    488         if (rc != ESR_SUCCESS)
    489           goto swichunk_cleanup;
    490 
    491       }
    492       else
    493         swichunk->segs.tuples = NULL;
    494     }
    495     strncpy(list_chunk.tag, "kvs ", 4);
    496     /* start searching from after "swi" */
    497     if (riffDescend(f, &list_chunk, &chunk, FIND_CHUNK, doSwap) == ESR_SUCCESS)
    498     {
    499       int i, num_pairs;
    500 
    501       fread(&num_pairs, 1, sizeof(int), f);
    502       if (doSwap) swapInt(&num_pairs);
    503       swichunk->kvals.num_pairs = num_pairs;
    504 
    505       sub_length = list_chunk.length - sizeof(int);
    506       if (sub_length)
    507       {
    508         char *kvpair_buf = NULL;
    509         RiffKVPair *pairs;
    510 
    511         swichunk->kvals.kvpairs = (RiffKVPair *)CALLOC(num_pairs, sizeof(RiffKVPair), MTAG);
    512         kvpair_buf = CALLOC(sub_length, sizeof(char), MTAG);
    513         if (!swichunk->kvals.kvpairs || !kvpair_buf)
    514         {
    515           if (kvpair_buf) FREE(kvpair_buf);
    516           if (swichunk->kvals.kvpairs) FREE(swichunk->kvals.kvpairs);
    517           swichunk->kvals.num_pairs = 0;
    518           rc = ESR_OUT_OF_MEMORY;
    519           goto swichunk_cleanup;
    520         }
    521 
    522         swichunk->kvals.kvpairs[0].key = kvpair_buf;
    523         if (fread(kvpair_buf, 1, sub_length, f) != (size_t)sub_length)
    524         {
    525           rc = ESR_FATAL_ERROR;
    526           goto swichunk_cleanup;
    527         }
    528         for (pairs = swichunk->kvals.kvpairs, i = 0; i < swichunk->kvals.num_pairs; i++, pairs++)
    529         {
    530           pairs->key = kvpair_buf;
    531           kvpair_buf +=  strlen(kvpair_buf) + 1;
    532           pairs->value = kvpair_buf;
    533           kvpair_buf +=  strlen(kvpair_buf) + 1;
    534         }
    535       }
    536       else
    537         swichunk->kvals.kvpairs = NULL;
    538     }
    539   }
    540   /* no matter what was found or not found, return with the file pointer in
    541    * the state that it was upon entering this function */
    542   if (riffAscend(f, parent) != ESR_SUCCESS)
    543   {
    544     rc = ESR_FATAL_ERROR;
    545     goto swichunk_cleanup;
    546   }
    547 
    548 swichunk_cleanup:
    549   if (rc == ESR_FATAL_ERROR) free_swiRiff(swichunk);
    550   return rc;
    551 }
    552 
    553 
    554 /* Reads RIFF format WAVE files
    555  */
    556 ESR_ReturnCode riffReadWave2L16(FILE *f, double from, double to,
    557                                 short **samples, int *rate, int *length, SwiRiffStruct *swichunk)
    558 {
    559   ChunkContext chunk, parent;
    560   WaveFormat *wf;
    561   char *cb;
    562   ESR_ReturnCode rc;
    563   int i, ifrom, ito;
    564   int doSwap = ! isLittleEndian();
    565 
    566   /* find the WAVE chunk */
    567   strncpy(parent.tag, "WAVE", 4);
    568   if (riffDescend(f, &parent, NULL, FIND_RIFF, doSwap) != ESR_SUCCESS)
    569   {
    570     //GS_AppendResult(res,"\nnot a RIFF waveform audio file",NULL);
    571     return ESR_FATAL_ERROR;
    572   }
    573 
    574   /* Wave format */
    575   strncpy(chunk.tag, "fmt ", 4);
    576   if (riffDescend(f, &chunk, &parent, FIND_CHUNK, doSwap) != ESR_SUCCESS)
    577   {
    578     //GS_AppendResult(res,"\nwaveform audio file has no \"fmt \" chunk.",NULL);
    579     return ESR_FATAL_ERROR;
    580   }
    581   if (chunk.length < sizeof(WaveFormat))
    582     wf = MALLOC(sizeof(WaveFormat), MTAG);
    583   else
    584     wf = MALLOC(chunk.length, MTAG);
    585 
    586   if (fread(wf, 1, chunk.length, f) != (size_t)chunk.length)
    587   {
    588     FREE((char *)wf);
    589     //GS_SetResult(res,"fmt chunk read failed.",GS_STATIC);
    590     return ESR_FATAL_ERROR;
    591   }
    592   if (doSwap) swapWaveFormat(wf);
    593   *rate = wf->nSamplesPerSec;
    594 
    595   /* data chunk */
    596   if (riffAscend(f, &chunk) != ESR_SUCCESS)
    597   {
    598     return ESR_FATAL_ERROR;
    599   }
    600   strncpy(chunk.tag, "data", 4);
    601   if (riffDescend(f, &chunk, &parent, FIND_CHUNK, doSwap) != ESR_SUCCESS)
    602   {
    603     //GS_AppendResult(res,"\nwaveform audio file has no \"data\" chunk.",NULL);
    604     return ESR_FATAL_ERROR;
    605   }
    606   cb = MALLOC(chunk.length, MTAG); /* waveform */
    607   if (fread(cb, 1, chunk.length, f) != (size_t)chunk.length)
    608   {
    609     FREE((char *)wf);
    610     FREE((char *)cb);
    611     //GS_SetResult(res,"truncated \"data\" chunk",GS_STATIC);
    612     return ESR_FATAL_ERROR;
    613   }
    614 
    615   if (swichunk)
    616   {
    617     rc = readSwiChunk(f, &parent, swichunk, doSwap);
    618     if (rc != ESR_SUCCESS)
    619     {
    620       FREE((char *)wf);
    621       FREE((char *)cb);
    622       return rc;
    623     }
    624   }
    625 
    626   for (i = 0;WaveCodecs[i].func;i++)
    627 
    628     if (wf->nFormatTag == WaveCodecs[i].id)
    629     {
    630       rc = (WaveCodecs[i].func)(wf, &chunk, cb, samples, length, doSwap);
    631       FREE((char *)wf);
    632       FREE((char *)cb);
    633       if (rc != ESR_SUCCESS)
    634       {
    635         if (swichunk) free_swiRiff(swichunk);
    636         return rc;
    637       }
    638       /* handle 'from' and 'to' - this isn't very efficient, but
    639        * saves all the format conversion routines the trouble of doing so
    640        */
    641       if (from == 0 && to == -1) return ESR_SUCCESS;
    642       if (from > 0)
    643         ifrom = (int)(from * (*rate) / 1000.0);
    644       else
    645         ifrom = 0;
    646 
    647       if (to >= 0)
    648       {
    649         ito = (int)(to * (*rate) / 1000.0 + 0.5);
    650         if (ito > *length)
    651           ito = *length;
    652       }
    653       else
    654         ito = *length;
    655 
    656       *length = ito - ifrom;
    657       if (ifrom > 0) memmove(*samples, (*samples) + ifrom, (*length)*sizeof(short));
    658       return ESR_SUCCESS;
    659     }
    660 
    661   //GS_SetResult(res,GS_Spf(0,"WAVE format (id 0x%x) not supported",
    662   //wf->nFormatTag),GS_VOLATILE);
    663   //
    664   if (swichunk) free_swiRiff(swichunk);
    665   FREE((char *)cb);
    666   return ESR_FATAL_ERROR;
    667 }
    668 
    669 
    670 
    671 /* Reads RIFF format WAVE files and returns:
    672  *   waveform: allocated with size num_bytes
    673  *   audio_type is a constant string (not allocated)
    674  * If swichunk==NULL, does not look for swi-specific chunk,
    675  * Returns ESR_FATAL_ERROR if num_channels != 1
    676  * If and only if ESR_SUCCESS, caller must free waveform, and swichunk contents (if any)
    677  */
    678 ESR_ReturnCode readRiff2Buf(FILE *f, void **waveform, unsigned int *num_bytes,
    679                             const wchar_t **audio_type, SwiRiffStruct *swichunk)
    680 {
    681   ChunkContext chunk, parent;
    682   WaveFormat *wf = NULL;
    683   ESR_ReturnCode rc = ESR_SUCCESS;
    684   int doSwap = ! isLittleEndian();
    685   *waveform = NULL;
    686 
    687   *audio_type = NULL;  /* for error recovery higher up */
    688 
    689   if (swichunk)
    690   { /* for error recovery */
    691     swichunk->segs.num_tuples = 0;
    692     swichunk->kvals.num_pairs = 0;
    693   }
    694 
    695   /* find the WAVE chunk */
    696   strncpy(parent.tag, "WAVE", 4);
    697   if (riffDescend(f, &parent, NULL, FIND_RIFF, doSwap) != ESR_SUCCESS)
    698   {
    699     return ESR_FATAL_ERROR;
    700   }
    701 
    702   /* Wave format */
    703   strncpy(chunk.tag, "fmt ", 4);
    704   if (riffDescend(f, &chunk, &parent, FIND_CHUNK, doSwap) != ESR_SUCCESS)
    705   {
    706     return ESR_FATAL_ERROR;
    707   }
    708   if (chunk.length < sizeof(WaveFormat))
    709     wf = MALLOC(sizeof(WaveFormat), MTAG);
    710   else
    711     wf = MALLOC(chunk.length, MTAG);
    712 
    713   if (fread(wf, 1, chunk.length, f) != (size_t)chunk.length)
    714   {
    715     FREE((char *)wf);
    716     return ESR_FATAL_ERROR;
    717   }
    718   if (doSwap) swapWaveFormat(wf);
    719 
    720   if (wf->nChannels != 1)
    721   {
    722     FREE((char *)wf);
    723     return ESR_FATAL_ERROR;
    724   }
    725   if (doSwap)
    726   {
    727     swapShort(&wf->nBlockAlign);  /* usually == blockAlign / nChannels */
    728     swapInt(&wf->nSamplesPerSec);
    729     swapShort(&wf->nFormatTag);
    730   }
    731 
    732   /* data chunk */
    733   if (riffAscend(f, &chunk) != ESR_SUCCESS)
    734   {
    735     rc = ESR_FATAL_ERROR;
    736     goto cleanup;
    737   }
    738 
    739   strncpy(chunk.tag, "data", 4);
    740   if (riffDescend(f, &chunk, &parent, FIND_CHUNK, doSwap) != ESR_SUCCESS)
    741   {
    742     rc =  ESR_FATAL_ERROR;
    743     goto cleanup;
    744   }
    745 
    746   *num_bytes = chunk.length;  /* already swapped, if need be */
    747   *waveform = CALLOC(chunk.length, 1, MTAG);
    748   if (fread(*waveform, 1, chunk.length, f) != (size_t)chunk.length)
    749   {
    750     rc = ESR_FATAL_ERROR;
    751     goto cleanup;
    752   }
    753   if (doSwap)
    754   {
    755     if (wf->nBlockAlign == 2)
    756       short_byte_swap((short *)*waveform, chunk.length);
    757     else if (wf->nBlockAlign == 4)
    758       int_byte_swap((int *)*waveform, chunk.length);
    759   }
    760 
    761   if (swichunk)
    762   {
    763     rc = readSwiChunk(f, &parent, swichunk, doSwap);
    764     goto cleanup;
    765   }
    766 
    767   *audio_type = NULL;
    768 
    769   /* assuming nchannels = 1, usually bytes_per_sample==blockAlign / nchannels (not aurora!) */
    770   if (wf->nFormatTag == WAVEFORMAT_PCM)
    771   {
    772     if (wf->nBlockAlign == 2)
    773     {/* can only be L16 */
    774       if (wf->nSamplesPerSec == 8000)
    775         *audio_type = L"audio/L16;rate=8000";
    776       else if (wf->nSamplesPerSec == 16000)
    777         *audio_type = L"audio/L16;rate=16000";
    778     }
    779   }
    780   else if (wf->nFormatTag == WAVEFORMAT_ALAW)
    781   {
    782     if (wf->nSamplesPerSec == 8000)
    783       *audio_type = L"audio/x-alaw-basic;rate=8000";
    784   }
    785   else if (wf->nFormatTag == WAVEFORMAT_MULAW)
    786   {
    787     if (wf->nSamplesPerSec == 8000)
    788     {
    789       if (swichunk)
    790       {
    791         char *encoding = getSwiRiffKVal(swichunk, "orig-encoding");
    792         if (!encoding)
    793           *audio_type = L"audio/basic;rate=8000";
    794         else  if (! strcmp(encoding, "g723"))
    795           *audio_type = L"audio/basic;rate=8000;orig-encoding=g723";
    796         else if (! strcmp(encoding, "g729"))
    797           *audio_type = L"audio/basic;rate=8000;orig-encoding=g729";
    798         else
    799         {
    800           // FIXME: warning because unknown orig-encoding??
    801           // rec_test will never get here cuz already checked validity of audiotype
    802           // but to be careful pour l'avenir, should handle this
    803           *audio_type = L"audio/basic;rate=8000";
    804         }
    805       }
    806       else
    807         *audio_type = L"audio/basic;rate=8000";
    808     }
    809     else if (wf->nSamplesPerSec == 16000)
    810       *audio_type = L"audio/basic;rate=16000";
    811 
    812   }
    813   else if (wf->nFormatTag == WAVEFORMAT_AURORA)
    814   {
    815     if (wf->nSamplesPerSec == 8000)
    816       *audio_type = L"application/x-feature;rate=8000;encoding=swifeature_aurora";
    817     else if (wf->nSamplesPerSec == 11000)
    818       *audio_type = L"application/x-feature;rate=11000;encoding=swifeature_aurora";
    819     else if (wf->nSamplesPerSec == 16000)
    820       *audio_type = L"application/x-feature;rate=16000;encoding=swifeature_aurora";
    821   }
    822   else if (wf->nFormatTag == WAVEFORMAT_ES_202_050)
    823   {
    824     if (wf->nSamplesPerSec == 8000)
    825       *audio_type = L"application/x-feature;rate=8000;encoding=ES_202_050";
    826     else if (wf->nSamplesPerSec == 11000)
    827       *audio_type = L"application/x-feature;rate=11000;encoding=ES_202_050";
    828     else if (wf->nSamplesPerSec == 16000)
    829       *audio_type = L"application/x-feature;rate=16000;encoding=ES_202_050";
    830   }
    831 
    832   if (*audio_type == NULL)
    833   {
    834     rc = ESR_FATAL_ERROR;
    835     goto cleanup;
    836   }
    837 
    838 cleanup:
    839   if (wf) FREE((char *)wf);
    840   if (rc != ESR_SUCCESS)
    841   {
    842     if (swichunk)
    843       free_swiRiff(swichunk);
    844     if (*waveform)
    845     {
    846       FREE((char *)*waveform);
    847       *waveform = NULL;
    848     }
    849   }
    850   return rc;
    851 }
    852 
    853 static int getFormatTag(wchar_t *audio_type)
    854 {
    855   if (!wcsncmp(audio_type, L"audio/basic", 11))
    856   {
    857     return WAVEFORMAT_MULAW;
    858   }
    859   if (!wcsncmp(audio_type, L"application/x-feature;", 14) &&
    860       wcsstr(audio_type, L"encoding=swifeature_aurora"))
    861   {
    862     return WAVEFORMAT_AURORA;
    863   }
    864   else if (!wcsncmp(audio_type, L"application/x-feature;", 14) &&
    865            wcsstr(audio_type, L"encoding=ES_202_050"))
    866   {
    867     return WAVEFORMAT_ES_202_050;
    868   }
    869   else if (!wcsncmp(audio_type, L"audio/x-alaw-basic", 18))
    870   {
    871     return WAVEFORMAT_ALAW;
    872   }
    873   else if (!wcsncmp(audio_type, L"audio/L16", 9))
    874   {
    875     return WAVEFORMAT_PCM;
    876   }
    877   return -1;
    878 }
    879 
    880 /* we are assuming that riffaudio->num_tuples!=0, and hence riffaudio->tuples!=NULL
    881  */
    882 static unsigned char *writeSwiAudioChunk(int doSwap, int chunk_len, SwiRiffAudio *riffaudio,
    883     unsigned char *workbuf)
    884 {
    885   ChunkInfoStruct ck;
    886   int chunkinfosize = sizeof(ChunkInfoStruct);
    887 
    888   strncpy(ck.ckString, "segs", 4);
    889   ck.ckLength = chunk_len;
    890   if (doSwap)
    891   {
    892     swapInt(&ck.ckLength);
    893     memcpy(workbuf, &ck, chunkinfosize);
    894     workbuf += chunkinfosize;
    895 
    896     memcpy(workbuf, &riffaudio->num_tuples, sizeof(int));
    897     workbuf += sizeof(int);
    898     chunk_len -= sizeof(int);
    899 
    900     memcpy(workbuf, riffaudio->tuples, chunk_len);
    901     int_byte_swap((int *)workbuf, riffaudio->num_tuples*3 + 1);
    902     /* count every tuple (3) + num_tuples itself */
    903     return workbuf + chunk_len;
    904   }
    905   else
    906   {
    907     memcpy(workbuf, &ck, chunkinfosize);
    908     workbuf += chunkinfosize;
    909     memcpy(workbuf, &riffaudio->num_tuples, sizeof(int));
    910     workbuf += sizeof(int);
    911     chunk_len -= sizeof(int);
    912 
    913     memcpy(workbuf, riffaudio->tuples, chunk_len);
    914     return workbuf + chunk_len;
    915   }
    916 }
    917 
    918 /* WARNING:  returns with file pointer past the 4 first chars
    919  *
    920  * If the first 4 bytes of the specified file are "RIFF",
    921  * then we assume it's a RIFF file
    922  */
    923 int isRiffFile(FILE *fp)
    924 {
    925   char tmpbuf[4];
    926   fseek(fp, 0, SEEK_SET);
    927   fread(tmpbuf, 4, sizeof(char), fp);
    928   return !strncmp(tmpbuf, "RIFF", 4);
    929 
    930 }
    931 
    932 /*
    933  * WARNING: assuming num_channels = 1
    934  * INPUT: waveform, num_bytes (waveform length), audio_type,
    935  *        swichunk (it returns unmodified, including not swapped)
    936  * OUTPUT: buf (entire riff chunk) and buflen
    937  *
    938  * AURORA special case:
    939  *   sampling rate = bytes_per_sample = -1; other fields of WaveFormat undefined
    940  */
    941 ESR_ReturnCode convertBuf2Riff(
    942   unsigned char *waveform,
    943   unsigned int num_bytes,
    944   wchar_t *audio_type,
    945   int rate,
    946   int bytes_per_sample,
    947   SwiRiffStruct *swichunk,
    948   unsigned char **buf,
    949   unsigned int *buflen)
    950 {
    951   unsigned int total_buflen;
    952   unsigned char *ptr, *workbuf;
    953   short num_channels = 1;
    954   int num_samples;
    955   int bytes_sec;
    956   short block_align;
    957   int doSwap;
    958   ChunkInfoStruct ck;
    959   RiffHeaderStruct header;
    960   int headerSize = sizeof(RiffHeaderStruct);
    961   int chunkInfoSize = sizeof(ChunkInfoStruct);
    962   int listChunkSize = 0;
    963   int segs_chunk_size, kvals_chunk_size;
    964   short format_tag = (short) getFormatTag(audio_type);
    965 
    966   if (format_tag == -1 ||
    967       (bytes_per_sample == -1 && format_tag != WAVEFORMAT_AURORA &&
    968        format_tag != WAVEFORMAT_ES_202_050))
    969   {
    970     PLogError(L("audio type not supported for RIFF conversion"));
    971     return ESR_FATAL_ERROR;
    972 
    973   }
    974   if (bytes_per_sample > 0)
    975     num_samples = num_bytes / bytes_per_sample;
    976   else
    977     num_samples = num_bytes;
    978 
    979   strncpy(header.riffString, "RIFF", 4);
    980   strncpy(header.waveString, "WAVE", 4);
    981   strncpy(header.fmtString, "fmt ", 4);
    982   strncpy(header.dataString, "data", 4);
    983 
    984   total_buflen = headerSize + num_bytes;
    985 
    986   if (swichunk->segs.num_tuples || swichunk->kvals.num_pairs)
    987   {
    988     listChunkSize = chunkInfoSize  /* LIST chunk info */ + 4 * sizeof(char);  /* "swi " */
    989     if (swichunk->segs.num_tuples)
    990     {
    991       segs_chunk_size = sizeof(int) + (swichunk->segs.num_tuples) * sizeof(RiffAudioTuple);
    992       listChunkSize += chunkInfoSize + segs_chunk_size;
    993     }
    994     if (swichunk->kvals.num_pairs)
    995     {
    996       int i;
    997       kvals_chunk_size = 0;
    998       for (i = 0; i < swichunk->kvals.num_pairs; i++)
    999       {
   1000         kvals_chunk_size += (strlen(swichunk->kvals.kvpairs[i].key) + 1
   1001                              + strlen(swichunk->kvals.kvpairs[i].value) + 1) * sizeof(char);
   1002       }
   1003       kvals_chunk_size += sizeof(int);  /* num_pairs */
   1004       listChunkSize += chunkInfoSize + kvals_chunk_size;
   1005     }
   1006     total_buflen += listChunkSize;
   1007   }
   1008   if (total_buflen > *buflen)
   1009   {
   1010     PLogError(L("ESR_BUFFER_OVERFLOW"));
   1011     return ESR_BUFFER_OVERFLOW;
   1012   }
   1013   workbuf = *buf;
   1014 
   1015   *buflen = total_buflen;
   1016   ptr = workbuf;
   1017   if (format_tag == WAVEFORMAT_AURORA || format_tag == WAVEFORMAT_ES_202_050)
   1018   {
   1019     bytes_sec = AURORA_BYTES_SEC;
   1020     block_align = 4;
   1021   }
   1022   else
   1023   {
   1024     bytes_sec = (short)(rate * num_channels * bytes_per_sample);
   1025     block_align = bytes_per_sample * num_channels;
   1026   }
   1027   doSwap = !isLittleEndian();
   1028   if (doSwap)
   1029   {
   1030     header.riffChunkLength = swapConstInt(*buflen - chunkInfoSize);
   1031     header.fmtChunkLength = swapConstInt(sizeof(WaveFormat));
   1032     header.waveinfo.nFormatTag = swapConstShort(format_tag);  /* codec */
   1033     header.waveinfo.nChannels = swapConstShort(num_channels);
   1034     header.waveinfo.nSamplesPerSec = swapConstInt(rate);
   1035     header.waveinfo.nAvgBytesPerSec = swapConstInt(bytes_sec);
   1036     header.waveinfo.nBlockAlign = swapConstShort(block_align);
   1037     header.waveinfo.wBitsPerSample = swapConstShort((short)((bytes_sec * 8) / rate));
   1038     header.dataLength = swapConstInt(num_bytes);
   1039     memcpy(ptr, &header, headerSize);
   1040 
   1041     memcpy(ptr + headerSize, waveform, header.dataLength);
   1042     if (bytes_per_sample == 2)
   1043       short_byte_swap((short *)(ptr + headerSize), num_samples);
   1044   }
   1045   else
   1046   {
   1047     header.riffChunkLength = total_buflen - chunkInfoSize;
   1048     header.fmtChunkLength = sizeof(WaveFormat);
   1049     header.waveinfo.nFormatTag = format_tag;  /* codec */
   1050     header.waveinfo.nChannels = num_channels;
   1051     header.waveinfo.nSamplesPerSec = rate;
   1052     header.waveinfo.nAvgBytesPerSec = bytes_sec;
   1053     header.waveinfo.nBlockAlign = (short) block_align;
   1054     header.waveinfo.wBitsPerSample = (bytes_sec * 8) / rate;
   1055     header.dataLength = num_bytes;
   1056 
   1057     memcpy(ptr, &header, headerSize);
   1058     memcpy(ptr + headerSize, waveform, header.dataLength);
   1059   }
   1060   ptr += headerSize + header.dataLength;
   1061 
   1062   if (swichunk->segs.num_tuples || swichunk->kvals.num_pairs)
   1063   {
   1064     strncpy(ck.ckString, "LIST", 4);
   1065     ck.ckLength = listChunkSize - chunkInfoSize;
   1066     if (doSwap) swapInt(&ck.ckLength);
   1067     memcpy(ptr, &ck, chunkInfoSize);   /* copy LIST */
   1068     ptr += chunkInfoSize;
   1069 
   1070     strncpy((char *)ptr, "swi ", 4);
   1071     ptr += 4;
   1072 
   1073     if (swichunk->segs.num_tuples)
   1074     {
   1075       ptr = writeSwiAudioChunk(doSwap, segs_chunk_size, &swichunk->segs, ptr);
   1076     }
   1077     if (swichunk->kvals.num_pairs)
   1078     {
   1079       int i, num_pairs;
   1080       RiffKVPair *pairs;
   1081 
   1082       strncpy(ck.ckString, "kvs ", 4);
   1083       ck.ckLength = kvals_chunk_size;   /* num_pairs and pairs themselves */
   1084       if (doSwap) swapInt(&ck.ckLength);
   1085       memcpy(ptr, &ck, chunkInfoSize);
   1086       ptr += chunkInfoSize;
   1087 
   1088       num_pairs = (doSwap) ? swapConstInt(swichunk->kvals.num_pairs) : swichunk->kvals.num_pairs;
   1089       memcpy(ptr, &num_pairs, sizeof(int));
   1090       ptr += sizeof(int);
   1091 
   1092       for (pairs = swichunk->kvals.kvpairs, i = 0; i < num_pairs; i++, pairs++)
   1093       {
   1094         strcpy((char *)ptr, pairs->key);
   1095         ptr += strlen(pairs->key) + 1;
   1096 
   1097         strcpy((char *)ptr, pairs->value);
   1098         ptr += strlen(pairs->value) + 1;
   1099       }
   1100     }
   1101   }
   1102   passert((unsigned int)(ptr - workbuf) == *buflen);
   1103 
   1104   return ESR_SUCCESS;
   1105 }
   1106 
   1107 
   1108