1 /* libSoX libsndfile formats.
2  *
3  * Copyright 2007 Reuben Thomas <rrt@sc3d.org>
4  * Copyright 1999-2005 Erik de Castro Lopo <eridk@mega-nerd.com>
5  *
6  * This library is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or (at
9  * your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "sox_i.h"
22 
23 #include <assert.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <sndfile.h>
28 
29 #define LOG_MAX 2048 /* As per the SFC_GET_LOG_INFO example */
30 
31 static const char* const sndfile_library_names[] =
32 {
33 #ifdef DL_LIBSNDFILE
34   "libsndfile",
35   "libsndfile-1",
36   "cygsndfile-1",
37 #endif
38   NULL
39 };
40 
41 #ifdef DL_LIBSNDFILE
42   #define SNDFILE_FUNC      LSX_DLENTRY_DYNAMIC
43   #define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB
44 #else
45   #define SNDFILE_FUNC      LSX_DLENTRY_STATIC
46 #ifdef HACKED_LSF
47   #define SNDFILE_FUNC_STOP LSX_DLENTRY_STATIC
48 #else
49   #define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB
50 #endif
51 #endif /* DL_LIBSNDFILE */
52 
53 #define SNDFILE_FUNC_OPEN(f,x) \
54   SNDFILE_FUNC(f,x, SNDFILE*, sf_open_virtual, (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data))
55 
56 #define SNDFILE_FUNC_ENTRIES(f,x) \
57   SNDFILE_FUNC_OPEN(f,x) \
58   SNDFILE_FUNC_STOP(f,x, int, sf_stop, (SNDFILE *sndfile)) \
59   SNDFILE_FUNC(f,x, int, sf_close, (SNDFILE *sndfile)) \
60   SNDFILE_FUNC(f,x, int, sf_format_check, (const SF_INFO *info)) \
61   SNDFILE_FUNC(f,x, int, sf_command, (SNDFILE *sndfile, int command, void *data, int datasize)) \
62   SNDFILE_FUNC(f,x, sf_count_t, sf_read_int, (SNDFILE *sndfile, int *ptr, sf_count_t items)) \
63   SNDFILE_FUNC(f,x, sf_count_t, sf_write_int, (SNDFILE *sndfile, const int *ptr, sf_count_t items)) \
64   SNDFILE_FUNC(f,x, sf_count_t, sf_seek, (SNDFILE *sndfile, sf_count_t frames, int whence)) \
65   SNDFILE_FUNC(f,x, const char*, sf_strerror, (SNDFILE *sndfile))
66 
67 /* Private data for sndfile files */
68 typedef struct {
69   SNDFILE *sf_file;
70   SF_INFO *sf_info;
71   char * log_buffer;
72   char const * log_buffer_ptr;
73   LSX_DLENTRIES_TO_PTRS(SNDFILE_FUNC_ENTRIES, sndfile_dl);
74 } priv_t;
75 
76 /*
77  * Drain LSF's wonderful log buffer
78  */
drain_log_buffer(sox_format_t * ft)79 static void drain_log_buffer(sox_format_t * ft)
80 {
81   priv_t * sf = (priv_t *)ft->priv;
82   sf->sf_command(sf->sf_file, SFC_GET_LOG_INFO, sf->log_buffer, LOG_MAX);
83   while (*sf->log_buffer_ptr) {
84     static char const warning_prefix[] = "*** Warning : ";
85     char const * end = strchr(sf->log_buffer_ptr, '\n');
86     if (!end)
87       end = strchr(sf->log_buffer_ptr, '\0');
88     if (!strncmp(sf->log_buffer_ptr, warning_prefix, strlen(warning_prefix))) {
89       sf->log_buffer_ptr += strlen(warning_prefix);
90       lsx_warn("`%s': %.*s",
91           ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr);
92     } else
93       lsx_debug("`%s': %.*s",
94           ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr);
95     sf->log_buffer_ptr = end;
96     if (*sf->log_buffer_ptr == '\n')
97       ++sf->log_buffer_ptr;
98   }
99 }
100 
101 /* Make libsndfile subtype from sample encoding and size */
ft_enc(unsigned size,sox_encoding_t e)102 static int ft_enc(unsigned size, sox_encoding_t e)
103 {
104   if (e == SOX_ENCODING_ULAW      && size ==  8) return SF_FORMAT_ULAW;
105   if (e == SOX_ENCODING_ALAW      && size ==  8) return SF_FORMAT_ALAW;
106   if (e == SOX_ENCODING_SIGN2     && size ==  8) return SF_FORMAT_PCM_S8;
107   if (e == SOX_ENCODING_SIGN2     && size == 16) return SF_FORMAT_PCM_16;
108   if (e == SOX_ENCODING_SIGN2     && size == 24) return SF_FORMAT_PCM_24;
109   if (e == SOX_ENCODING_SIGN2     && size == 32) return SF_FORMAT_PCM_32;
110   if (e == SOX_ENCODING_UNSIGNED  && size ==  8) return SF_FORMAT_PCM_U8;
111   if (e == SOX_ENCODING_FLOAT     && size == 32) return SF_FORMAT_FLOAT;
112   if (e == SOX_ENCODING_FLOAT     && size == 64) return SF_FORMAT_DOUBLE;
113   if (e == SOX_ENCODING_G721      && size ==  4) return SF_FORMAT_G721_32;
114   if (e == SOX_ENCODING_G723      && size ==  3) return SF_FORMAT_G723_24;
115   if (e == SOX_ENCODING_G723      && size ==  5) return SF_FORMAT_G723_40;
116   if (e == SOX_ENCODING_MS_ADPCM  && size ==  4) return SF_FORMAT_MS_ADPCM;
117   if (e == SOX_ENCODING_IMA_ADPCM && size ==  4) return SF_FORMAT_IMA_ADPCM;
118   if (e == SOX_ENCODING_OKI_ADPCM && size ==  4) return SF_FORMAT_VOX_ADPCM;
119   if (e == SOX_ENCODING_DPCM      && size ==  8) return SF_FORMAT_DPCM_8;
120   if (e == SOX_ENCODING_DPCM      && size == 16) return SF_FORMAT_DPCM_16;
121   if (e == SOX_ENCODING_DWVW      && size == 12) return SF_FORMAT_DWVW_12;
122   if (e == SOX_ENCODING_DWVW      && size == 16) return SF_FORMAT_DWVW_16;
123   if (e == SOX_ENCODING_DWVW      && size == 24) return SF_FORMAT_DWVW_24;
124   if (e == SOX_ENCODING_DWVWN     && size ==  0) return SF_FORMAT_DWVW_N;
125   if (e == SOX_ENCODING_GSM       && size ==  0) return SF_FORMAT_GSM610;
126   if (e == SOX_ENCODING_FLAC      && size ==  8) return SF_FORMAT_PCM_S8;
127   if (e == SOX_ENCODING_FLAC      && size == 16) return SF_FORMAT_PCM_16;
128   if (e == SOX_ENCODING_FLAC      && size == 24) return SF_FORMAT_PCM_24;
129   if (e == SOX_ENCODING_FLAC      && size == 32) return SF_FORMAT_PCM_32;
130   return 0; /* Bad encoding */
131 }
132 
133 /* Convert format's encoding type to libSoX encoding type & size. */
sox_enc(int ft_encoding,unsigned * size)134 static sox_encoding_t sox_enc(int ft_encoding, unsigned * size)
135 {
136   int sub = ft_encoding & SF_FORMAT_SUBMASK;
137   int type = ft_encoding & SF_FORMAT_TYPEMASK;
138 
139   if (type == SF_FORMAT_FLAC) switch (sub) {
140     case SF_FORMAT_PCM_S8   : *size =  8; return SOX_ENCODING_FLAC;
141     case SF_FORMAT_PCM_16   : *size = 16; return SOX_ENCODING_FLAC;
142     case SF_FORMAT_PCM_24   : *size = 24; return SOX_ENCODING_FLAC;
143   }
144   switch (sub) {
145     case SF_FORMAT_ULAW     : *size =  8; return SOX_ENCODING_ULAW;
146     case SF_FORMAT_ALAW     : *size =  8; return SOX_ENCODING_ALAW;
147     case SF_FORMAT_PCM_S8   : *size =  8; return SOX_ENCODING_SIGN2;
148     case SF_FORMAT_PCM_16   : *size = 16; return SOX_ENCODING_SIGN2;
149     case SF_FORMAT_PCM_24   : *size = 24; return SOX_ENCODING_SIGN2;
150     case SF_FORMAT_PCM_32   : *size = 32; return SOX_ENCODING_SIGN2;
151     case SF_FORMAT_PCM_U8   : *size =  8; return SOX_ENCODING_UNSIGNED;
152     case SF_FORMAT_FLOAT    : *size = 32; return SOX_ENCODING_FLOAT;
153     case SF_FORMAT_DOUBLE   : *size = 64; return SOX_ENCODING_FLOAT;
154     case SF_FORMAT_G721_32  : *size =  4; return SOX_ENCODING_G721;
155     case SF_FORMAT_G723_24  : *size =  3; return SOX_ENCODING_G723;
156     case SF_FORMAT_G723_40  : *size =  5; return SOX_ENCODING_G723;
157     case SF_FORMAT_MS_ADPCM : *size =  4; return SOX_ENCODING_MS_ADPCM;
158     case SF_FORMAT_IMA_ADPCM: *size =  4; return SOX_ENCODING_IMA_ADPCM;
159     case SF_FORMAT_VOX_ADPCM: *size =  4; return SOX_ENCODING_OKI_ADPCM;
160     case SF_FORMAT_DPCM_8   : *size =  8; return SOX_ENCODING_DPCM;
161     case SF_FORMAT_DPCM_16  : *size = 16; return SOX_ENCODING_DPCM;
162     case SF_FORMAT_DWVW_12  : *size = 12; return SOX_ENCODING_DWVW;
163     case SF_FORMAT_DWVW_16  : *size = 16; return SOX_ENCODING_DWVW;
164     case SF_FORMAT_DWVW_24  : *size = 24; return SOX_ENCODING_DWVW;
165     case SF_FORMAT_DWVW_N   : *size =  0; return SOX_ENCODING_DWVWN;
166     case SF_FORMAT_GSM610   : *size =  0; return SOX_ENCODING_GSM;
167     default                 : *size =  0; return SOX_ENCODING_UNKNOWN;
168   }
169 }
170 
171 static struct {
172   const char *ext;
173   int format;
174 } format_map[] =
175 {
176   { "aif",      SF_FORMAT_AIFF },
177   { "aiff",     SF_FORMAT_AIFF },
178   { "wav",      SF_FORMAT_WAV },
179   { "au",       SF_FORMAT_AU },
180   { "snd",      SF_FORMAT_AU },
181   { "caf",      SF_FORMAT_CAF },
182   { "flac",     SF_FORMAT_FLAC },
183   { "wve",      SF_FORMAT_WVE },
184   { "ogg",      SF_FORMAT_OGG },
185   { "svx",      SF_FORMAT_SVX },
186   { "8svx",     SF_FORMAT_SVX },
187   { "paf",      SF_ENDIAN_BIG | SF_FORMAT_PAF },
188   { "fap",      SF_ENDIAN_LITTLE | SF_FORMAT_PAF },
189   { "gsm",      SF_FORMAT_RAW | SF_FORMAT_GSM610 },
190   { "nist",     SF_FORMAT_NIST },
191   { "sph",      SF_FORMAT_NIST },
192   { "ircam",    SF_FORMAT_IRCAM },
193   { "sf",       SF_FORMAT_IRCAM },
194   { "voc",      SF_FORMAT_VOC },
195   { "w64",      SF_FORMAT_W64 },
196   { "raw",      SF_FORMAT_RAW },
197   { "mat4",     SF_FORMAT_MAT4 },
198   { "mat5",     SF_FORMAT_MAT5 },
199   { "mat",      SF_FORMAT_MAT4 },
200   { "pvf",      SF_FORMAT_PVF },
201   { "sds",      SF_FORMAT_SDS },
202   { "sd2",      SF_FORMAT_SD2 },
203   { "vox",      SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM },
204   { "xi",       SF_FORMAT_XI }
205 };
206 
sf_stop_stub(SNDFILE * sndfile UNUSED)207 static int sf_stop_stub(SNDFILE *sndfile UNUSED)
208 {
209     return 1;
210 }
211 
vio_get_filelen(void * user_data)212 static sf_count_t vio_get_filelen(void *user_data)
213 {
214   sox_format_t *ft = (sox_format_t *)user_data;
215 
216   /* lsf excepts unbuffered I/O behavior for get_filelen() so force that */
217   lsx_flush(ft);
218 
219   return (sf_count_t)lsx_filelength((sox_format_t *)user_data);
220 }
221 
vio_seek(sf_count_t offset,int whence,void * user_data)222 static sf_count_t vio_seek(sf_count_t offset, int whence, void *user_data)
223 {
224     return lsx_seeki((sox_format_t *)user_data, (off_t)offset, whence);
225 }
226 
vio_read(void * ptr,sf_count_t count,void * user_data)227 static sf_count_t vio_read(void *ptr, sf_count_t count, void *user_data)
228 {
229     return lsx_readbuf((sox_format_t *)user_data, ptr, (size_t)count);
230 }
231 
vio_write(const void * ptr,sf_count_t count,void * user_data)232 static sf_count_t vio_write(const void *ptr, sf_count_t count, void *user_data)
233 {
234     return lsx_writebuf((sox_format_t *)user_data, ptr, (size_t)count);
235 }
236 
vio_tell(void * user_data)237 static sf_count_t vio_tell(void *user_data)
238 {
239     return lsx_tell((sox_format_t *)user_data);
240 }
241 
242 static SF_VIRTUAL_IO vio =
243 {
244     vio_get_filelen,
245     vio_seek,
246     vio_read,
247     vio_write,
248     vio_tell
249 };
250 
251 /* Convert file name or type to libsndfile format */
name_to_format(const char * name)252 static int name_to_format(const char *name)
253 {
254   int k;
255 #define FILE_TYPE_BUFLEN (size_t)15
256   char buffer[FILE_TYPE_BUFLEN + 1], *cptr;
257 
258   if ((cptr = strrchr(name, '.')) != NULL) {
259     strncpy(buffer, cptr + 1, FILE_TYPE_BUFLEN);
260     buffer[FILE_TYPE_BUFLEN] = '\0';
261 
262     for (k = 0; buffer[k]; k++)
263       buffer[k] = tolower((buffer[k]));
264   } else {
265     strncpy(buffer, name, FILE_TYPE_BUFLEN);
266     buffer[FILE_TYPE_BUFLEN] = '\0';
267   }
268 
269   for (k = 0; k < (int)(sizeof(format_map) / sizeof(format_map [0])); k++) {
270     if (strcmp(buffer, format_map[k].ext) == 0)
271       return format_map[k].format;
272   }
273 
274   return 0;
275 }
276 
start(sox_format_t * ft)277 static int start(sox_format_t * ft)
278 {
279   priv_t * sf = (priv_t *)ft->priv;
280   int subtype = ft_enc(ft->encoding.bits_per_sample? ft->encoding.bits_per_sample : ft->signal.precision, ft->encoding.encoding);
281   int open_library_result;
282 
283   LSX_DLLIBRARY_OPEN(
284       sf,
285       sndfile_dl,
286       SNDFILE_FUNC_ENTRIES,
287       "libsndfile library",
288       sndfile_library_names,
289       open_library_result);
290   if (open_library_result)
291     return SOX_EOF;
292 
293   sf->log_buffer_ptr = sf->log_buffer = lsx_malloc((size_t)LOG_MAX);
294   sf->sf_info = lsx_calloc(1, sizeof(SF_INFO));
295 
296   /* Copy format info */
297   if (subtype) {
298     if (strcmp(ft->filetype, "sndfile") == 0)
299       sf->sf_info->format = name_to_format(ft->filename) | subtype;
300     else
301       sf->sf_info->format = name_to_format(ft->filetype) | subtype;
302   }
303   sf->sf_info->samplerate = (int)ft->signal.rate;
304   sf->sf_info->channels = ft->signal.channels;
305   if (ft->signal.channels)
306     sf->sf_info->frames = ft->signal.length / ft->signal.channels;
307 
308   return SOX_SUCCESS;
309 }
310 
check_read_params(sox_format_t * ft,unsigned channels,sox_rate_t rate,sox_encoding_t encoding,unsigned bits_per_sample,uint64_t length)311 static int check_read_params(sox_format_t * ft, unsigned channels,
312     sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, uint64_t length)
313 {
314   ft->signal.length = length;
315 
316   if (channels && ft->signal.channels && ft->signal.channels != channels)
317     lsx_warn("`%s': overriding number of channels", ft->filename);
318   else ft->signal.channels = channels;
319 
320   if (rate && ft->signal.rate && ft->signal.rate != rate)
321     lsx_warn("`%s': overriding sample rate", ft->filename);
322   else ft->signal.rate = rate;
323 
324   if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding)
325     lsx_warn("`%s': overriding encoding type", ft->filename);
326   else ft->encoding.encoding = encoding;
327 
328   if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample)
329     lsx_warn("`%s': overriding encoding size", ft->filename);
330   ft->encoding.bits_per_sample = bits_per_sample;
331 
332   if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
333     return SOX_SUCCESS;
334   lsx_fail_errno(ft, EINVAL, "invalid format for this file type");
335   return SOX_EOF;
336 }
337 
338 /*
339  * Open file in sndfile.
340  */
startread(sox_format_t * ft)341 static int startread(sox_format_t * ft)
342 {
343   priv_t * sf = (priv_t *)ft->priv;
344   unsigned bits_per_sample;
345   sox_encoding_t encoding;
346   sox_rate_t rate;
347 
348   if (start(ft) == SOX_EOF)
349       return SOX_EOF;
350 
351   sf->sf_file = sf->sf_open_virtual(&vio, SFM_READ, sf->sf_info, ft);
352   drain_log_buffer(ft);
353 
354   if (sf->sf_file == NULL) {
355     memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr));
356     strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1);
357     free(sf->sf_file);
358     return SOX_EOF;
359   }
360 
361   if (!(encoding = sox_enc(sf->sf_info->format, &bits_per_sample))) {
362     lsx_fail_errno(ft, SOX_EFMT, "unsupported sndfile encoding %#x", sf->sf_info->format);
363     return SOX_EOF;
364   }
365 
366   /* Don't believe LSF's rate for raw files */
367   if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW && !ft->signal.rate) {
368     lsx_warn("`%s': sample rate not specified; trying 8kHz", ft->filename);
369     rate = 8000;
370   }
371   else rate = sf->sf_info->samplerate;
372 
373   if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) {
374     sf->sf_command(sf->sf_file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
375     sf->sf_command(sf->sf_file, SFC_SET_CLIPPING, NULL, SF_TRUE);
376   }
377 
378 #if 0 /* FIXME */
379     sox_append_comments(&ft->oob.comments, buf);
380 #endif
381 
382   return check_read_params(ft, (unsigned)sf->sf_info->channels, rate,
383       encoding, bits_per_sample, (uint64_t)(sf->sf_info->frames * sf->sf_info->channels));
384 }
385 
386 /*
387  * Read up to len samples of type sox_sample_t from file into buf[].
388  * Return number of samples read.
389  */
read_samples(sox_format_t * ft,sox_sample_t * buf,size_t len)390 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
391 {
392   priv_t * sf = (priv_t *)ft->priv;
393   /* FIXME: We assume int == sox_sample_t here */
394   return (size_t)sf->sf_read_int(sf->sf_file, (int *)buf, (sf_count_t)len);
395 }
396 
397 /*
398  * Close file for libsndfile (this doesn't close the file handle)
399  */
stopread(sox_format_t * ft)400 static int stopread(sox_format_t * ft)
401 {
402   priv_t * sf = (priv_t *)ft->priv;
403   sf->sf_stop(sf->sf_file);
404   drain_log_buffer(ft);
405   sf->sf_close(sf->sf_file);
406   LSX_DLLIBRARY_CLOSE(sf, sndfile_dl);
407   return SOX_SUCCESS;
408 }
409 
startwrite(sox_format_t * ft)410 static int startwrite(sox_format_t * ft)
411 {
412   priv_t * sf = (priv_t *)ft->priv;
413 
414   if (start(ft) == SOX_EOF)
415       return SOX_EOF;
416 
417   /* If output format is invalid, try to find a sensible default */
418   if (!sf->sf_format_check(sf->sf_info)) {
419     SF_FORMAT_INFO format_info;
420     int i, count;
421 
422     sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT_COUNT, &count, (int) sizeof(int));
423     for (i = 0; i < count; i++) {
424       format_info.format = i;
425       sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT, &format_info, (int) sizeof(format_info));
426       if ((format_info.format & SF_FORMAT_TYPEMASK) == (sf->sf_info->format & SF_FORMAT_TYPEMASK)) {
427         sf->sf_info->format = format_info.format;
428         /* FIXME: Print out exactly what we chose, needs sndfile ->
429            sox encoding conversion functions */
430         break;
431       }
432     }
433 
434     if (!sf->sf_format_check(sf->sf_info)) {
435       lsx_fail("cannot find a usable output encoding");
436       return SOX_EOF;
437     }
438     if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW)
439       lsx_warn("cannot use desired output encoding, choosing default");
440   }
441 
442   sf->sf_file = sf->sf_open_virtual(&vio, SFM_WRITE, sf->sf_info, ft);
443   drain_log_buffer(ft);
444 
445   if (sf->sf_file == NULL) {
446     memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr));
447     strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1);
448     free(sf->sf_file);
449     return SOX_EOF;
450   }
451 
452   if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT)
453     sf->sf_command(sf->sf_file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE);
454 
455   return SOX_SUCCESS;
456 }
457 
458 /*
459  * Write len samples of type sox_sample_t from buf[] to file.
460  * Return number of samples written.
461  */
write_samples(sox_format_t * ft,const sox_sample_t * buf,size_t len)462 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len)
463 {
464   priv_t * sf = (priv_t *)ft->priv;
465   /* FIXME: We assume int == sox_sample_t here */
466   return (size_t)sf->sf_write_int(sf->sf_file, (int *)buf, (sf_count_t)len);
467 }
468 
469 /*
470  * Close file for libsndfile (this doesn't close the file handle)
471  */
stopwrite(sox_format_t * ft)472 static int stopwrite(sox_format_t * ft)
473 {
474   priv_t * sf = (priv_t *)ft->priv;
475   sf->sf_stop(sf->sf_file);
476   drain_log_buffer(ft);
477   sf->sf_close(sf->sf_file);
478   LSX_DLLIBRARY_CLOSE(sf, sndfile_dl);
479   return SOX_SUCCESS;
480 }
481 
seek(sox_format_t * ft,uint64_t offset)482 static int seek(sox_format_t * ft, uint64_t offset)
483 {
484   priv_t * sf = (priv_t *)ft->priv;
485   sf->sf_seek(sf->sf_file, (sf_count_t)(offset / ft->signal.channels), SEEK_CUR);
486   return SOX_SUCCESS;
487 }
488 
LSX_FORMAT_HANDLER(sndfile)489 LSX_FORMAT_HANDLER(sndfile)
490 {
491   static char const * const names[] = {
492     "sndfile", /* Special type to force use of sndfile for the following: */
493   /* LSF implementation of formats built in to SoX: */
494     /* "aif", */
495     /* "au", */
496     /* "gsm", */
497     /* "nist", */
498     /* "raw", */
499     /* "sf", "ircam", */
500     /* "snd", */
501     /* "svx", */
502     /* "voc", */
503     /* "vox", */
504     /* "wav", */
505   /* LSF wrappers of formats already wrapped in SoX: */
506     /* "flac", */
507 
508     "sds",  /* ?? */
509     NULL
510   };
511 
512   static unsigned const write_encodings[] = {
513     SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0,
514     SOX_ENCODING_UNSIGNED, 8, 0,
515     SOX_ENCODING_FLOAT, 32, 64, 0,
516     SOX_ENCODING_ALAW, 8, 0,
517     SOX_ENCODING_ULAW, 8, 0,
518     SOX_ENCODING_IMA_ADPCM, 4, 0,
519     SOX_ENCODING_MS_ADPCM, 4, 0,
520     SOX_ENCODING_OKI_ADPCM, 4, 0,
521     SOX_ENCODING_GSM, 0,
522     0};
523 
524   static sox_format_handler_t const format = {SOX_LIB_VERSION_CODE,
525     "Pseudo format to use libsndfile", names, 0,
526     startread, read_samples, stopread,
527     startwrite, write_samples, stopwrite,
528     seek, write_encodings, NULL, sizeof(priv_t)
529   };
530 
531   return &format;
532 }
533