pulling trunk
[ardour.git] / libs / libsndfile / src / g72x.c
1 /*
2 ** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "sfconfig.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "sndfile.h"
26 #include "sfendian.h"
27 #include "float_cast.h"
28 #include "common.h"
29 #include "G72x/g72x.h"
30
31 /* This struct is private to the G72x code. */
32 struct g72x_state ;
33 typedef struct g72x_state G72x_STATE ;
34
35 typedef struct
36 {       /* Private data. Don't mess with it. */
37         struct g72x_state * private ;
38
39         /* Public data. Read only. */
40         int                             blocksize, samplesperblock, bytesperblock ;
41
42         /* Public data. Read and write. */
43         int                             blocks_total, block_curr, sample_curr ;
44         unsigned char   block   [G72x_BLOCK_SIZE] ;
45         short                   samples [G72x_BLOCK_SIZE] ;
46 } G72x_PRIVATE ;
47
48 static  int     psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ;
49 static  int     psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ;
50
51 static  sf_count_t      g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
52 static  sf_count_t      g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
53 static  sf_count_t      g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
54 static  sf_count_t      g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
55
56 static  sf_count_t      g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
57 static  sf_count_t      g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
58 static  sf_count_t      g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
59 static  sf_count_t      g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
60
61 static  sf_count_t g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
62
63 static  int     g72x_close (SF_PRIVATE *psf) ;
64
65
66 /*============================================================================================
67 ** WAV G721 Reader initialisation function.
68 */
69
70 int
71 g72x_init (SF_PRIVATE * psf)
72 {       G72x_PRIVATE    *pg72x ;
73         int     bitspersample, bytesperblock, codec ;
74
75         if (psf->fdata != NULL)
76         {       psf_log_printf (psf, "*** psf->fdata is not NULL.\n") ;
77                 return SFE_INTERNAL ;
78                 } ;
79
80         psf->sf.seekable = SF_FALSE ;
81
82         if (psf->sf.channels != 1)
83                 return SFE_G72X_NOT_MONO ;
84
85         if ((pg72x = calloc (1, sizeof (G72x_PRIVATE))) == NULL)
86                 return SFE_MALLOC_FAILED ;
87
88         psf->fdata = (void*) pg72x ;
89
90         pg72x->block_curr = 0 ;
91         pg72x->sample_curr = 0 ;
92
93         switch (psf->sf.format & SF_FORMAT_SUBMASK)
94         {       case SF_FORMAT_G721_32 :
95                                 codec = G721_32_BITS_PER_SAMPLE ;
96                                 bytesperblock = G721_32_BYTES_PER_BLOCK ;
97                                 bitspersample = G721_32_BITS_PER_SAMPLE ;
98                                 break ;
99
100                 case SF_FORMAT_G723_24:
101                                 codec = G723_24_BITS_PER_SAMPLE ;
102                                 bytesperblock = G723_24_BYTES_PER_BLOCK ;
103                                 bitspersample = G723_24_BITS_PER_SAMPLE ;
104                                 break ;
105
106                 case SF_FORMAT_G723_40:
107                                 codec = G723_40_BITS_PER_SAMPLE ;
108                                 bytesperblock = G723_40_BYTES_PER_BLOCK ;
109                                 bitspersample = G723_40_BITS_PER_SAMPLE ;
110                                 break ;
111
112                 default : return SFE_UNIMPLEMENTED ;
113                 } ;
114
115         psf->blockwidth = psf->bytewidth = 1 ;
116
117         psf->filelength = psf_get_filelen (psf) ;
118         if (psf->filelength < psf->dataoffset)
119                 psf->filelength = psf->dataoffset ;
120
121         psf->datalength = psf->filelength - psf->dataoffset ;
122         if (psf->dataend > 0)
123                 psf->datalength -= psf->filelength - psf->dataend ;
124
125         if (psf->mode == SFM_READ)
126         {       pg72x->private = g72x_reader_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ;
127                 if (pg72x->private == NULL)
128                         return SFE_MALLOC_FAILED ;
129
130                 pg72x->bytesperblock = bytesperblock ;
131
132                 psf->read_short         = g72x_read_s ;
133                 psf->read_int           = g72x_read_i ;
134                 psf->read_float         = g72x_read_f ;
135                 psf->read_double        = g72x_read_d ;
136
137                 psf->seek = g72x_seek ;
138
139                 if (psf->datalength % pg72x->blocksize)
140                 {       psf_log_printf (psf, "*** Odd psf->datalength (%D) should be a multiple of %d\n", psf->datalength, pg72x->blocksize) ;
141                         pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ;
142                         }
143                 else
144                         pg72x->blocks_total = psf->datalength / pg72x->blocksize ;
145
146                 psf->sf.frames = pg72x->blocks_total * pg72x->samplesperblock ;
147
148                 psf_g72x_decode_block (psf, pg72x) ;
149                 }
150         else if (psf->mode == SFM_WRITE)
151         {       pg72x->private = g72x_writer_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ;
152                 if (pg72x->private == NULL)
153                         return SFE_MALLOC_FAILED ;
154
155                 pg72x->bytesperblock = bytesperblock ;
156
157                 psf->write_short        = g72x_write_s ;
158                 psf->write_int          = g72x_write_i ;
159                 psf->write_float        = g72x_write_f ;
160                 psf->write_double       = g72x_write_d ;
161
162                 if (psf->datalength % pg72x->blocksize)
163                         pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ;
164                 else
165                         pg72x->blocks_total = psf->datalength / pg72x->blocksize ;
166
167                 if (psf->datalength > 0)
168                         psf->sf.frames = (8 * psf->datalength) / bitspersample ;
169
170                 if ((psf->sf.frames * bitspersample) / 8 != psf->datalength)
171                         psf_log_printf (psf, "*** Warning : weird psf->datalength.\n") ;
172                 } ;
173
174         psf->codec_close        = g72x_close ;
175
176         return 0 ;
177 } /* g72x_init */
178
179 /*============================================================================================
180 ** G721 Read Functions.
181 */
182
183 static int
184 psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x)
185 {       int     k ;
186
187         pg72x->block_curr ++ ;
188         pg72x->sample_curr = 0 ;
189
190         if (pg72x->block_curr > pg72x->blocks_total)
191         {       memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ;
192                 return 1 ;
193                 } ;
194
195         if ((k = psf_fread (pg72x->block, 1, pg72x->bytesperblock, psf)) != pg72x->bytesperblock)
196                 psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pg72x->bytesperblock) ;
197
198         pg72x->blocksize = k ;
199         g72x_decode_block (pg72x->private, pg72x->block, pg72x->samples) ;
200
201         return 1 ;
202 } /* psf_g72x_decode_block */
203
204 static int
205 g72x_read_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, short *ptr, int len)
206 {       int     count, total = 0, indx = 0 ;
207
208         while (indx < len)
209         {       if (pg72x->block_curr > pg72x->blocks_total)
210                 {       memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ;
211                         return total ;
212                         } ;
213
214                 if (pg72x->sample_curr >= pg72x->samplesperblock)
215                         psf_g72x_decode_block (psf, pg72x) ;
216
217                 count = pg72x->samplesperblock - pg72x->sample_curr ;
218                 count = (len - indx > count) ? count : len - indx ;
219
220                 memcpy (&(ptr [indx]), &(pg72x->samples [pg72x->sample_curr]), count * sizeof (short)) ;
221                 indx += count ;
222                 pg72x->sample_curr += count ;
223                 total = indx ;
224                 } ;
225
226         return total ;
227 } /* g72x_read_block */
228
229 static sf_count_t
230 g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
231 {       G72x_PRIVATE    *pg72x ;
232         int                     readcount, count ;
233         sf_count_t      total = 0 ;
234
235         if (psf->fdata == NULL)
236                 return 0 ;
237         pg72x = (G72x_PRIVATE*) psf->fdata ;
238
239         while (len > 0)
240         {       readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
241
242                 count = g72x_read_block (psf, pg72x, ptr, readcount) ;
243
244                 total += count ;
245                 len -= count ;
246
247                 if (count != readcount)
248                         break ;
249                 } ;
250
251         return total ;
252 } /* g72x_read_s */
253
254 static sf_count_t
255 g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
256 {       G72x_PRIVATE *pg72x ;
257         short           *sptr ;
258         int                     k, bufferlen, readcount = 0, count ;
259         sf_count_t      total = 0 ;
260
261         if (psf->fdata == NULL)
262                 return 0 ;
263         pg72x = (G72x_PRIVATE*) psf->fdata ;
264
265         sptr = psf->u.sbuf ;
266         bufferlen = SF_BUFFER_LEN / sizeof (short) ;
267         while (len > 0)
268         {       readcount = (len >= bufferlen) ? bufferlen : len ;
269                 count = g72x_read_block (psf, pg72x, sptr, readcount) ;
270
271                 for (k = 0 ; k < readcount ; k++)
272                         ptr [total + k] = sptr [k] << 16 ;
273
274                 total += count ;
275                 len -= readcount ;
276                 if (count != readcount)
277                         break ;
278                 } ;
279
280         return total ;
281 } /* g72x_read_i */
282
283 static sf_count_t
284 g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
285 {       G72x_PRIVATE *pg72x ;
286         short           *sptr ;
287         int                     k, bufferlen, readcount = 0, count ;
288         sf_count_t      total = 0 ;
289         float           normfact ;
290
291         if (psf->fdata == NULL)
292                 return 0 ;
293         pg72x = (G72x_PRIVATE*) psf->fdata ;
294
295         normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
296
297         sptr = psf->u.sbuf ;
298         bufferlen = SF_BUFFER_LEN / sizeof (short) ;
299         while (len > 0)
300         {       readcount = (len >= bufferlen) ? bufferlen : len ;
301                 count = g72x_read_block (psf, pg72x, sptr, readcount) ;
302                 for (k = 0 ; k < readcount ; k++)
303                         ptr [total + k] = normfact * sptr [k] ;
304
305                 total += count ;
306                 len -= readcount ;
307                 if (count != readcount)
308                         break ;
309                 } ;
310
311         return total ;
312 } /* g72x_read_f */
313
314 static sf_count_t
315 g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
316 {       G72x_PRIVATE *pg72x ;
317         short           *sptr ;
318         int                     k, bufferlen, readcount = 0, count ;
319         sf_count_t      total = 0 ;
320         double          normfact ;
321
322         if (psf->fdata == NULL)
323                 return 0 ;
324         pg72x = (G72x_PRIVATE*) psf->fdata ;
325
326         normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
327
328         sptr = psf->u.sbuf ;
329         bufferlen = SF_BUFFER_LEN / sizeof (short) ;
330         while (len > 0)
331         {       readcount = (len >= bufferlen) ? bufferlen : len ;
332                 count = g72x_read_block (psf, pg72x, sptr, readcount) ;
333                 for (k = 0 ; k < readcount ; k++)
334                         ptr [total + k] = normfact * (double) (sptr [k]) ;
335
336                 total += count ;
337                 len -= readcount ;
338                 if (count != readcount)
339                         break ;
340                 } ;
341
342         return total ;
343 } /* g72x_read_d */
344
345 static sf_count_t
346 g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
347 {
348         /* Prevent compiler warnings. */
349         mode ++ ;
350         offset ++ ;
351
352         psf_log_printf (psf, "seek unsupported\n") ;
353
354         /*      No simple solution. To do properly, would need to seek
355         **      to start of file and decode everything up to seek position.
356         **      Maybe implement SEEK_SET to 0 only?
357         */
358         return 0 ;
359
360 /*
361 **              G72x_PRIVATE    *pg72x ;
362 **              int                     newblock, newsample, sample_curr ;
363 **
364 **              if (psf->fdata == NULL)
365 **                      return 0 ;
366 **              pg72x = (G72x_PRIVATE*) psf->fdata ;
367 **
368 **              if (! (psf->datalength && psf->dataoffset))
369 **              {       psf->error = SFE_BAD_SEEK ;
370 **                      return  PSF_SEEK_ERROR ;
371 **                      } ;
372 **
373 **              sample_curr = (8 * psf->datalength) / G721_32_BITS_PER_SAMPLE ;
374 **
375 **              switch (whence)
376 **              {       case SEEK_SET :
377 **                                      if (offset < 0 || offset > sample_curr)
378 **                                      {       psf->error = SFE_BAD_SEEK ;
379 **                                              return  PSF_SEEK_ERROR ;
380 **                                              } ;
381 **                                      newblock  = offset / pg72x->samplesperblock ;
382 **                                      newsample = offset % pg72x->samplesperblock ;
383 **                                      break ;
384 **
385 **                      case SEEK_CUR :
386 **                                      if (psf->current + offset < 0 || psf->current + offset > sample_curr)
387 **                                      {       psf->error = SFE_BAD_SEEK ;
388 **                                              return  PSF_SEEK_ERROR ;
389 **                                              } ;
390 **                                      newblock  = (8 * (psf->current + offset)) / pg72x->samplesperblock ;
391 **                                      newsample = (8 * (psf->current + offset)) % pg72x->samplesperblock ;
392 **                                      break ;
393 **
394 **                      case SEEK_END :
395 **                                      if (offset > 0 || sample_curr + offset < 0)
396 **                                      {       psf->error = SFE_BAD_SEEK ;
397 **                                              return  PSF_SEEK_ERROR ;
398 **                                              } ;
399 **                                      newblock  = (sample_curr + offset) / pg72x->samplesperblock ;
400 **                                      newsample = (sample_curr + offset) % pg72x->samplesperblock ;
401 **                                      break ;
402 **
403 **                      default :
404 **                                      psf->error = SFE_BAD_SEEK ;
405 **                                      return  PSF_SEEK_ERROR ;
406 **                      } ;
407 **
408 **              if (psf->mode == SFM_READ)
409 **              {       psf_fseek (psf, psf->dataoffset + newblock * pg72x->blocksize, SEEK_SET) ;
410 **                      pg72x->block_curr  = newblock ;
411 **                      psf_g72x_decode_block (psf, pg72x) ;
412 **                      pg72x->sample_curr = newsample ;
413 **                      }
414 **              else
415 **              {       /+* What to do about write??? *+/
416 **                      psf->error = SFE_BAD_SEEK ;
417 **                      return  PSF_SEEK_ERROR ;
418 **                      } ;
419 **
420 **              psf->current = newblock * pg72x->samplesperblock + newsample ;
421 **              return psf->current ;
422 **
423 */
424 } /* g72x_seek */
425
426 /*==========================================================================================
427 ** G72x Write Functions.
428 */
429
430 static int
431 psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x)
432 {       int k ;
433
434         /* Encode the samples. */
435         g72x_encode_block (pg72x->private, pg72x->samples, pg72x->block) ;
436
437         /* Write the block to disk. */
438         if ((k = psf_fwrite (pg72x->block, 1, pg72x->blocksize, psf)) != pg72x->blocksize)
439                 psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pg72x->blocksize) ;
440
441         pg72x->sample_curr = 0 ;
442         pg72x->block_curr ++ ;
443
444         /* Set samples to zero for next block. */
445         memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ;
446
447         return 1 ;
448 } /* psf_g72x_encode_block */
449
450 static int
451 g72x_write_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, const short *ptr, int len)
452 {       int     count, total = 0, indx = 0 ;
453
454         while (indx < len)
455         {       count = pg72x->samplesperblock - pg72x->sample_curr ;
456
457                 if (count > len - indx)
458                         count = len - indx ;
459
460                 memcpy (&(pg72x->samples [pg72x->sample_curr]), &(ptr [indx]), count * sizeof (short)) ;
461                 indx += count ;
462                 pg72x->sample_curr += count ;
463                 total = indx ;
464
465                 if (pg72x->sample_curr >= pg72x->samplesperblock)
466                         psf_g72x_encode_block (psf, pg72x) ;
467                 } ;
468
469         return total ;
470 } /* g72x_write_block */
471
472 static sf_count_t
473 g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
474 {       G72x_PRIVATE    *pg72x ;
475         int                     writecount, count ;
476         sf_count_t      total = 0 ;
477
478         if (psf->fdata == NULL)
479                 return 0 ;
480         pg72x = (G72x_PRIVATE*) psf->fdata ;
481
482         while (len > 0)
483         {       writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
484
485                 count = g72x_write_block (psf, pg72x, ptr, writecount) ;
486
487                 total += count ;
488                 len -= count ;
489                 if (count != writecount)
490                         break ;
491                 } ;
492
493         return total ;
494 } /* g72x_write_s */
495
496 static sf_count_t
497 g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
498 {       G72x_PRIVATE *pg72x ;
499         short           *sptr ;
500         int                     k, bufferlen, writecount = 0, count ;
501         sf_count_t      total = 0 ;
502
503         if (psf->fdata == NULL)
504                 return 0 ;
505         pg72x = (G72x_PRIVATE*) psf->fdata ;
506
507         sptr = psf->u.sbuf ;
508         bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
509         while (len > 0)
510         {       writecount = (len >= bufferlen) ? bufferlen : len ;
511                 for (k = 0 ; k < writecount ; k++)
512                         sptr [k] = ptr [total + k] >> 16 ;
513                 count = g72x_write_block (psf, pg72x, sptr, writecount) ;
514
515                 total += count ;
516                 len -= writecount ;
517                 if (count != writecount)
518                         break ;
519                 } ;
520         return total ;
521 } /* g72x_write_i */
522
523 static sf_count_t
524 g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
525 {       G72x_PRIVATE *pg72x ;
526         short           *sptr ;
527         int                     k, bufferlen, writecount = 0, count ;
528         sf_count_t      total = 0 ;
529         float           normfact ;
530
531         if (psf->fdata == NULL)
532                 return 0 ;
533         pg72x = (G72x_PRIVATE*) psf->fdata ;
534
535         normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ;
536
537         sptr = psf->u.sbuf ;
538         bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
539         while (len > 0)
540         {       writecount = (len >= bufferlen) ? bufferlen : len ;
541                 for (k = 0 ; k < writecount ; k++)
542                         sptr [k] = lrintf (normfact * ptr [total + k]) ;
543                 count = g72x_write_block (psf, pg72x, sptr, writecount) ;
544
545                 total += count ;
546                 len -= writecount ;
547                 if (count != writecount)
548                         break ;
549                 } ;
550
551         return total ;
552 } /* g72x_write_f */
553
554 static sf_count_t
555 g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
556 {       G72x_PRIVATE *pg72x ;
557         short           *sptr ;
558         int                     k, bufferlen, writecount = 0, count ;
559         sf_count_t      total = 0 ;
560         double          normfact ;
561
562         if (psf->fdata == NULL)
563                 return 0 ;
564         pg72x = (G72x_PRIVATE*) psf->fdata ;
565
566         normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ;
567
568         sptr = psf->u.sbuf ;
569         bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
570         while (len > 0)
571         {       writecount = (len >= bufferlen) ? bufferlen : len ;
572                 for (k = 0 ; k < writecount ; k++)
573                         sptr [k] = lrint (normfact * ptr [total + k]) ;
574                 count = g72x_write_block (psf, pg72x, sptr, writecount) ;
575
576                 total += count ;
577                 len -= writecount ;
578                 if (count != writecount)
579                         break ;
580                 } ;
581
582         return total ;
583 } /* g72x_write_d */
584
585 static int
586 g72x_close (SF_PRIVATE *psf)
587 {       G72x_PRIVATE *pg72x ;
588
589         pg72x = (G72x_PRIVATE*) psf->fdata ;
590
591         if (psf->mode == SFM_WRITE)
592         {       /*      If a block has been partially assembled, write it out
593                 **      as the final block.
594                 */
595
596                 if (pg72x->sample_curr && pg72x->sample_curr < G72x_BLOCK_SIZE)
597                         psf_g72x_encode_block (psf, pg72x) ;
598
599                 if (psf->write_header)
600                         psf->write_header (psf, SF_FALSE) ;
601                 } ;
602
603         /* Only free the pointer allocated by g72x_(reader|writer)_init. */
604         free (pg72x->private) ;
605
606         return 0 ;
607 } /* g72x_close */
608
609 /*
610 ** Do not edit or modify anything in this comment block.
611 ** The arch-tag line is a file identity tag for the GNU Arch
612 ** revision control system.
613 **
614 ** arch-tag: 3cc5439e-7247-486b-b2e6-11a4affa5744
615 */