1 /*
2 ** Copyright (C) 1999-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions are
8 ** met:
9 **
10 ** * Redistributions of source code must retain the above copyright
11 ** notice, this list of conditions and the following disclaimer.
12 ** * Redistributions in binary form must reproduce the above copyright
13 ** notice, this list of conditions and the following disclaimer in
14 ** the documentation and/or other materials provided with the
15 ** distribution.
16 ** * Neither the author nor the names of any contributors may be used
17 ** to endorse or promote products derived from this software without
18 ** specific prior written permission.
19 **
20 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include <sndfile.h>
39
40 #include "common.h"
41
42
43 typedef struct
44 { char *infilename, *outfilename ;
45 SF_INFO infileinfo, outfileinfo ;
46 } OptionData ;
47
48 static void copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels) ;
49
50 static void
usage_exit(const char * progname)51 usage_exit (const char *progname)
52 {
53 printf ("\nUsage : %s [options] [encoding] <input file> <output file>\n", progname) ;
54 puts ("\n"
55 " where [option] may be:\n\n"
56 " -override-sample-rate=X : force sample rate of input to X\n"
57 " -endian=little : force output file to little endian data\n"
58 " -endian=big : force output file to big endian data\n"
59 " -endian=cpu : force output file same endian-ness as the CPU\n"
60 " -normalize : normalize the data in the output file\n"
61 ) ;
62
63 puts (
64 " where [encoding] may be one of the following:\n\n"
65 " -pcms8 : signed 8 bit pcm\n"
66 " -pcmu8 : unsigned 8 bit pcm\n"
67 " -pcm16 : 16 bit pcm\n"
68 " -pcm24 : 24 bit pcm\n"
69 " -pcm32 : 32 bit pcm\n"
70 " -float32 : 32 bit floating point\n"
71 " -float64 : 64 bit floating point\n"
72 " -ulaw : ULAW\n"
73 " -alaw : ALAW\n"
74 " -alac16 : 16 bit ALAC (CAF only)\n"
75 " -alac20 : 20 bit ALAC (CAF only)\n"
76 " -alac24 : 24 bit ALAC (CAF only)\n"
77 " -alac32 : 32 bit ALAC (CAF only)\n"
78 " -ima-adpcm : IMA ADPCM (WAV only)\n"
79 " -ms-adpcm : MS ADPCM (WAV only)\n"
80 " -gsm610 : GSM6.10 (WAV only)\n"
81 " -dwvw12 : 12 bit DWVW (AIFF only)\n"
82 " -dwvw16 : 16 bit DWVW (AIFF only)\n"
83 " -dwvw24 : 24 bit DWVW (AIFF only)\n"
84 " -vorbis : Vorbis (OGG only)\n"
85 " -opus : Opus (OGG only)\n"
86 ) ;
87
88 puts (
89 " If no encoding is specified, the program will try to use the encoding\n"
90 " of the input file in the output file. This will not always work as\n"
91 " most container formats (eg WAV, AIFF etc) only support a small subset\n"
92 " of codec formats (eg 16 bit PCM, a-law, Vorbis etc).\n"
93 ) ;
94
95 puts (
96 " The format of the output file is determined by the file extension of the\n"
97 " output file name. The following extensions are currently understood:\n"
98 ) ;
99
100 sfe_dump_format_map () ;
101
102 puts ("") ;
103 exit (1) ;
104 } /* usage_exit */
105
106 static void
report_format_error_exit(const char * argv0,SF_INFO * sfinfo)107 report_format_error_exit (const char * argv0, SF_INFO * sfinfo)
108 { int old_format = sfinfo->format ;
109 int endian = sfinfo->format & SF_FORMAT_ENDMASK ;
110 int channels = sfinfo->channels ;
111
112 sfinfo->format = old_format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ;
113
114 if (endian && sf_format_check (sfinfo))
115 { printf ("Error : output file format does not support %s endian-ness.\n", sfe_endian_name (endian)) ;
116 exit (1) ;
117 } ;
118
119 sfinfo->channels = 1 ;
120 if (sf_format_check (sfinfo))
121 { printf ("Error : output file format does not support %d channels.\n", channels) ;
122 exit (1) ;
123 } ;
124
125 printf ("\n"
126 "Error : output file format is invalid.\n"
127 "The '%s' container does not support '%s' codec data.\n"
128 "Run '%s --help' for clues.\n\n",
129 sfe_container_name (sfinfo->format), sfe_codec_name (sfinfo->format), program_name (argv0)) ;
130 exit (1) ;
131 } /* report_format_error_exit */
132
133 int
main(int argc,char * argv[])134 main (int argc, char * argv [])
135 { const char *progname, *infilename, *outfilename ;
136 SNDFILE *infile = NULL, *outfile = NULL ;
137 SF_INFO sfinfo ;
138 int k, outfilemajor, outfileminor = 0, infileminor ;
139 int override_sample_rate = 0 ; /* assume no sample rate override. */
140 int endian = SF_ENDIAN_FILE, normalize = SF_FALSE ;
141
142 progname = program_name (argv [0]) ;
143
144 if (argc < 3 || argc > 5)
145 usage_exit (progname) ;
146
147 infilename = argv [argc-2] ;
148 outfilename = argv [argc-1] ;
149
150 if (strcmp (infilename, outfilename) == 0)
151 { printf ("Error : Input and output filenames are the same.\n\n") ;
152 usage_exit (progname) ;
153 } ;
154
155 if (strlen (infilename) > 1 && infilename [0] == '-')
156 { printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ;
157 usage_exit (progname) ;
158 } ;
159
160 if (outfilename [0] == '-')
161 { printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ;
162 usage_exit (progname) ;
163 } ;
164
165 for (k = 1 ; k < argc - 2 ; k++)
166 { if (! strcmp (argv [k], "-pcms8"))
167 { outfileminor = SF_FORMAT_PCM_S8 ;
168 continue ;
169 } ;
170 if (! strcmp (argv [k], "-pcmu8"))
171 { outfileminor = SF_FORMAT_PCM_U8 ;
172 continue ;
173 } ;
174 if (! strcmp (argv [k], "-pcm16"))
175 { outfileminor = SF_FORMAT_PCM_16 ;
176 continue ;
177 } ;
178 if (! strcmp (argv [k], "-pcm24"))
179 { outfileminor = SF_FORMAT_PCM_24 ;
180 continue ;
181 } ;
182 if (! strcmp (argv [k], "-pcm32"))
183 { outfileminor = SF_FORMAT_PCM_32 ;
184 continue ;
185 } ;
186 if (! strcmp (argv [k], "-float32"))
187 { outfileminor = SF_FORMAT_FLOAT ;
188 continue ;
189 } ;
190 if (! strcmp (argv [k], "-float64"))
191 { outfileminor = SF_FORMAT_DOUBLE ;
192 continue ;
193 } ;
194 if (! strcmp (argv [k], "-ulaw"))
195 { outfileminor = SF_FORMAT_ULAW ;
196 continue ;
197 } ;
198 if (! strcmp (argv [k], "-alaw"))
199 { outfileminor = SF_FORMAT_ALAW ;
200 continue ;
201 } ;
202 if (! strcmp (argv [k], "-alac16"))
203 { outfileminor = SF_FORMAT_ALAC_16 ;
204 continue ;
205 } ;
206 if (! strcmp (argv [k], "-alac20"))
207 { outfileminor = SF_FORMAT_ALAC_20 ;
208 continue ;
209 } ;
210 if (! strcmp (argv [k], "-alac24"))
211 { outfileminor = SF_FORMAT_ALAC_24 ;
212 continue ;
213 } ;
214 if (! strcmp (argv [k], "-alac32"))
215 { outfileminor = SF_FORMAT_ALAC_32 ;
216 continue ;
217 } ;
218 if (! strcmp (argv [k], "-ima-adpcm"))
219 { outfileminor = SF_FORMAT_IMA_ADPCM ;
220 continue ;
221 } ;
222 if (! strcmp (argv [k], "-ms-adpcm"))
223 { outfileminor = SF_FORMAT_MS_ADPCM ;
224 continue ;
225 } ;
226 if (! strcmp (argv [k], "-gsm610"))
227 { outfileminor = SF_FORMAT_GSM610 ;
228 continue ;
229 } ;
230 if (! strcmp (argv [k], "-dwvw12"))
231 { outfileminor = SF_FORMAT_DWVW_12 ;
232 continue ;
233 } ;
234 if (! strcmp (argv [k], "-dwvw16"))
235 { outfileminor = SF_FORMAT_DWVW_16 ;
236 continue ;
237 } ;
238 if (! strcmp (argv [k], "-dwvw24"))
239 { outfileminor = SF_FORMAT_DWVW_24 ;
240 continue ;
241 } ;
242 if (! strcmp (argv [k], "-vorbis"))
243 { outfileminor = SF_FORMAT_VORBIS ;
244 continue ;
245 } ;
246 if (! strcmp (argv [k], "-opus"))
247 { outfileminor = SF_FORMAT_OPUS ;
248 continue ;
249 } ;
250
251 if (strstr (argv [k], "-override-sample-rate=") == argv [k])
252 { const char *ptr ;
253
254 ptr = argv [k] + strlen ("-override-sample-rate=") ;
255 override_sample_rate = atoi (ptr) ;
256 continue ;
257 } ;
258
259 if (! strcmp (argv [k], "-endian=little"))
260 { endian = SF_ENDIAN_LITTLE ;
261 continue ;
262 } ;
263
264 if (! strcmp (argv [k], "-endian=big"))
265 { endian = SF_ENDIAN_BIG ;
266 continue ;
267 } ;
268
269 if (! strcmp (argv [k], "-endian=cpu"))
270 { endian = SF_ENDIAN_CPU ;
271 continue ;
272 } ;
273
274 if (! strcmp (argv [k], "-endian=file"))
275 { endian = SF_ENDIAN_FILE ;
276 continue ;
277 } ;
278
279 if (! strcmp (argv [k], "-normalize"))
280 { normalize = SF_TRUE ;
281 continue ;
282 } ;
283
284 printf ("Error : Not able to decode argunment '%s'.\n", argv [k]) ;
285 exit (1) ;
286 } ;
287
288 memset (&sfinfo, 0, sizeof (sfinfo)) ;
289
290 if ((infile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL)
291 { printf ("Not able to open input file %s.\n", infilename) ;
292 puts (sf_strerror (NULL)) ;
293 return 1 ;
294 } ;
295
296 /* Update sample rate if forced to something else. */
297 if (override_sample_rate)
298 sfinfo.samplerate = override_sample_rate ;
299
300 infileminor = sfinfo.format & SF_FORMAT_SUBMASK ;
301
302 if ((sfinfo.format = sfe_file_type_of_ext (outfilename, sfinfo.format)) == 0)
303 { printf ("Error : Not able to determine output file type for %s.\n", outfilename) ;
304 return 1 ;
305 } ;
306
307 outfilemajor = sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_ENDMASK) ;
308
309 if (outfileminor == 0)
310 outfileminor = sfinfo.format & SF_FORMAT_SUBMASK ;
311
312 if (outfileminor != 0)
313 sfinfo.format = outfilemajor | outfileminor ;
314 else
315 sfinfo.format = outfilemajor | (sfinfo.format & SF_FORMAT_SUBMASK) ;
316
317 sfinfo.format |= endian ;
318
319 if ((sfinfo.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_XI)
320 switch (sfinfo.format & SF_FORMAT_SUBMASK)
321 { case SF_FORMAT_PCM_16 :
322 sfinfo.format = outfilemajor | SF_FORMAT_DPCM_16 ;
323 break ;
324
325 case SF_FORMAT_PCM_S8 :
326 case SF_FORMAT_PCM_U8 :
327 sfinfo.format = outfilemajor | SF_FORMAT_DPCM_8 ;
328 break ;
329 } ;
330
331 if (sf_format_check (&sfinfo) == 0)
332 { sf_close (infile) ;
333 report_format_error_exit (argv [0], &sfinfo) ;
334 } ;
335
336 if ((sfinfo.format & SF_FORMAT_SUBMASK) == SF_FORMAT_GSM610 && sfinfo.samplerate != 8000)
337 { printf (
338 "WARNING: GSM 6.10 data format only supports 8kHz sample rate. The converted\n"
339 "ouput file will contain the input data converted to the GSM 6.10 data format\n"
340 "but not re-sampled.\n"
341 ) ;
342 } ;
343
344 /* Open the output file. */
345 if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo)) == NULL)
346 { printf ("Not able to open output file %s : %s\n", outfilename, sf_strerror (NULL)) ;
347 return 1 ;
348 } ;
349
350 /* Copy the metadata */
351 copy_metadata (outfile, infile, sfinfo.channels) ;
352
353 if (normalize
354 || (outfileminor == SF_FORMAT_DOUBLE) || (outfileminor == SF_FORMAT_FLOAT)
355 || (infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT)
356 || (infileminor == SF_FORMAT_OPUS) || (outfileminor == SF_FORMAT_OPUS)
357 || (infileminor == SF_FORMAT_VORBIS) || (outfileminor == SF_FORMAT_VORBIS))
358 { if (sfe_copy_data_fp (outfile, infile, sfinfo.channels, normalize) != 0)
359 { printf ("Error : Not able to decode input file %s.\n", infilename) ;
360 return 1 ;
361 } ;
362 }
363 else
364 sfe_copy_data_int (outfile, infile, sfinfo.channels) ;
365
366 sf_close (infile) ;
367 sf_close (outfile) ;
368
369 return 0 ;
370 } /* main */
371
372 static void
copy_metadata(SNDFILE * outfile,SNDFILE * infile,int channels)373 copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels)
374 { SF_INSTRUMENT inst ;
375 SF_CUES cues ;
376 SF_BROADCAST_INFO_2K binfo ;
377 const char *str ;
378 int k, chanmap [256] ;
379
380 for (k = SF_STR_FIRST ; k <= SF_STR_LAST ; k++)
381 { str = sf_get_string (infile, k) ;
382 if (str != NULL)
383 sf_set_string (outfile, k, str) ;
384 } ;
385
386 memset (&inst, 0, sizeof (inst)) ;
387 memset (&cues, 0, sizeof (cues)) ;
388 memset (&binfo, 0, sizeof (binfo)) ;
389
390 if (channels < ARRAY_LEN (chanmap))
391 { size_t size = channels * sizeof (chanmap [0]) ;
392
393 if (sf_command (infile, SFC_GET_CHANNEL_MAP_INFO, chanmap, size) == SF_TRUE)
394 sf_command (outfile, SFC_SET_CHANNEL_MAP_INFO, chanmap, size) ;
395 } ;
396
397 if (sf_command (infile, SFC_GET_CUE, &cues, sizeof (cues)) == SF_TRUE)
398 sf_command (outfile, SFC_SET_CUE, &cues, sizeof (cues)) ;
399
400 if (sf_command (infile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE)
401 sf_command (outfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) ;
402
403 if (sf_command (infile, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == SF_TRUE)
404 sf_command (outfile, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) ;
405
406 } /* copy_metadata */
407
408