• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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