README.osx wasn't easily readable in Finder. Revert back to
[sox.git] / src / formats.c
blob3a6ac33a50c18e1e39572b4a23e5b3b69f0a14c7
1 /* Implements the public API for using libSoX file formats.
2 * All public functions & data are prefixed with sox_ .
4 * (c) 2005-8 Chris Bagwell and SoX contributors
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.
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.
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
21 #include "sox_i.h"
23 #include <assert.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
32 #ifdef HAVE_IO_H
33 #include <io.h>
34 #endif
36 #if HAVE_MAGIC
37 #include <magic.h>
38 #endif
40 #define AUTO_DETECT_SIZE 256
42 static char const * auto_detect_format(sox_format_t * ft, char const * ext)
44 char data[AUTO_DETECT_SIZE];
45 size_t len = lsx_readbuf(ft, data, sizeof(data));
46 #define CHECK(type, p2, l2, d2, p1, l1, d1) if (len >= p1 + l1 && \
47 !memcmp(data + p1, d1, (size_t)l1) && !memcmp(data + p2, d2, (size_t)l2)) return #type;
48 CHECK(voc , 0, 0, "" , 0, 20, "Creative Voice File\x1a")
49 CHECK(smp , 0, 0, "" , 0, 17, "SOUND SAMPLE DATA")
50 CHECK(wve , 0, 0, "" , 0, 15, "ALawSoundFile**")
51 CHECK(gsrt , 0, 0, "" , 16, 9, "ring.bin")
52 CHECK(amr-wb, 0, 0, "" , 0, 9, "#!AMR-WB\n")
53 CHECK(prc , 0, 0, "" , 0, 8, "\x37\x00\x00\x10\x6d\x00\x00\x10")
54 CHECK(sph , 0, 0, "" , 0, 7, "NIST_1A")
55 CHECK(amr-nb, 0, 0, "" , 0, 6, "#!AMR\n")
56 CHECK(txw , 0, 0, "" , 0, 6, "LM8953")
57 CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a")
58 CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis")
59 CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex")
60 CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM")
61 CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE")
62 CHECK(wav , 0, 4, "RIFX" , 8, 4, "WAVE")
63 CHECK(aiff , 0, 4, "FORM" , 8, 4, "AIFF")
64 CHECK(aifc , 0, 4, "FORM" , 8, 4, "AIFC")
65 CHECK(8svx , 0, 4, "FORM" , 8, 4, "8SVX")
66 CHECK(maud , 0, 4, "FORM" , 8, 4, "MAUD")
67 CHECK(xa , 0, 0, "" , 0, 4, "XA\0\0")
68 CHECK(xa , 0, 0, "" , 0, 4, "XAI\0")
69 CHECK(xa , 0, 0, "" , 0, 4, "XAJ\0")
70 CHECK(au , 0, 0, "" , 0, 4, ".snd")
71 CHECK(au , 0, 0, "" , 0, 4, "dns.")
72 CHECK(au , 0, 0, "" , 0, 4, "\0ds.")
73 CHECK(au , 0, 0, "" , 0, 4, ".sd\0")
74 CHECK(flac , 0, 0, "" , 0, 4, "fLaC")
75 CHECK(avr , 0, 0, "" , 0, 4, "2BIT")
76 CHECK(caf , 0, 0, "" , 0, 4, "caff")
77 CHECK(wv , 0, 0, "" , 0, 4, "wvpk")
78 CHECK(paf , 0, 0, "" , 0, 4, " paf")
79 CHECK(sf , 0, 0, "" , 0, 4, "\144\243\001\0")
80 CHECK(sf , 0, 0, "" , 0, 4, "\0\001\243\144")
81 CHECK(sf , 0, 0, "" , 0, 4, "\144\243\002\0")
82 CHECK(sf , 0, 0, "" , 0, 4, "\0\002\243\144")
83 CHECK(sf , 0, 0, "" , 0, 4, "\144\243\003\0")
84 CHECK(sf , 0, 0, "" , 0, 4, "\0\003\243\144")
85 CHECK(sf , 0, 0, "" , 0, 4, "\144\243\004\0")
86 CHECK(sox , 0, 0, "" , 0, 4, ".SoX")
87 CHECK(sox , 0, 0, "" , 0, 4, "XoS.")
89 if (ext && !strcasecmp(ext, "snd"))
90 CHECK(sndr , 7, 1, "" , 0, 2, "\0")
91 #undef CHECK
93 #if HAVE_MAGIC
94 if (sox_globals.use_magic) {
95 static magic_t magic;
96 char const * filetype = NULL;
97 if (!magic) {
98 magic = magic_open(MAGIC_MIME | MAGIC_SYMLINK);
99 if (magic)
100 magic_load(magic, NULL);
102 if (magic)
103 filetype = magic_buffer(magic, data, sizeof(data));
104 if (filetype && strncmp(filetype, "application/octet-stream", (size_t)24) &&
105 !lsx_strends(filetype, "/unknown") &&
106 strncmp(filetype, "text/plain", (size_t)10) )
107 return filetype;
108 else if (filetype)
109 lsx_debug("libmagic detected %s", filetype);
111 #endif
112 return NULL;
115 sox_encodings_info_t const sox_encodings_info[] = {
116 {0 , "n/a" , "Unknown or not applicable"},
117 {0 , "Signed PCM" , "Signed Integer PCM"},
118 {0 , "Unsigned PCM" , "Unsigned Integer PCM"},
119 {0 , "F.P. PCM" , "Floating Point PCM"},
120 {0 , "F.P. PCM" , "Floating Point (text) PCM"},
121 {0 , "FLAC" , "FLAC"},
122 {0 , "HCOM" , "HCOM"},
123 {0 , "WavPack" , "WavPack"},
124 {0 , "F.P. WavPack" , "Floating Point WavPack"},
125 {SOX_LOSSY1, "u-law" , "u-law"},
126 {SOX_LOSSY1, "A-law" , "A-law"},
127 {SOX_LOSSY1, "G.721 ADPCM" , "G.721 ADPCM"},
128 {SOX_LOSSY1, "G.723 ADPCM" , "G.723 ADPCM"},
129 {SOX_LOSSY1, "CL ADPCM (8)" , "CL ADPCM (from 8-bit)"},
130 {SOX_LOSSY1, "CL ADPCM (16)", "CL ADPCM (from 16-bit)"},
131 {SOX_LOSSY1, "MS ADPCM" , "MS ADPCM"},
132 {SOX_LOSSY1, "IMA ADPCM" , "IMA ADPCM"},
133 {SOX_LOSSY1, "OKI ADPCM" , "OKI ADPCM"},
134 {SOX_LOSSY1, "DPCM" , "DPCM"},
135 {0 , "DWVW" , "DWVW"},
136 {0 , "DWVWN" , "DWVWN"},
137 {SOX_LOSSY2, "GSM" , "GSM"},
138 {SOX_LOSSY2, "MPEG audio" , "MPEG audio (layer I, II or III)"},
139 {SOX_LOSSY2, "Vorbis" , "Vorbis"},
140 {SOX_LOSSY2, "AMR-WB" , "AMR-WB"},
141 {SOX_LOSSY2, "AMR-NB" , "AMR-NB"},
142 {SOX_LOSSY2, "CVSD" , "CVSD"},
143 {SOX_LOSSY2, "LPC10" , "LPC10"},
146 assert_static(array_length(sox_encodings_info) == SOX_ENCODINGS,
147 SIZE_MISMATCH_BETWEEN_sox_encoding_t_AND_sox_encodings_info);
149 unsigned sox_precision(sox_encoding_t encoding, unsigned bits_per_sample)
151 switch (encoding) {
152 case SOX_ENCODING_DWVW: return bits_per_sample;
153 case SOX_ENCODING_DWVWN: return !bits_per_sample? 16: 0; /* ? */
154 case SOX_ENCODING_HCOM: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 1? bits_per_sample: 0;
155 case SOX_ENCODING_WAVPACK:
156 case SOX_ENCODING_FLAC: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0;
157 case SOX_ENCODING_SIGN2: return bits_per_sample <= 32? bits_per_sample : 0;
158 case SOX_ENCODING_UNSIGNED: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0;
160 case SOX_ENCODING_ALAW: return bits_per_sample == 8? 13: 0;
161 case SOX_ENCODING_ULAW: return bits_per_sample == 8? 14: 0;
163 case SOX_ENCODING_CL_ADPCM: return bits_per_sample? 8: 0;
164 case SOX_ENCODING_CL_ADPCM16: return bits_per_sample == 4? 13: 0;
165 case SOX_ENCODING_MS_ADPCM: return bits_per_sample == 4? 14: 0;
166 case SOX_ENCODING_IMA_ADPCM: return bits_per_sample == 4? 13: 0;
167 case SOX_ENCODING_OKI_ADPCM: return bits_per_sample == 4? 12: 0;
168 case SOX_ENCODING_G721: return bits_per_sample == 4? 12: 0;
169 case SOX_ENCODING_G723: return bits_per_sample == 3? 8:
170 bits_per_sample == 5? 14: 0;
171 case SOX_ENCODING_CVSD: return bits_per_sample == 1? 16: 0;
172 case SOX_ENCODING_DPCM: return bits_per_sample; /* ? */
174 case SOX_ENCODING_MP3: return 0; /* Accept the precision returned by the format. */
176 case SOX_ENCODING_GSM:
177 case SOX_ENCODING_VORBIS:
178 case SOX_ENCODING_AMR_WB:
179 case SOX_ENCODING_AMR_NB:
180 case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;
182 case SOX_ENCODING_WAVPACKF:
183 case SOX_ENCODING_FLOAT: return bits_per_sample == 32 ? 24: bits_per_sample == 64 ? 53: 0;
184 case SOX_ENCODING_FLOAT_TEXT: return !bits_per_sample? 53: 0;
186 case SOX_ENCODINGS:
187 case SOX_ENCODING_UNKNOWN: break;
189 return 0;
192 void sox_init_encodinginfo(sox_encodinginfo_t * e)
194 e->reverse_bytes = SOX_OPTION_DEFAULT;
195 e->reverse_nibbles = SOX_OPTION_DEFAULT;
196 e->reverse_bits = SOX_OPTION_DEFAULT;
197 e->compression = HUGE_VAL;
200 /*--------------------------------- Comments ---------------------------------*/
202 size_t sox_num_comments(sox_comments_t comments)
204 size_t result = 0;
205 if (!comments)
206 return 0;
207 while (*comments++)
208 ++result;
209 return result;
212 void sox_append_comment(sox_comments_t * comments, char const * comment)
214 size_t n = sox_num_comments(*comments);
215 *comments = lsx_realloc(*comments, (n + 2) * sizeof(**comments));
216 assert(comment);
217 (*comments)[n++] = lsx_strdup(comment);
218 (*comments)[n] = 0;
221 void sox_append_comments(sox_comments_t * comments, char const * comment)
223 char * end;
224 if (comment) {
225 while ((end = strchr(comment, '\n'))) {
226 size_t len = end - comment;
227 char * c = lsx_malloc((len + 1) * sizeof(*c));
228 strncpy(c, comment, len);
229 c[len] = '\0';
230 sox_append_comment(comments, c);
231 comment += len + 1;
232 free(c);
234 if (*comment)
235 sox_append_comment(comments, comment);
239 sox_comments_t sox_copy_comments(sox_comments_t comments)
241 sox_comments_t result = 0;
243 if (comments) while (*comments)
244 sox_append_comment(&result, *comments++);
245 return result;
248 void sox_delete_comments(sox_comments_t * comments)
250 sox_comments_t p = *comments;
252 if (p) while (*p)
253 free(*p++);
254 free(*comments);
255 *comments = 0;
258 char * lsx_cat_comments(sox_comments_t comments)
260 sox_comments_t p = comments;
261 size_t len = 0;
262 char * result;
264 if (p) while (*p)
265 len += strlen(*p++) + 1;
267 result = lsx_calloc(len? len : 1, sizeof(*result));
269 if ((p = comments) && *p) {
270 strcpy(result, *p);
271 while (*++p)
272 strcat(strcat(result, "\n"), *p);
274 return result;
277 char const * sox_find_comment(sox_comments_t comments, char const * id)
279 size_t len = strlen(id);
281 if (comments) for (;*comments; ++comments)
282 if (!strncasecmp(*comments, id, len) && (*comments)[len] == '=')
283 return *comments + len + 1;
284 return NULL;
287 static void set_endiannesses(sox_format_t * ft)
289 if (ft->encoding.opposite_endian)
290 ft->encoding.reverse_bytes = (ft->handler.flags & SOX_FILE_ENDIAN)?
291 !(ft->handler.flags & SOX_FILE_ENDBIG) != MACHINE_IS_BIGENDIAN : sox_true;
292 else if (ft->encoding.reverse_bytes == SOX_OPTION_DEFAULT)
293 ft->encoding.reverse_bytes = (ft->handler.flags & SOX_FILE_ENDIAN)?
294 !(ft->handler.flags & SOX_FILE_ENDBIG) == MACHINE_IS_BIGENDIAN : sox_false;
296 /* FIXME: Change reports to suitable warnings if trying
297 * to override something that can't be overridden. */
299 if (ft->handler.flags & SOX_FILE_ENDIAN) {
300 if (ft->encoding.reverse_bytes == (sox_option_t)
301 (!(ft->handler.flags & SOX_FILE_ENDBIG) != MACHINE_IS_BIGENDIAN))
302 lsx_report("`%s': overriding file-type byte-order", ft->filename);
303 } else if (ft->encoding.reverse_bytes == sox_true)
304 lsx_report("`%s': overriding machine byte-order", ft->filename);
306 if (ft->encoding.reverse_bits == SOX_OPTION_DEFAULT)
307 ft->encoding.reverse_bits = !!(ft->handler.flags & SOX_FILE_BIT_REV);
308 else if (ft->encoding.reverse_bits == !(ft->handler.flags & SOX_FILE_BIT_REV))
309 lsx_report("`%s': overriding file-type bit-order", ft->filename);
311 if (ft->encoding.reverse_nibbles == SOX_OPTION_DEFAULT)
312 ft->encoding.reverse_nibbles = !!(ft->handler.flags & SOX_FILE_NIB_REV);
313 else
314 if (ft->encoding.reverse_nibbles == !(ft->handler.flags & SOX_FILE_NIB_REV))
315 lsx_report("`%s': overriding file-type nibble-order", ft->filename);
318 static sox_bool is_seekable(sox_format_t const * ft)
320 struct stat st;
322 assert(ft);
323 if (!ft->fp)
324 return sox_false;
325 fstat(fileno(ft->fp), &st);
326 return ((st.st_mode & S_IFMT) == S_IFREG);
329 /* check that all settings have been given */
330 static int sox_checkformat(sox_format_t * ft)
332 ft->sox_errno = SOX_SUCCESS;
334 if (!ft->signal.rate) {
335 lsx_fail_errno(ft,SOX_EFMT,"sampling rate was not specified");
336 return SOX_EOF;
338 if (!ft->signal.precision) {
339 lsx_fail_errno(ft,SOX_EFMT,"data encoding was not specified");
340 return SOX_EOF;
342 return SOX_SUCCESS;
345 static sox_bool is_url(char const * text) /* detects only wget-supported URLs */
347 return !(
348 strncasecmp(text, "http:" , (size_t)5) &&
349 strncasecmp(text, "https:", (size_t)6) &&
350 strncasecmp(text, "ftp:" , (size_t)4));
353 static int xfclose(FILE * file, lsx_io_type io_type)
355 return
356 #ifdef HAVE_POPEN
357 io_type != lsx_io_file? pclose(file) :
358 #endif
359 fclose(file);
362 static FILE * xfopen(char const * identifier, char const * mode, lsx_io_type * io_type)
364 *io_type = lsx_io_file;
366 if (*identifier == '|') {
367 FILE * f = NULL;
368 #ifdef HAVE_POPEN
369 f = popen(identifier + 1, "r");
370 *io_type = lsx_io_pipe;
371 #else
372 lsx_fail("this build of SoX cannot open pipes");
373 #endif
374 return f;
376 else if (is_url(identifier)) {
377 FILE * f = NULL;
378 #ifdef HAVE_POPEN
379 char const * const command_format = "wget --no-check-certificate -q -O- \"%s\"";
380 char * command = lsx_malloc(strlen(command_format) + strlen(identifier));
381 sprintf(command, command_format, identifier);
382 f = popen(command, "r");
383 free(command);
384 *io_type = lsx_io_url;
385 #else
386 lsx_fail("this build of SoX cannot open URLs");
387 #endif
388 return f;
390 return fopen(identifier, mode);
393 /* Hack to rewind pipes (a small amount).
394 * Works by resetting the FILE buffer pointer */
395 static void UNUSED rewind_pipe(FILE * fp)
397 /* _FSTDIO is for Torek stdio (i.e. most BSD-derived libc's)
398 * In theory, we no longer need to check _NEWLIB_VERSION or __APPLE__ */
399 #if defined _FSTDIO || defined _NEWLIB_VERSION || defined __APPLE__
400 fp->_p -= AUTO_DETECT_SIZE;
401 fp->_r += AUTO_DETECT_SIZE;
402 #elif defined __GLIBC__
403 fp->_IO_read_ptr = fp->_IO_read_base;
404 #elif defined _MSC_VER || defined __MINGW_H || defined _ISO_STDIO_ISO_H
405 fp->_ptr = fp->_base;
406 #else
407 /* To fix this #error, either simply remove the #error line and live without
408 * file-type detection with pipes, or add support for your compiler in the
409 * lines above. Test with cat monkey.au | ./sox --info - */
410 #error FIX NEEDED HERE
411 #define NO_REWIND_PIPE
412 (void)fp;
413 #endif
416 static sox_format_t * open_read(
417 char const * path,
418 void * buffer UNUSED,
419 size_t buffer_size UNUSED,
420 sox_signalinfo_t const * signal,
421 sox_encodinginfo_t const * encoding,
422 char const * filetype)
424 sox_format_t * ft = lsx_calloc(1, sizeof(*ft));
425 sox_format_handler_t const * handler;
426 char const * const io_types[] = {"file", "pipe", "file URL"};
427 char const * type = "";
428 size_t input_bufsiz = sox_globals.input_bufsiz?
429 sox_globals.input_bufsiz : sox_globals.bufsiz;
431 if (filetype) {
432 if (!(handler = sox_find_format(filetype, sox_false))) {
433 lsx_fail("no handler for given file type `%s'", filetype);
434 goto error;
436 ft->handler = *handler;
439 if (!(ft->handler.flags & SOX_FILE_NOSTDIO)) {
440 if (!strcmp(path, "-")) { /* Use stdin if the filename is "-" */
441 if (sox_globals.stdin_in_use_by) {
442 lsx_fail("`-' (stdin) already in use by `%s'", sox_globals.stdin_in_use_by);
443 goto error;
445 sox_globals.stdin_in_use_by = "audio input";
446 SET_BINARY_MODE(stdin);
447 ft->fp = stdin;
449 else {
450 ft->fp =
451 #ifdef HAVE_FMEMOPEN
452 buffer? fmemopen(buffer, buffer_size, "rb") :
453 #endif
454 xfopen(path, "rb", &ft->io_type);
455 type = io_types[ft->io_type];
456 if (ft->fp == NULL) {
457 lsx_fail("can't open input %s `%s': %s", type, path, strerror(errno));
458 goto error;
461 if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * input_bufsiz)) {
462 lsx_fail("Can't set read buffer");
463 goto error;
465 ft->seekable = is_seekable(ft);
468 if (!filetype) {
469 if (ft->seekable) {
470 filetype = auto_detect_format(ft, lsx_find_file_extension(path));
471 lsx_rewind(ft);
473 #ifndef NO_REWIND_PIPE
474 else if (!(ft->handler.flags & SOX_FILE_NOSTDIO) &&
475 input_bufsiz >= AUTO_DETECT_SIZE) {
476 filetype = auto_detect_format(ft, lsx_find_file_extension(path));
477 rewind_pipe(ft->fp);
478 ft->tell_off = 0;
480 #endif
482 if (filetype) {
483 lsx_report("detected file format type `%s'", filetype);
484 if (!(handler = sox_find_format(filetype, sox_false))) {
485 lsx_fail("no handler for detected file type `%s'", filetype);
486 goto error;
489 else {
490 if (ft->io_type == lsx_io_pipe) {
491 filetype = "sox"; /* With successful pipe rewind, this isn't useful */
492 lsx_report("assuming input pipe `%s' has file-type `sox'", path);
494 else if (!(filetype = lsx_find_file_extension(path))) {
495 lsx_fail("can't determine type of %s `%s'", type, path);
496 goto error;
498 if (!(handler = sox_find_format(filetype, sox_true))) {
499 lsx_fail("no handler for file extension `%s'", filetype);
500 goto error;
503 ft->handler = *handler;
504 if (ft->handler.flags & SOX_FILE_NOSTDIO) {
505 xfclose(ft->fp, ft->io_type);
506 ft->fp = NULL;
509 if (!ft->handler.startread && !ft->handler.read) {
510 lsx_fail("file type `%s' isn't readable", filetype);
511 goto error;
514 ft->mode = 'r';
515 ft->filetype = lsx_strdup(filetype);
516 ft->filename = lsx_strdup(path);
517 if (signal)
518 ft->signal = *signal;
520 if (encoding)
521 ft->encoding = *encoding;
522 else sox_init_encodinginfo(&ft->encoding);
523 set_endiannesses(ft);
525 if ((ft->handler.flags & SOX_FILE_DEVICE) && !(ft->handler.flags & SOX_FILE_PHONY))
526 lsx_set_signal_defaults(ft);
528 ft->priv = lsx_calloc(1, ft->handler.priv_size);
529 /* Read and write starters can change their formats. */
530 if (ft->handler.startread && (*ft->handler.startread)(ft) != SOX_SUCCESS) {
531 lsx_fail("can't open input %s `%s': %s", type, ft->filename, ft->sox_errstr);
532 goto error;
535 /* Fill in some defaults: */
536 if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
537 ft->signal.precision = sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample);
538 if (!(ft->handler.flags & SOX_FILE_PHONY) && !ft->signal.channels)
539 ft->signal.channels = 1;
541 if (sox_checkformat(ft) != SOX_SUCCESS) {
542 lsx_fail("bad input format for %s `%s': %s", type, ft->filename, ft->sox_errstr);
543 goto error;
546 if (signal) {
547 if (signal->rate && signal->rate != ft->signal.rate)
548 lsx_warn("can't set sample rate %g; using %g", signal->rate, ft->signal.rate);
549 if (signal->channels && signal->channels != ft->signal.channels)
550 lsx_warn("can't set %u channels; using %u", signal->channels, ft->signal.channels);
552 return ft;
554 error:
555 if (ft->fp && ft->fp != stdin)
556 xfclose(ft->fp, ft->io_type);
557 free(ft->priv);
558 free(ft->filename);
559 free(ft->filetype);
560 free(ft);
561 return NULL;
564 sox_format_t * sox_open_read(
565 char const * path,
566 sox_signalinfo_t const * signal,
567 sox_encodinginfo_t const * encoding,
568 char const * filetype)
570 return open_read(path, NULL, (size_t)0, signal, encoding, filetype);
573 sox_format_t * sox_open_mem_read(
574 void * buffer,
575 size_t buffer_size,
576 sox_signalinfo_t const * signal,
577 sox_encodinginfo_t const * encoding,
578 char const * filetype)
580 return open_read("", buffer, buffer_size, signal,encoding,filetype);
583 sox_bool sox_format_supports_encoding(
584 char const * path,
585 char const * filetype,
586 sox_encodinginfo_t const * encoding)
588 #define enc_arg(T) (T)handler->write_formats[i++]
589 sox_bool is_file_extension = filetype == NULL;
590 sox_format_handler_t const * handler;
591 unsigned i = 0, s;
592 sox_encoding_t e;
594 assert(path);
595 assert(encoding);
596 if (!filetype)
597 filetype = lsx_find_file_extension(path);
599 if (!filetype || !(handler = sox_find_format(filetype, is_file_extension)) ||
600 !handler->write_formats)
601 return sox_false;
602 while ((e = enc_arg(sox_encoding_t))) {
603 if (e == encoding->encoding) {
604 sox_bool has_bits;
605 for (has_bits = sox_false; (s = enc_arg(unsigned)); has_bits = sox_true)
606 if (s == encoding->bits_per_sample)
607 return sox_true;
608 if (!has_bits && !encoding->bits_per_sample)
609 return sox_true;
610 break;
612 while (enc_arg(unsigned));
614 return sox_false;
615 #undef enc_arg
618 static void set_output_format(sox_format_t * ft)
620 sox_encoding_t e;
621 unsigned i, s;
622 unsigned const * encodings = ft->handler.write_formats;
623 #define enc_arg(T) (T)encodings[i++]
625 if (ft->handler.write_rates){
626 if (!ft->signal.rate)
627 ft->signal.rate = ft->handler.write_rates[0];
628 else {
629 sox_rate_t r;
630 i = 0;
631 while ((r = ft->handler.write_rates[i++])) {
632 if (r == ft->signal.rate)
633 break;
635 if (r != ft->signal.rate) {
636 sox_rate_t given = ft->signal.rate, max = 0;
637 ft->signal.rate = HUGE_VAL;
638 i = 0;
639 while ((r = ft->handler.write_rates[i++])) {
640 if (r > given && r < ft->signal.rate)
641 ft->signal.rate = r;
642 else max = max(r, max);
644 if (ft->signal.rate == HUGE_VAL)
645 ft->signal.rate = max;
646 lsx_warn("%s can't encode at %gHz; using %gHz", ft->handler.names[0], given, ft->signal.rate);
650 else if (!ft->signal.rate)
651 ft->signal.rate = SOX_DEFAULT_RATE;
653 if (ft->handler.flags & SOX_FILE_CHANS) {
654 if (ft->signal.channels == 1 && !(ft->handler.flags & SOX_FILE_MONO)) {
655 ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 4;
656 lsx_warn("%s can't encode mono; setting channels to %u", ft->handler.names[0], ft->signal.channels);
657 } else
658 if (ft->signal.channels == 2 && !(ft->handler.flags & SOX_FILE_STEREO)) {
659 ft->signal.channels = (ft->handler.flags & SOX_FILE_QUAD)? 4 : 1;
660 lsx_warn("%s can't encode stereo; setting channels to %u", ft->handler.names[0], ft->signal.channels);
661 } else
662 if (ft->signal.channels == 4 && !(ft->handler.flags & SOX_FILE_QUAD)) {
663 ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 1;
664 lsx_warn("%s can't encode quad; setting channels to %u", ft->handler.names[0], ft->signal.channels);
666 } else ft->signal.channels = max(ft->signal.channels, 1);
668 if (!encodings)
669 return;
670 /* If an encoding has been given, check if it supported by this handler */
671 if (ft->encoding.encoding) {
672 i = 0;
673 while ((e = enc_arg(sox_encoding_t))) {
674 if (e == ft->encoding.encoding)
675 break;
676 while (enc_arg(unsigned));
678 if (e != ft->encoding.encoding) {
679 lsx_warn("%s can't encode %s", ft->handler.names[0], sox_encodings_info[ft->encoding.encoding].desc);
680 ft->encoding.encoding = 0;
682 else {
683 unsigned max_p = 0;
684 unsigned max_p_s = 0;
685 unsigned given_size = 0;
686 sox_bool found = sox_false;
687 if (ft->encoding.bits_per_sample)
688 given_size = ft->encoding.bits_per_sample;
689 ft->encoding.bits_per_sample = 65;
690 while ((s = enc_arg(unsigned))) {
691 if (s == given_size)
692 found = sox_true;
693 if (sox_precision(e, s) >= ft->signal.precision) {
694 if (s < ft->encoding.bits_per_sample)
695 ft->encoding.bits_per_sample = s;
697 else if (sox_precision(e, s) > max_p) {
698 max_p = sox_precision(e, s);
699 max_p_s = s;
702 if (ft->encoding.bits_per_sample == 65)
703 ft->encoding.bits_per_sample = max_p_s;
704 if (given_size) {
705 if (found)
706 ft->encoding.bits_per_sample = given_size;
707 else lsx_warn("%s can't encode %s to %u-bit", ft->handler.names[0], sox_encodings_info[ft->encoding.encoding].desc, given_size);
712 /* If a size has been given, check if it supported by this handler */
713 if (!ft->encoding.encoding && ft->encoding.bits_per_sample) {
714 i = 0;
715 s= 0;
716 while (s != ft->encoding.bits_per_sample && (e = enc_arg(sox_encoding_t)))
717 while ((s = enc_arg(unsigned)) && s != ft->encoding.bits_per_sample);
718 if (s != ft->encoding.bits_per_sample) {
719 lsx_warn("%s can't encode to %u-bit", ft->handler.names[0], ft->encoding.bits_per_sample);
720 ft->encoding.bits_per_sample = 0;
722 else ft->encoding.encoding = e;
725 /* Find the smallest lossless encoding with precision >= signal.precision */
726 if (!ft->encoding.encoding) {
727 ft->encoding.bits_per_sample = 65;
728 i = 0;
729 while ((e = enc_arg(sox_encoding_t)))
730 while ((s = enc_arg(unsigned)))
731 if (!(sox_encodings_info[e].flags & (SOX_LOSSY1 | SOX_LOSSY2)) &&
732 sox_precision(e, s) >= ft->signal.precision && s < ft->encoding.bits_per_sample) {
733 ft->encoding.encoding = e;
734 ft->encoding.bits_per_sample = s;
738 /* Find the smallest lossy encoding with precision >= signal precision,
739 * or, if none such, the highest precision encoding */
740 if (!ft->encoding.encoding) {
741 unsigned max_p = 0;
742 sox_encoding_t max_p_e = 0;
743 unsigned max_p_s = 0;
744 i = 0;
745 while ((e = enc_arg(sox_encoding_t)))
746 do {
747 s = enc_arg(unsigned);
748 if (sox_precision(e, s) >= ft->signal.precision) {
749 if (s < ft->encoding.bits_per_sample) {
750 ft->encoding.encoding = e;
751 ft->encoding.bits_per_sample = s;
754 else if (sox_precision(e, s) > max_p) {
755 max_p = sox_precision(e, s);
756 max_p_e = e;
757 max_p_s = s;
759 } while (s);
760 if (!ft->encoding.encoding) {
761 ft->encoding.encoding = max_p_e;
762 ft->encoding.bits_per_sample = max_p_s;
765 ft->signal.precision = min(ft->signal.precision, sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample));
766 #undef enc_arg
769 sox_format_handler_t const * sox_write_handler(
770 char const * path,
771 char const * filetype,
772 char const * * filetype1)
774 sox_format_handler_t const * handler;
775 if (filetype) {
776 if (!(handler = sox_find_format(filetype, sox_false))) {
777 if (filetype1)
778 lsx_fail("no handler for given file type `%s'", filetype);
779 return NULL;
782 else if (path) {
783 if (!(filetype = lsx_find_file_extension(path))) {
784 if (filetype1)
785 lsx_fail("can't determine type of `%s'", path);
786 return NULL;
788 if (!(handler = sox_find_format(filetype, sox_true))) {
789 if (filetype1)
790 lsx_fail("no handler for file extension `%s'", filetype);
791 return NULL;
794 else return NULL;
795 if (!handler->startwrite && !handler->write) {
796 if (filetype1)
797 lsx_fail("file type `%s' isn't writeable", filetype);
798 return NULL;
800 if (filetype1)
801 *filetype1 = filetype;
802 return handler;
805 static sox_format_t * open_write(
806 char const * path,
807 void * buffer UNUSED,
808 size_t buffer_size UNUSED,
809 char * * buffer_ptr UNUSED,
810 size_t * buffer_size_ptr UNUSED,
811 sox_signalinfo_t const * signal,
812 sox_encodinginfo_t const * encoding,
813 char const * filetype,
814 sox_oob_t const * oob,
815 sox_bool (*overwrite_permitted)(const char *filename))
817 sox_format_t * ft = lsx_calloc(sizeof(*ft), 1);
818 sox_format_handler_t const * handler;
820 if (!path || !signal) {
821 lsx_fail("must specify file name and signal parameters to write file");
822 goto error;
825 if (!(handler = sox_write_handler(path, filetype, &filetype)))
826 goto error;
828 ft->handler = *handler;
830 if (!(ft->handler.flags & SOX_FILE_NOSTDIO)) {
831 if (!strcmp(path, "-")) { /* Use stdout if the filename is "-" */
832 if (sox_globals.stdout_in_use_by) {
833 lsx_fail("`-' (stdout) already in use by `%s'", sox_globals.stdout_in_use_by);
834 goto error;
836 sox_globals.stdout_in_use_by = "audio output";
837 SET_BINARY_MODE(stdout);
838 ft->fp = stdout;
840 else {
841 struct stat st;
842 if (!stat(path, &st) && (st.st_mode & S_IFMT) == S_IFREG &&
843 (overwrite_permitted && !overwrite_permitted(path))) {
844 lsx_fail("permission to overwrite `%s' denied", path);
845 goto error;
847 ft->fp =
848 #ifdef HAVE_FMEMOPEN
849 buffer? fmemopen(buffer, buffer_size, "w+b") :
850 buffer_ptr? open_memstream(buffer_ptr, buffer_size_ptr) :
851 #endif
852 fopen(path, "w+b");
853 if (ft->fp == NULL) {
854 lsx_fail("can't open output file `%s': %s", path, strerror(errno));
855 goto error;
859 /* stdout tends to be line-buffered. Override this */
860 /* to be Full Buffering. */
861 if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * sox_globals.bufsiz)) {
862 lsx_fail("Can't set write buffer");
863 goto error;
865 ft->seekable = is_seekable(ft);
868 ft->filetype = lsx_strdup(filetype);
869 ft->filename = lsx_strdup(path);
870 ft->mode = 'w';
871 ft->signal = *signal;
873 if (encoding)
874 ft->encoding = *encoding;
875 else sox_init_encodinginfo(&ft->encoding);
876 set_endiannesses(ft);
878 if (oob) {
879 ft->oob = *oob;
880 /* deep copy: */
881 ft->oob.comments = sox_copy_comments(oob->comments);
884 set_output_format(ft);
886 /* FIXME: doesn't cover the situation where
887 * codec changes audio length due to block alignment (e.g. 8svx, gsm): */
888 if (signal->rate && signal->channels)
889 ft->signal.length = ft->signal.length * ft->signal.rate / signal->rate *
890 ft->signal.channels / signal->channels + .5;
892 if ((ft->handler.flags & SOX_FILE_REWIND) && strcmp(ft->filetype, "sox") && !ft->signal.length && !ft->seekable)
893 lsx_warn("can't seek in output file `%s'; length in file header will be unspecified", ft->filename);
895 ft->priv = lsx_calloc(1, ft->handler.priv_size);
896 /* Read and write starters can change their formats. */
897 if (ft->handler.startwrite && (ft->handler.startwrite)(ft) != SOX_SUCCESS){
898 lsx_fail("can't open output file `%s': %s", ft->filename, ft->sox_errstr);
899 goto error;
902 if (sox_checkformat(ft) != SOX_SUCCESS) {
903 lsx_fail("bad format for output file `%s': %s", ft->filename, ft->sox_errstr);
904 goto error;
907 if ((ft->handler.flags & SOX_FILE_DEVICE) && signal) {
908 if (signal->rate && signal->rate != ft->signal.rate)
909 lsx_report("can't set sample rate %g; using %g", signal->rate, ft->signal.rate);
910 if (signal->channels && signal->channels != ft->signal.channels)
911 lsx_report("can't set %u channels; using %u", signal->channels, ft->signal.channels);
913 return ft;
915 error:
916 if (ft->fp && ft->fp != stdout)
917 xfclose(ft->fp, ft->io_type);
918 free(ft->priv);
919 free(ft->filename);
920 free(ft->filetype);
921 free(ft);
922 return NULL;
925 sox_format_t * sox_open_write(
926 char const * path,
927 sox_signalinfo_t const * signal,
928 sox_encodinginfo_t const * encoding,
929 char const * filetype,
930 sox_oob_t const * oob,
931 sox_bool (*overwrite_permitted)(const char *filename))
933 return open_write(path, NULL, (size_t)0, NULL, NULL, signal, encoding, filetype, oob, overwrite_permitted);
936 sox_format_t * sox_open_mem_write(
937 void * buffer,
938 size_t buffer_size,
939 sox_signalinfo_t const * signal,
940 sox_encodinginfo_t const * encoding,
941 char const * filetype,
942 sox_oob_t const * oob)
944 return open_write("", buffer, buffer_size, NULL, NULL, signal, encoding, filetype, oob, NULL);
947 sox_format_t * sox_open_memstream_write(
948 char * * buffer_ptr,
949 size_t * buffer_size_ptr,
950 sox_signalinfo_t const * signal,
951 sox_encodinginfo_t const * encoding,
952 char const * filetype,
953 sox_oob_t const * oob)
955 return open_write("", NULL, (size_t)0, buffer_ptr, buffer_size_ptr, signal, encoding, filetype, oob, NULL);
958 size_t sox_read(sox_format_t * ft, sox_sample_t * buf, size_t len)
960 size_t actual;
961 if (ft->signal.length != SOX_UNSPEC)
962 len = min(len, ft->signal.length - ft->olength);
963 actual = ft->handler.read? (*ft->handler.read)(ft, buf, len) : 0;
964 actual = actual > len? 0 : actual;
965 ft->olength += actual;
966 return actual;
969 size_t sox_write(sox_format_t * ft, const sox_sample_t *buf, size_t len)
971 size_t actual = ft->handler.write? (*ft->handler.write)(ft, buf, len) : 0;
972 ft->olength += actual;
973 return actual;
976 int sox_close(sox_format_t * ft)
978 int result = SOX_SUCCESS;
980 if (ft->mode == 'r')
981 result = ft->handler.stopread? (*ft->handler.stopread)(ft) : SOX_SUCCESS;
982 else {
983 if (ft->handler.flags & SOX_FILE_REWIND) {
984 if (ft->olength != ft->signal.length && ft->seekable) {
985 result = lsx_seeki(ft, (off_t)0, 0);
986 if (result == SOX_SUCCESS)
987 result = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft)
988 : ft->handler.startwrite?(*ft->handler.startwrite)(ft) : SOX_SUCCESS;
991 else result = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft) : SOX_SUCCESS;
994 if (ft->fp && ft->fp != stdin && ft->fp != stdout)
995 xfclose(ft->fp, ft->io_type);
996 free(ft->priv);
997 free(ft->filename);
998 free(ft->filetype);
999 sox_delete_comments(&ft->oob.comments);
1001 free(ft);
1002 return result;
1005 int sox_seek(sox_format_t * ft, uint64_t offset, int whence)
1007 /* FIXME: Implement SOX_SEEK_CUR and SOX_SEEK_END. */
1008 if (whence != SOX_SEEK_SET)
1009 return SOX_EOF; /* FIXME: return SOX_EINVAL */
1011 /* If file is a seekable file and this handler supports seeking,
1012 * then invoke handler's function.
1014 if (ft->seekable && ft->handler.seek)
1015 return (*ft->handler.seek)(ft, offset);
1016 return SOX_EOF; /* FIXME: return SOX_EBADF */
1019 static int strcaseends(char const * str, char const * end)
1021 size_t str_len = strlen(str), end_len = strlen(end);
1022 return str_len >= end_len && !strcasecmp(str + str_len - end_len, end);
1025 typedef enum {None, M3u, Pls} playlist_t;
1027 static playlist_t playlist_type(char const * filename)
1029 char * x, * p;
1030 playlist_t result = None;
1032 if (*filename == '|')
1033 return result;
1034 if (strcaseends(filename, ".m3u"))
1035 return M3u;
1036 if (strcaseends(filename, ".pls"))
1037 return Pls;
1038 x = lsx_strdup(filename);
1039 p = strrchr(x, '?');
1040 if (p) {
1041 *p = '\0';
1042 result = playlist_type(x);
1044 free(x);
1045 return result;
1048 sox_bool sox_is_playlist(char const * filename)
1050 return playlist_type(filename) != None;
1053 int sox_parse_playlist(sox_playlist_callback_t callback, void * p, char const * const listname)
1055 sox_bool const is_pls = playlist_type(listname) == Pls;
1056 int const comment_char = "#;"[is_pls];
1057 size_t text_length = 100;
1058 char * text = lsx_malloc(text_length + 1);
1059 char * dirname = lsx_strdup(listname);
1060 char * slash_pos = LAST_SLASH(dirname);
1061 lsx_io_type io_type;
1062 FILE * file = xfopen(listname, "r", &io_type);
1063 char * filename;
1064 int c, result = SOX_SUCCESS;
1066 if (!slash_pos)
1067 *dirname = '\0';
1068 else
1069 *slash_pos = '\0';
1071 if (file == NULL) {
1072 lsx_fail("Can't open playlist file `%s': %s", listname, strerror(errno));
1073 result = SOX_EOF;
1075 else {
1076 do {
1077 size_t i = 0;
1078 size_t begin = 0, end = 0;
1080 while (isspace(c = getc(file)));
1081 if (c == EOF)
1082 break;
1083 while (c != EOF && !strchr("\r\n", c) && c != comment_char) {
1084 if (i == text_length)
1085 text = lsx_realloc(text, (text_length <<= 1) + 1);
1086 text[i++] = c;
1087 if (!strchr(" \t\f", c))
1088 end = i;
1089 c = getc(file);
1091 if (ferror(file))
1092 break;
1093 if (c == comment_char) {
1094 do c = getc(file);
1095 while (c != EOF && !strchr("\r\n", c));
1096 if (ferror(file))
1097 break;
1099 text[end] = '\0';
1100 if (is_pls) {
1101 char dummy;
1102 if (!strncasecmp(text, "file", (size_t) 4) && sscanf(text + 4, "%*u=%c", &dummy) == 1)
1103 begin = strchr(text + 5, '=') - text + 1;
1104 else end = 0;
1106 if (begin != end) {
1107 char const * id = text + begin;
1109 if (!dirname[0] || is_url(id) || IS_ABSOLUTE(id))
1110 filename = lsx_strdup(id);
1111 else {
1112 filename = lsx_malloc(strlen(dirname) + strlen(id) + 2);
1113 sprintf(filename, "%s/%s", dirname, id);
1115 if (sox_is_playlist(filename))
1116 sox_parse_playlist(callback, p, filename);
1117 else if (callback(p, filename))
1118 c = EOF;
1119 free(filename);
1121 } while (c != EOF);
1123 if (ferror(file)) {
1124 lsx_fail("error reading playlist file `%s': %s", listname, strerror(errno));
1125 result = SOX_EOF;
1127 if (xfclose(file, io_type) && io_type == lsx_io_url) {
1128 lsx_fail("error reading playlist file URL `%s'", listname);
1129 result = SOX_EOF;
1132 free(text);
1133 free(dirname);
1134 return result;
1137 /*----------------------------- Formats library ------------------------------*/
1139 enum {
1140 #define FORMAT(f) f,
1141 #include "formats.h"
1142 #undef FORMAT
1143 NSTATIC_FORMATS
1146 static sox_bool plugins_initted = sox_false;
1148 #ifdef HAVE_LIBLTDL /* Plugin format handlers */
1149 #define MAX_DYNAMIC_FORMATS 42
1150 #define MAX_FORMATS (NSTATIC_FORMATS + MAX_DYNAMIC_FORMATS)
1151 #define MAX_FORMATS_1 (MAX_FORMATS + 1)
1152 #define MAX_NAME_LEN (size_t)1024 /* FIXME: Use vasprintf */
1154 static unsigned nformats = NSTATIC_FORMATS;
1156 static int init_format(const char *file, lt_ptr data)
1158 lt_dlhandle lth = lt_dlopenext(file);
1159 const char *end = file + strlen(file);
1160 const char prefix[] = "sox_fmt_";
1161 char fnname[MAX_NAME_LEN];
1162 char *start = strstr(file, prefix);
1164 (void)data;
1165 if (start && (start += sizeof(prefix) - 1) < end) {
1166 int ret = snprintf(fnname, MAX_NAME_LEN,
1167 "lsx_%.*s_format_fn", (int)(end - start), start);
1168 if (ret > 0 && ret < (int)MAX_NAME_LEN) {
1169 union {sox_format_fn_t fn; lt_ptr ptr;} ltptr;
1170 ltptr.ptr = lt_dlsym(lth, fnname);
1171 lsx_debug("opening format plugin `%s': library %p, entry point %p\n",
1172 fnname, (void *)lth, ltptr.ptr);
1173 if (ltptr.fn && (ltptr.fn()->sox_lib_version_code & ~255) ==
1174 (SOX_LIB_VERSION_CODE & ~255)) { /* compatible version check */
1175 if (nformats == MAX_FORMATS) {
1176 lsx_warn("too many plugin formats");
1177 return -1;
1179 sox_format_fns[nformats++].fn = ltptr.fn;
1183 return 0;
1185 #else
1186 #define MAX_FORMATS_1
1187 #endif
1189 #define FORMAT(f) extern sox_format_handler_t const * lsx_##f##_format_fn(void);
1190 #include "formats.h"
1191 #undef FORMAT
1193 sox_format_tab_t sox_format_fns[MAX_FORMATS_1] = {
1194 #define FORMAT(f) {NULL, lsx_##f##_format_fn},
1195 #include "formats.h"
1196 #undef FORMAT
1197 {NULL, NULL}
1200 int sox_format_init(void) /* Find & load format handlers. */
1202 if (plugins_initted)
1203 return SOX_EOF;
1205 plugins_initted = sox_true;
1206 #ifdef HAVE_LIBLTDL
1208 int error = lt_dlinit();
1209 if (error) {
1210 lsx_fail("lt_dlinit failed with %d error(s): %s", error, lt_dlerror());
1211 return SOX_EOF;
1213 lt_dlforeachfile(PKGLIBDIR, init_format, NULL);
1215 #endif
1216 return SOX_SUCCESS;
1219 void sox_format_quit(void) /* Cleanup things. */
1221 #ifdef HAVE_LIBLTDL
1222 int ret;
1223 if (plugins_initted && (ret = lt_dlexit()) != 0)
1224 lsx_fail("lt_dlexit failed with %d error(s): %s", ret, lt_dlerror());
1225 #endif
1228 /* Find a named format in the formats library.
1230 * (c) 2005-9 Chris Bagwell and SoX contributors.
1231 * Copyright 1991 Lance Norskog And Sundry Contributors.
1233 * This source code is freely redistributable and may be used for any
1234 * purpose. This copyright notice must be maintained.
1236 * Lance Norskog, Sundry Contributors, Chris Bagwell and SoX contributors
1237 * are not responsible for the consequences of using this software.
1239 sox_format_handler_t const * sox_find_format(char const * name0, sox_bool no_dev)
1241 size_t f, n;
1243 if (name0) {
1244 char * name = lsx_strdup(name0);
1245 char * pos = strchr(name, ';');
1246 if (pos) /* Use only the 1st clause of a mime string */
1247 *pos = '\0';
1248 for (f = 0; sox_format_fns[f].fn; ++f) {
1249 sox_format_handler_t const * handler = sox_format_fns[f].fn();
1251 if (!(no_dev && (handler->flags & SOX_FILE_DEVICE)))
1252 for (n = 0; handler->names[n]; ++n)
1253 if (!strcasecmp(handler->names[n], name)) {
1254 free(name);
1255 return handler; /* Found it. */
1258 free(name);
1260 if (sox_format_init() == SOX_SUCCESS) /* Try again with plugins */
1261 return sox_find_format(name0, no_dev);
1262 return NULL;