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
25typedef struct ChunkContext_t
26{
27  char tag[4];
28  long  start;
29  int  length;
30}
31ChunkContext;
32
33typedef enum
34{
35  FIND_RIFF,
36  FIND_CHUNK,
37  FIND_LIST
38} DescendType;
39
40int 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 */
60typedef ESR_ReturnCode(waveReadFunc)(WaveFormat *wf, ChunkContext *data,
61                                     char *cb, short **samples, int *length, int doSwap);
62
63static ESR_ReturnCode readPCMWave(WaveFormat *wf, ChunkContext *data,
64                                  char *cb, short **samples, int *length, int doSwap);
65static ESR_ReturnCode readMulawWave(WaveFormat *wf, ChunkContext *data,
66                                    char *cb, short **samples, int *length, int doSwap);
67static ESR_ReturnCode readAlawWave(WaveFormat *wf, ChunkContext *data,
68                                   char *cb, short **samples, int *length, int doSwap);
69
70static struct
71{
72  int id;
73  waveReadFunc *func;
74}
75WaveCodecs[] = {
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
86static 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
97static 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
105static 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
120static 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 */
134static 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 */
149static 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
165static 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
176static 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
193static 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 */
218static 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 */
251static 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 */
276static 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
302void 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
317char *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
330static 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
446static 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
457static 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
548swichunk_cleanup:
549  if (rc == ESR_FATAL_ERROR) free_swiRiff(swichunk);
550  return rc;
551}
552
553
554/* Reads RIFF format WAVE files
555 */
556ESR_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 */
678ESR_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
838cleanup:
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
853static 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 */
882static 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 */
923int 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 */
941ESR_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