2 ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** All rights reserved.
5 ** This code is released under 2-clause BSD license. Please see the
6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
19 #include <samplerate.h>
22 #define DEFAULT_CONVERTER SRC_SINC_MEDIUM_QUALITY
24 #define BUFFER_LEN 4096 /*-(1<<16)-*/
26 static void usage_exit (const char *progname
) ;
27 static sf_count_t
sample_rate_convert (SNDFILE
*infile
, SNDFILE
*outfile
, int converter
, double src_ratio
, int channels
, double * gain
, int normalize
) ;
28 static double apply_gain (float * data
, long frames
, int channels
, double max
, double gain
) ;
31 main (int argc
, char *argv
[])
32 { SNDFILE
*infile
, *outfile
= NULL
;
37 double src_ratio
= -1.0, gain
= 1.0 ;
38 int new_sample_rate
= -1, k
, converter
, max_speed
= SF_FALSE
;
40 if (argc
== 2 && strcmp (argv
[1], "--version") == 0)
41 { char buffer
[64], *cptr
;
43 if ((cptr
= strrchr (argv
[0], '/')) != NULL
)
45 if ((cptr
= strrchr (argv
[0], '\\')) != NULL
)
48 sf_command (NULL
, SFC_GET_LIB_VERSION
, buffer
, sizeof (buffer
)) ;
50 printf ("%s (%s,%s)\n", argv
[0], src_get_version (), buffer
) ;
54 if (argc
!= 5 && argc
!= 7 && argc
!= 8)
55 usage_exit (argv
[0]) ;
57 /* Set default converter. */
58 converter
= DEFAULT_CONVERTER
;
60 for (k
= 1 ; k
< argc
- 2 ; k
++)
61 { if (strcmp (argv
[k
], "--max-speed") == 0)
63 else if (strcmp (argv
[k
], "--no-normalize") == 0)
65 else if (strcmp (argv
[k
], "-to") == 0)
67 new_sample_rate
= atoi (argv
[k
]) ;
69 else if (strcmp (argv
[k
], "-by") == 0)
71 src_ratio
= atof (argv
[k
]) ;
73 else if (strcmp (argv
[k
], "-c") == 0)
75 converter
= atoi (argv
[k
]) ;
78 usage_exit (argv
[0]) ;
81 if (new_sample_rate
<= 0 && src_ratio
<= 0.0)
82 usage_exit (argv
[0]) ;
84 if (src_get_name (converter
) == NULL
)
85 { printf ("Error : bad converter number.\n") ;
86 usage_exit (argv
[0]) ;
89 if (strcmp (argv
[argc
- 2], argv
[argc
- 1]) == 0)
90 { printf ("Error : input and output file names are the same.\n") ;
94 if ((infile
= sf_open (argv
[argc
- 2], SFM_READ
, &sfinfo
)) == NULL
)
95 { printf ("Error : Not able to open input file '%s'\n", argv
[argc
- 2]) ;
99 printf ("Input File : %s\n", argv
[argc
- 2]) ;
100 printf ("Sample Rate : %d\n", sfinfo
.samplerate
) ;
101 printf ("Input Frames : %ld\n\n", (long) sfinfo
.frames
) ;
103 if (new_sample_rate
> 0)
104 { src_ratio
= (1.0 * new_sample_rate
) / sfinfo
.samplerate
;
105 sfinfo
.samplerate
= new_sample_rate
;
107 else if (src_is_valid_ratio (src_ratio
))
108 sfinfo
.samplerate
= (int) floor (sfinfo
.samplerate
* src_ratio
) ;
110 { printf ("Not able to determine new sample rate. Exiting.\n") ;
115 if (fabs (src_ratio
- 1.0) < 1e-20)
116 { printf ("Target samplerate and input samplerate are the same. Exiting.\n") ;
121 printf ("SRC Ratio : %f\n", src_ratio
) ;
122 printf ("Converter : %s\n\n", src_get_name (converter
)) ;
124 if (src_is_valid_ratio (src_ratio
) == 0)
125 { printf ("Error : Sample rate change out of valid range.\n") ;
130 /* Delete the output file length to zero if already exists. */
131 remove (argv
[argc
- 1]) ;
133 printf ("Output file : %s\n", argv
[argc
- 1]) ;
134 printf ("Sample Rate : %d\n", sfinfo
.samplerate
) ;
137 { sf_close (outfile
) ;
139 if ((outfile
= sf_open (argv
[argc
- 1], SFM_WRITE
, &sfinfo
)) == NULL
)
140 { printf ("Error : Not able to open output file '%s'\n", argv
[argc
- 1]) ;
146 { /* This is mainly for the comparison program tests/src-evaluate.c */
147 sf_command (outfile
, SFC_SET_ADD_PEAK_CHUNK
, NULL
, SF_FALSE
) ;
150 { /* Update the file header after every write. */
151 sf_command (outfile
, SFC_SET_UPDATE_HEADER_AUTO
, NULL
, SF_TRUE
) ;
154 sf_command (outfile
, SFC_SET_CLIPPING
, NULL
, SF_TRUE
) ;
156 count
= sample_rate_convert (infile
, outfile
, converter
, src_ratio
, sfinfo
.channels
, &gain
, normalize
) ;
160 printf ("Output Frames : %ld\n\n", (long) count
) ;
168 /*==============================================================================
172 sample_rate_convert (SNDFILE
*infile
, SNDFILE
*outfile
, int converter
, double src_ratio
, int channels
, double * gain
, int normalize
)
173 { static float input
[BUFFER_LEN
] ;
174 static float output
[BUFFER_LEN
] ;
176 SRC_STATE
*src_state
;
180 sf_count_t output_count
= 0 ;
182 sf_seek (infile
, 0, SEEK_SET
) ;
183 sf_seek (outfile
, 0, SEEK_SET
) ;
185 /* Initialize the sample rate converter. */
186 if ((src_state
= src_new (converter
, channels
, &error
)) == NULL
)
187 { printf ("\n\nError : src_new() failed : %s.\n\n", src_strerror (error
)) ;
191 src_data
.end_of_input
= 0 ; /* Set this later. */
193 /* Start with zero to force load in while loop. */
194 src_data
.input_frames
= 0 ;
195 src_data
.data_in
= input
;
197 src_data
.src_ratio
= src_ratio
;
199 src_data
.data_out
= output
;
200 src_data
.output_frames
= BUFFER_LEN
/channels
;
204 /* If the input buffer is empty, refill it. */
205 if (src_data
.input_frames
== 0)
206 { src_data
.input_frames
= sf_readf_float (infile
, input
, BUFFER_LEN
/ channels
) ;
207 src_data
.data_in
= input
;
209 /* The last read will not be a full buffer, so snd_of_input. */
210 if (src_data
.input_frames
< BUFFER_LEN
/ channels
)
211 src_data
.end_of_input
= SF_TRUE
;
214 if ((error
= src_process (src_state
, &src_data
)))
215 { printf ("\nError : %s\n", src_strerror (error
)) ;
219 /* Terminate if done. */
220 if (src_data
.end_of_input
&& src_data
.output_frames_gen
== 0)
223 max
= apply_gain (src_data
.data_out
, src_data
.output_frames_gen
, channels
, max
, *gain
) ;
226 sf_writef_float (outfile
, output
, src_data
.output_frames_gen
) ;
227 output_count
+= src_data
.output_frames_gen
;
229 src_data
.data_in
+= src_data
.input_frames_used
* channels
;
230 src_data
.input_frames
-= src_data
.input_frames_used
;
233 src_delete (src_state
) ;
235 if (normalize
&& max
> 1.0)
236 { *gain
= 1.0 / max
;
237 printf ("\nOutput has clipped. Restarting conversion to prevent clipping.\n\n") ;
241 return output_count
;
242 } /* sample_rate_convert */
245 apply_gain (float * data
, long frames
, int channels
, double max
, double gain
)
249 for (k
= 0 ; k
< frames
* channels
; k
++)
252 if (fabs (data
[k
]) > max
)
253 max
= fabs (data
[k
]) ;
260 usage_exit (const char *progname
)
261 { char lsf_ver
[128] ;
265 if ((cptr
= strrchr (progname
, '/')) != NULL
)
266 progname
= cptr
+ 1 ;
268 if ((cptr
= strrchr (progname
, '\\')) != NULL
)
269 progname
= cptr
+ 1 ;
272 sf_command (NULL
, SFC_GET_LIB_VERSION
, lsf_ver
, sizeof (lsf_ver
)) ;
275 " A Sample Rate Converter using libsndfile for file I/O and Secret \n"
276 " Rabbit Code (aka libsamplerate) for performing the conversion.\n"
277 " It works on any file format supported by libsndfile with any \n"
278 " number of channels (limited only by host memory).\n"
284 " %s -to <new sample rate> [-c <number>] <input file> <output file>\n"
285 " %s -by <amount> [-c <number>] <input file> <output file>\n"
286 "\n", src_get_version (), lsf_ver
, progname
, progname
) ;
289 " The optional -c argument allows the converter type to be chosen from\n"
290 " the following list :"
294 for (k
= 0 ; (cptr
= src_get_name (k
)) != NULL
; k
++)
295 printf (" %d : %s%s\n", k
, cptr
, k
== DEFAULT_CONVERTER
? " (default)" : "") ;
298 " The --no-normalize option disables clipping check and normalization.") ;
305 /*==============================================================================
308 #else /* (HAVE_SNFILE == 0) */
310 /* Alternative main function when libsndfile is not available. */
316 "****************************************************************\n"
317 " This example program was compiled without libsndfile \n"
318 " (http://www.mega-nerd.com/libsndfile/).\n"
319 " It is therefore completely broken and non-functional.\n"
320 "****************************************************************\n"