add libsndfile directory
[ardour.git] / libs / libsndfile / src / gsm610.c
1 /*
2 ** Copyright (C) 1999-2006 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 "wav_w64.h"
30 #include "GSM610/gsm.h"
31
32 #define GSM610_BLOCKSIZE                33
33 #define GSM610_SAMPLES                  160
34
35 typedef struct gsm610_tag
36 {       int                             blocks ;
37         int                             blockcount, samplecount ;
38         int                             samplesperblock, blocksize ;
39
40         int                             (*decode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ;
41         int                             (*encode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ;
42
43         short                   samples [WAV_W64_GSM610_SAMPLES] ;
44         unsigned char   block [WAV_W64_GSM610_BLOCKSIZE] ;
45
46         /* Damn I hate typedef-ed pointers; yes, gsm is a pointer type. */
47         gsm                             gsm_data ;
48 } GSM610_PRIVATE ;
49
50 static sf_count_t       gsm610_read_s   (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
51 static sf_count_t       gsm610_read_i   (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
52 static sf_count_t       gsm610_read_f   (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
53 static sf_count_t       gsm610_read_d   (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
54
55 static sf_count_t       gsm610_write_s  (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
56 static sf_count_t       gsm610_write_i  (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
57 static sf_count_t       gsm610_write_f  (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
58 static sf_count_t       gsm610_write_d  (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
59
60 static  int gsm610_read_block   (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) ;
61 static  int gsm610_write_block  (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) ;
62
63 static  int     gsm610_decode_block     (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
64 static  int     gsm610_encode_block     (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
65
66 static  int     gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
67 static  int     gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
68
69 static sf_count_t       gsm610_seek     (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
70
71 static int      gsm610_close    (SF_PRIVATE *psf) ;
72
73 /*============================================================================================
74 ** WAV GSM610 initialisation function.
75 */
76
77 int
78 gsm610_init     (SF_PRIVATE *psf)
79 {       GSM610_PRIVATE  *pgsm610 ;
80         int             true_flag = 1 ;
81
82         if (psf->fdata != NULL)
83         {       psf_log_printf (psf, "*** psf->fdata is not NULL.\n") ;
84                 return SFE_INTERNAL ;
85                 } ;
86
87         if (psf->mode == SFM_RDWR)
88                 return SFE_BAD_MODE_RW ;
89
90         psf->sf.seekable = SF_FALSE ;
91
92         if ((pgsm610 = calloc (1, sizeof (GSM610_PRIVATE))) == NULL)
93                 return SFE_MALLOC_FAILED ;
94
95         psf->fdata = (void*) pgsm610 ;
96
97         memset (pgsm610, 0, sizeof (GSM610_PRIVATE)) ;
98
99 /*============================================================
100
101 Need separate gsm_data structs for encode and decode.
102
103 ============================================================*/
104
105         if ((pgsm610->gsm_data = gsm_create ()) == NULL)
106                 return SFE_MALLOC_FAILED ;
107
108         switch (psf->sf.format & SF_FORMAT_TYPEMASK)
109         {       case SF_FORMAT_WAV :
110                 case SF_FORMAT_WAVEX :
111                 case SF_FORMAT_W64 :
112                         gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ;
113
114                         pgsm610->encode_block = gsm610_wav_encode_block ;
115                         pgsm610->decode_block = gsm610_wav_decode_block ;
116
117                         pgsm610->samplesperblock = WAV_W64_GSM610_SAMPLES ;
118                         pgsm610->blocksize = WAV_W64_GSM610_BLOCKSIZE ;
119                         break ;
120
121                 case SF_FORMAT_AIFF :
122                 case SF_FORMAT_RAW :
123                         pgsm610->encode_block = gsm610_encode_block ;
124                         pgsm610->decode_block = gsm610_decode_block ;
125
126                         pgsm610->samplesperblock = GSM610_SAMPLES ;
127                         pgsm610->blocksize = GSM610_BLOCKSIZE ;
128                         break ;
129
130                 default :
131                         return SFE_INTERNAL ;
132                         break ;
133                 } ;
134
135         if (psf->mode == SFM_READ)
136         {       if (psf->datalength % pgsm610->blocksize == 0)
137                         pgsm610->blocks = psf->datalength / pgsm610->blocksize ;
138                 else if (psf->datalength % pgsm610->blocksize == 1 && pgsm610->blocksize == GSM610_BLOCKSIZE)
139                 {       /*
140                         **      Weird AIFF specific case.
141                         **      AIFF chunks must be at an odd offset from the start of file and
142                         **      GSM610_BLOCKSIZE is odd which can result in an odd length SSND
143                         **      chunk. The SSND chunk then gets padded on write which means that
144                         **      when it is read the datalength is too big by 1.
145                         */
146                         pgsm610->blocks = psf->datalength / pgsm610->blocksize ;
147                         }
148                 else
149                 {       psf_log_printf (psf, "*** Warning : data chunk seems to be truncated.\n") ;
150                         pgsm610->blocks = psf->datalength / pgsm610->blocksize + 1 ;
151                         } ;
152
153                 psf->sf.frames = pgsm610->samplesperblock * pgsm610->blocks ;
154
155                 pgsm610->decode_block (psf, pgsm610) ;  /* Read first block. */
156
157                 psf->read_short         = gsm610_read_s ;
158                 psf->read_int           = gsm610_read_i ;
159                 psf->read_float         = gsm610_read_f ;
160                 psf->read_double        = gsm610_read_d ;
161                 } ;
162
163         if (psf->mode == SFM_WRITE)
164         {       pgsm610->blockcount = 0 ;
165                 pgsm610->samplecount = 0 ;
166
167                 psf->write_short        = gsm610_write_s ;
168                 psf->write_int          = gsm610_write_i ;
169                 psf->write_float        = gsm610_write_f ;
170                 psf->write_double       = gsm610_write_d ;
171                 } ;
172
173         psf->codec_close = gsm610_close ;
174
175         psf->seek = gsm610_seek ;
176
177         psf->filelength = psf_get_filelen (psf) ;
178         psf->datalength = psf->filelength - psf->dataoffset ;
179
180         return 0 ;
181 } /* gsm610_init */
182
183 /*============================================================================================
184 ** GSM 6.10 Read Functions.
185 */
186
187 static int
188 gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
189 {       int     k ;
190
191         pgsm610->blockcount ++ ;
192         pgsm610->samplecount = 0 ;
193
194         if (pgsm610->blockcount > pgsm610->blocks)
195         {       memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
196                 return 1 ;
197                 } ;
198
199         if ((k = psf_fread (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
200                 psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
201
202         if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0)
203         {       psf_log_printf (psf, "Error from gsm_decode() on frame : %d\n", pgsm610->blockcount) ;
204                 return 0 ;
205                 } ;
206
207         if (gsm_decode (pgsm610->gsm_data, pgsm610->block + (WAV_W64_GSM610_BLOCKSIZE + 1) / 2, pgsm610->samples + WAV_W64_GSM610_SAMPLES / 2) < 0)
208         {       psf_log_printf (psf, "Error from gsm_decode() on frame : %d.5\n", pgsm610->blockcount) ;
209                 return 0 ;
210                 } ;
211
212         return 1 ;
213 } /* gsm610_wav_decode_block */
214
215 static int
216 gsm610_decode_block     (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
217 {       int     k ;
218
219         pgsm610->blockcount ++ ;
220         pgsm610->samplecount = 0 ;
221
222         if (pgsm610->blockcount > pgsm610->blocks)
223         {       memset (pgsm610->samples, 0, GSM610_SAMPLES * sizeof (short)) ;
224                 return 1 ;
225                 } ;
226
227         if ((k = psf_fread (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE)
228                 psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, GSM610_BLOCKSIZE) ;
229
230         if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0)
231         {       psf_log_printf (psf, "Error from gsm_decode() on frame : %d\n", pgsm610->blockcount) ;
232                 return 0 ;
233                 } ;
234
235         return 1 ;
236 } /* gsm610_decode_block */
237
238 static int
239 gsm610_read_block       (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len)
240 {       int     count, total = 0, indx = 0 ;
241
242         while (indx < len)
243         {       if (pgsm610->blockcount >= pgsm610->blocks && pgsm610->samplecount >= pgsm610->samplesperblock)
244                 {       memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ;
245                         return total ;
246                         } ;
247
248                 if (pgsm610->samplecount >= pgsm610->samplesperblock)
249                         pgsm610->decode_block (psf, pgsm610) ;
250
251                 count = pgsm610->samplesperblock - pgsm610->samplecount ;
252                 count = (len - indx > count) ? count : len - indx ;
253
254                 memcpy (&(ptr [indx]), &(pgsm610->samples [pgsm610->samplecount]), count * sizeof (short)) ;
255                 indx += count ;
256                 pgsm610->samplecount += count ;
257                 total = indx ;
258                 } ;
259
260         return total ;
261 } /* gsm610_read_block */
262
263 static sf_count_t
264 gsm610_read_s   (SF_PRIVATE *psf, short *ptr, sf_count_t len)
265 {       GSM610_PRIVATE  *pgsm610 ;
266         int                     readcount, count ;
267         sf_count_t      total = 0 ;
268
269         if (psf->fdata == NULL)
270                 return 0 ;
271         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
272
273         while (len > 0)
274         {       readcount = (len > 0x10000000) ? 0x1000000 : (int) len ;
275
276                 count = gsm610_read_block (psf, pgsm610, ptr, readcount) ;
277
278                 total += count ;
279                 len -= count ;
280
281                 if (count != readcount)
282                         break ;
283                 } ;
284
285         return total ;
286 } /* gsm610_read_s */
287
288 static sf_count_t
289 gsm610_read_i   (SF_PRIVATE *psf, int *ptr, sf_count_t len)
290 {       GSM610_PRIVATE *pgsm610 ;
291         short           *sptr ;
292         int                     k, bufferlen, readcount = 0, count ;
293         sf_count_t      total = 0 ;
294
295         if (psf->fdata == NULL)
296                 return 0 ;
297         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
298
299         sptr = psf->u.sbuf ;
300         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
301         while (len > 0)
302         {       readcount = (len >= bufferlen) ? bufferlen : len ;
303                 count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
304                 for (k = 0 ; k < readcount ; k++)
305                         ptr [total + k] = sptr [k] << 16 ;
306
307                 total += count ;
308                 len -= readcount ;
309                 } ;
310         return total ;
311 } /* gsm610_read_i */
312
313 static sf_count_t
314 gsm610_read_f   (SF_PRIVATE *psf, float *ptr, sf_count_t len)
315 {       GSM610_PRIVATE *pgsm610 ;
316         short           *sptr ;
317         int                     k, bufferlen, readcount = 0, count ;
318         sf_count_t      total = 0 ;
319         float           normfact ;
320
321         if (psf->fdata == NULL)
322                 return 0 ;
323         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
324
325         normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
326
327         sptr = psf->u.sbuf ;
328         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
329         while (len > 0)
330         {       readcount = (len >= bufferlen) ? bufferlen : len ;
331                 count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
332                 for (k = 0 ; k < readcount ; k++)
333                         ptr [total + k] = normfact * sptr [k] ;
334
335                 total += count ;
336                 len -= readcount ;
337                 } ;
338         return total ;
339 } /* gsm610_read_f */
340
341 static sf_count_t
342 gsm610_read_d   (SF_PRIVATE *psf, double *ptr, sf_count_t len)
343 {       GSM610_PRIVATE *pgsm610 ;
344         short           *sptr ;
345         int                     k, bufferlen, readcount = 0, count ;
346         sf_count_t      total = 0 ;
347         double          normfact ;
348
349         normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
350
351         if (psf->fdata == NULL)
352                 return 0 ;
353         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
354
355         sptr = psf->u.sbuf ;
356         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
357         while (len > 0)
358         {       readcount = (len >= bufferlen) ? bufferlen : len ;
359                 count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
360                 for (k = 0 ; k < readcount ; k++)
361                         ptr [total + k] = normfact * sptr [k] ;
362
363                 total += count ;
364                 len -= readcount ;
365                 } ;
366         return total ;
367 } /* gsm610_read_d */
368
369 static sf_count_t
370 gsm610_seek     (SF_PRIVATE *psf, int mode, sf_count_t offset)
371 {       GSM610_PRIVATE *pgsm610 ;
372         int                     newblock, newsample ;
373
374         mode = mode ;
375
376         if (psf->fdata == NULL)
377                 return 0 ;
378         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
379
380         if (psf->dataoffset < 0)
381         {       psf->error = SFE_BAD_SEEK ;
382                 return  PSF_SEEK_ERROR ;
383                 } ;
384
385         if (offset == 0)
386         {       int true_flag = 1 ;
387
388                 psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
389                 pgsm610->blockcount = 0 ;
390
391                 gsm_init (pgsm610->gsm_data) ;
392                 if ((psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
393                                 (psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_W64)
394                         gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ;
395
396                 pgsm610->decode_block (psf, pgsm610) ;
397                 pgsm610->samplecount = 0 ;
398                 return 0 ;
399                 } ;
400
401         if (offset < 0 || offset > pgsm610->blocks * pgsm610->samplesperblock)
402         {       psf->error = SFE_BAD_SEEK ;
403                 return  PSF_SEEK_ERROR ;
404                 } ;
405
406         newblock        = offset / pgsm610->samplesperblock ;
407         newsample       = offset % pgsm610->samplesperblock ;
408
409         if (psf->mode == SFM_READ)
410         {       if (psf->read_current != newblock * pgsm610->samplesperblock + newsample)
411                 {       psf_fseek (psf, psf->dataoffset + newblock * pgsm610->samplesperblock, SEEK_SET) ;
412                         pgsm610->blockcount = newblock ;
413                         pgsm610->decode_block (psf, pgsm610) ;
414                         pgsm610->samplecount = newsample ;
415                         } ;
416
417                 return newblock * pgsm610->samplesperblock + newsample ;
418                 } ;
419
420         /* What to do about write??? */
421         psf->error = SFE_BAD_SEEK ;
422         return  PSF_SEEK_ERROR ;
423 } /* gsm610_seek */
424
425 /*==========================================================================================
426 ** GSM 6.10 Write Functions.
427 */
428
429 static int
430 gsm610_encode_block     (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
431 {       int k ;
432
433         /* Encode the samples. */
434         gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ;
435
436         /* Write the block to disk. */
437         if ((k = psf_fwrite (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE)
438                 psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, GSM610_BLOCKSIZE) ;
439
440         pgsm610->samplecount = 0 ;
441         pgsm610->blockcount ++ ;
442
443         /* Set samples to zero for next block. */
444         memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
445
446         return 1 ;
447 } /* gsm610_encode_block */
448
449 static int
450 gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
451 {       int k ;
452
453         /* Encode the samples. */
454         gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ;
455         gsm_encode (pgsm610->gsm_data, pgsm610->samples+WAV_W64_GSM610_SAMPLES/2, pgsm610->block+WAV_W64_GSM610_BLOCKSIZE/2) ;
456
457         /* Write the block to disk. */
458         if ((k = psf_fwrite (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
459                 psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
460
461         pgsm610->samplecount = 0 ;
462         pgsm610->blockcount ++ ;
463
464         /* Set samples to zero for next block. */
465         memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
466
467         return 1 ;
468 } /* gsm610_wav_encode_block */
469
470 static int
471 gsm610_write_block      (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len)
472 {       int             count, total = 0, indx = 0 ;
473
474         while (indx < len)
475         {       count = pgsm610->samplesperblock - pgsm610->samplecount ;
476
477                 if (count > len - indx)
478                         count = len - indx ;
479
480                 memcpy (&(pgsm610->samples [pgsm610->samplecount]), &(ptr [indx]), count * sizeof (short)) ;
481                 indx += count ;
482                 pgsm610->samplecount += count ;
483                 total = indx ;
484
485                 if (pgsm610->samplecount >= pgsm610->samplesperblock)
486                         pgsm610->encode_block (psf, pgsm610) ;
487                 } ;
488
489         return total ;
490 } /* gsm610_write_block */
491
492 static sf_count_t
493 gsm610_write_s  (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
494 {       GSM610_PRIVATE  *pgsm610 ;
495         int                     writecount, count ;
496         sf_count_t      total = 0 ;
497
498         if (psf->fdata == NULL)
499                 return 0 ;
500         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
501
502         while (len > 0)
503         {       writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
504
505                 count = gsm610_write_block (psf, pgsm610, ptr, writecount) ;
506
507                 total += count ;
508                 len -= count ;
509
510                 if (count != writecount)
511                         break ;
512                 } ;
513
514         return total ;
515 } /* gsm610_write_s */
516
517 static sf_count_t
518 gsm610_write_i  (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
519 {       GSM610_PRIVATE *pgsm610 ;
520         short           *sptr ;
521         int                     k, bufferlen, writecount = 0, count ;
522         sf_count_t      total = 0 ;
523
524         if (psf->fdata == NULL)
525                 return 0 ;
526         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
527
528         sptr = psf->u.sbuf ;
529         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
530         while (len > 0)
531         {       writecount = (len >= bufferlen) ? bufferlen : len ;
532                 for (k = 0 ; k < writecount ; k++)
533                         sptr [k] = ptr [total + k] >> 16 ;
534                 count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
535
536                 total += count ;
537                 len -= writecount ;
538                 } ;
539         return total ;
540 } /* gsm610_write_i */
541
542 static sf_count_t
543 gsm610_write_f  (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
544 {       GSM610_PRIVATE *pgsm610 ;
545         short           *sptr ;
546         int                     k, bufferlen, writecount = 0, count ;
547         sf_count_t      total = 0 ;
548         float           normfact ;
549
550         if (psf->fdata == NULL)
551                 return 0 ;
552         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
553
554         normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
555
556         sptr = psf->u.sbuf ;
557         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
558         while (len > 0)
559         {       writecount = (len >= bufferlen) ? bufferlen : len ;
560                 for (k = 0 ; k < writecount ; k++)
561                         sptr [k] = lrintf (normfact * ptr [total + k]) ;
562                 count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
563
564                 total += count ;
565                 len -= writecount ;
566                 } ;
567         return total ;
568 } /* gsm610_write_f */
569
570 static sf_count_t
571 gsm610_write_d  (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
572 {       GSM610_PRIVATE *pgsm610 ;
573         short           *sptr ;
574         int                     k, bufferlen, writecount = 0, count ;
575         sf_count_t      total = 0 ;
576         double          normfact ;
577
578         if (psf->fdata == NULL)
579                 return 0 ;
580         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
581
582         normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
583
584         sptr = psf->u.sbuf ;
585         bufferlen = ARRAY_LEN (psf->u.sbuf) ;
586         while (len > 0)
587         {       writecount = (len >= bufferlen) ? bufferlen : len ;
588                 for (k = 0 ; k < writecount ; k++)
589                         sptr [k] = lrint (normfact * ptr [total + k]) ;
590                 count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
591
592                 total += count ;
593                 len -= writecount ;
594                 } ;
595         return total ;
596 } /* gsm610_write_d */
597
598 static int
599 gsm610_close    (SF_PRIVATE *psf)
600 {       GSM610_PRIVATE *pgsm610 ;
601
602         if (psf->fdata == NULL)
603                 return 0 ;
604
605         pgsm610 = (GSM610_PRIVATE*) psf->fdata ;
606
607         if (psf->mode == SFM_WRITE)
608         {       /*      If a block has been partially assembled, write it out
609                 **      as the final block.
610                 */
611
612                 if (pgsm610->samplecount && pgsm610->samplecount < pgsm610->samplesperblock)
613                         pgsm610->encode_block (psf, pgsm610) ;
614                 } ;
615
616         if (pgsm610->gsm_data)
617                 gsm_destroy (pgsm610->gsm_data) ;
618
619         return 0 ;
620 } /* gsm610_close */
621
622 /*
623 ** Do not edit or modify anything in this comment block.
624 ** The arch-tag line is a file identity tag for the GNU Arch 
625 ** revision control system.
626 **
627 ** arch-tag: 8575187d-af4f-4acf-b9dd-6ff705628345
628 */