You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
8.6KB

  1. /*
  2. ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
  3. ** All rights reserved.
  4. **
  5. ** This code is released under 2-clause BSD license. Please see the
  6. ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
  7. */
  8. #include "config.h"
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #if (HAVE_SNDFILE)
  15. #include <samplerate.h>
  16. #include <sndfile.h>
  17. #define DEFAULT_CONVERTER SRC_SINC_MEDIUM_QUALITY
  18. #define BUFFER_LEN 4096 /*-(1<<16)-*/
  19. static void usage_exit (const char *progname) ;
  20. static sf_count_t sample_rate_convert (SNDFILE *infile, SNDFILE *outfile, int converter, double src_ratio, int channels, double * gain, int normalize) ;
  21. static double apply_gain (float * data, long frames, int channels, double max, double gain) ;
  22. int
  23. main (int argc, char *argv [])
  24. { SNDFILE *infile, *outfile = NULL ;
  25. SF_INFO sfinfo ;
  26. int normalize = 1 ;
  27. sf_count_t count ;
  28. double src_ratio = -1.0, gain = 1.0 ;
  29. int new_sample_rate = -1, k, converter, max_speed = SF_FALSE ;
  30. if (argc == 2 && strcmp (argv [1], "--version") == 0)
  31. { char buffer [64], *cptr ;
  32. if ((cptr = strrchr (argv [0], '/')) != NULL)
  33. argv [0] = cptr + 1 ;
  34. if ((cptr = strrchr (argv [0], '\\')) != NULL)
  35. argv [0] = cptr + 1 ;
  36. sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
  37. printf ("%s (%s,%s)\n", argv [0], src_get_version (), buffer) ;
  38. exit (0) ;
  39. } ;
  40. if (argc != 5 && argc != 7 && argc != 8)
  41. usage_exit (argv [0]) ;
  42. /* Set default converter. */
  43. converter = DEFAULT_CONVERTER ;
  44. for (k = 1 ; k < argc - 2 ; k++)
  45. { if (strcmp (argv [k], "--max-speed") == 0)
  46. max_speed = SF_TRUE ;
  47. else if (strcmp (argv [k], "--no-normalize") == 0)
  48. normalize = 0 ;
  49. else if (strcmp (argv [k], "-to") == 0)
  50. { k ++ ;
  51. new_sample_rate = atoi (argv [k]) ;
  52. }
  53. else if (strcmp (argv [k], "-by") == 0)
  54. { k ++ ;
  55. src_ratio = atof (argv [k]) ;
  56. }
  57. else if (strcmp (argv [k], "-c") == 0)
  58. { k ++ ;
  59. converter = atoi (argv [k]) ;
  60. }
  61. else
  62. usage_exit (argv [0]) ;
  63. } ;
  64. if (new_sample_rate <= 0 && src_ratio <= 0.0)
  65. usage_exit (argv [0]) ;
  66. if (src_get_name (converter) == NULL)
  67. { printf ("Error : bad converter number.\n") ;
  68. usage_exit (argv [0]) ;
  69. } ;
  70. if (strcmp (argv [argc - 2], argv [argc - 1]) == 0)
  71. { printf ("Error : input and output file names are the same.\n") ;
  72. exit (1) ;
  73. } ;
  74. if ((infile = sf_open (argv [argc - 2], SFM_READ, &sfinfo)) == NULL)
  75. { printf ("Error : Not able to open input file '%s'\n", argv [argc - 2]) ;
  76. exit (1) ;
  77. } ;
  78. printf ("Input File : %s\n", argv [argc - 2]) ;
  79. printf ("Sample Rate : %d\n", sfinfo.samplerate) ;
  80. printf ("Input Frames : %ld\n\n", (long) sfinfo.frames) ;
  81. if (new_sample_rate > 0)
  82. { src_ratio = (1.0 * new_sample_rate) / sfinfo.samplerate ;
  83. sfinfo.samplerate = new_sample_rate ;
  84. }
  85. else if (src_is_valid_ratio (src_ratio))
  86. sfinfo.samplerate = (int) floor (sfinfo.samplerate * src_ratio) ;
  87. else
  88. { printf ("Not able to determine new sample rate. Exiting.\n") ;
  89. sf_close (infile) ;
  90. exit (1) ;
  91. } ;
  92. if (fabs (src_ratio - 1.0) < 1e-20)
  93. { printf ("Target samplerate and input samplerate are the same. Exiting.\n") ;
  94. sf_close (infile) ;
  95. exit (0) ;
  96. } ;
  97. printf ("SRC Ratio : %f\n", src_ratio) ;
  98. printf ("Converter : %s\n\n", src_get_name (converter)) ;
  99. if (src_is_valid_ratio (src_ratio) == 0)
  100. { printf ("Error : Sample rate change out of valid range.\n") ;
  101. sf_close (infile) ;
  102. exit (1) ;
  103. } ;
  104. /* Delete the output file length to zero if already exists. */
  105. remove (argv [argc - 1]) ;
  106. printf ("Output file : %s\n", argv [argc - 1]) ;
  107. printf ("Sample Rate : %d\n", sfinfo.samplerate) ;
  108. do
  109. { sf_close (outfile) ;
  110. if ((outfile = sf_open (argv [argc - 1], SFM_WRITE, &sfinfo)) == NULL)
  111. { printf ("Error : Not able to open output file '%s'\n", argv [argc - 1]) ;
  112. sf_close (infile) ;
  113. exit (1) ;
  114. } ;
  115. if (max_speed)
  116. { /* This is mainly for the comparison program tests/src-evaluate.c */
  117. sf_command (outfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ;
  118. }
  119. else
  120. { /* Update the file header after every write. */
  121. sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) ;
  122. } ;
  123. sf_command (outfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ;
  124. count = sample_rate_convert (infile, outfile, converter, src_ratio, sfinfo.channels, &gain, normalize) ;
  125. }
  126. while (count < 0) ;
  127. printf ("Output Frames : %ld\n\n", (long) count) ;
  128. sf_close (infile) ;
  129. sf_close (outfile) ;
  130. return 0 ;
  131. } /* main */
  132. /*==============================================================================
  133. */
  134. static sf_count_t
  135. sample_rate_convert (SNDFILE *infile, SNDFILE *outfile, int converter, double src_ratio, int channels, double * gain, int normalize)
  136. { static float input [BUFFER_LEN] ;
  137. static float output [BUFFER_LEN] ;
  138. SRC_STATE *src_state ;
  139. SRC_DATA src_data ;
  140. int error ;
  141. double max = 0.0 ;
  142. sf_count_t output_count = 0 ;
  143. sf_seek (infile, 0, SEEK_SET) ;
  144. sf_seek (outfile, 0, SEEK_SET) ;
  145. /* Initialize the sample rate converter. */
  146. if ((src_state = src_new (converter, channels, &error)) == NULL)
  147. { printf ("\n\nError : src_new() failed : %s.\n\n", src_strerror (error)) ;
  148. exit (1) ;
  149. } ;
  150. src_data.end_of_input = 0 ; /* Set this later. */
  151. /* Start with zero to force load in while loop. */
  152. src_data.input_frames = 0 ;
  153. src_data.data_in = input ;
  154. src_data.src_ratio = src_ratio ;
  155. src_data.data_out = output ;
  156. src_data.output_frames = BUFFER_LEN /channels ;
  157. while (1)
  158. {
  159. /* If the input buffer is empty, refill it. */
  160. if (src_data.input_frames == 0)
  161. { src_data.input_frames = sf_readf_float (infile, input, BUFFER_LEN / channels) ;
  162. src_data.data_in = input ;
  163. /* The last read will not be a full buffer, so snd_of_input. */
  164. if (src_data.input_frames < BUFFER_LEN / channels)
  165. src_data.end_of_input = SF_TRUE ;
  166. } ;
  167. if ((error = src_process (src_state, &src_data)))
  168. { printf ("\nError : %s\n", src_strerror (error)) ;
  169. exit (1) ;
  170. } ;
  171. /* Terminate if done. */
  172. if (src_data.end_of_input && src_data.output_frames_gen == 0)
  173. break ;
  174. max = apply_gain (src_data.data_out, src_data.output_frames_gen, channels, max, *gain) ;
  175. /* Write output. */
  176. sf_writef_float (outfile, output, src_data.output_frames_gen) ;
  177. output_count += src_data.output_frames_gen ;
  178. src_data.data_in += src_data.input_frames_used * channels ;
  179. src_data.input_frames -= src_data.input_frames_used ;
  180. } ;
  181. src_delete (src_state) ;
  182. if (normalize && max > 1.0)
  183. { *gain = 1.0 / max ;
  184. printf ("\nOutput has clipped. Restarting conversion to prevent clipping.\n\n") ;
  185. return -1 ;
  186. } ;
  187. return output_count ;
  188. } /* sample_rate_convert */
  189. static double
  190. apply_gain (float * data, long frames, int channels, double max, double gain)
  191. {
  192. long k ;
  193. for (k = 0 ; k < frames * channels ; k++)
  194. { data [k] *= gain ;
  195. if (fabs (data [k]) > max)
  196. max = fabs (data [k]) ;
  197. } ;
  198. return max ;
  199. } /* apply_gain */
  200. static void
  201. usage_exit (const char *progname)
  202. { char lsf_ver [128] ;
  203. const char *cptr ;
  204. int k ;
  205. if ((cptr = strrchr (progname, '/')) != NULL)
  206. progname = cptr + 1 ;
  207. if ((cptr = strrchr (progname, '\\')) != NULL)
  208. progname = cptr + 1 ;
  209. sf_command (NULL, SFC_GET_LIB_VERSION, lsf_ver, sizeof (lsf_ver)) ;
  210. printf ("\n"
  211. " A Sample Rate Converter using libsndfile for file I/O and Secret \n"
  212. " Rabbit Code (aka libsamplerate) for performing the conversion.\n"
  213. " It works on any file format supported by libsndfile with any \n"
  214. " number of channels (limited only by host memory).\n"
  215. "\n"
  216. " %s\n"
  217. " %s\n"
  218. "\n"
  219. " Usage : \n"
  220. " %s -to <new sample rate> [-c <number>] <input file> <output file>\n"
  221. " %s -by <amount> [-c <number>] <input file> <output file>\n"
  222. "\n", src_get_version (), lsf_ver, progname, progname) ;
  223. puts (
  224. " The optional -c argument allows the converter type to be chosen from\n"
  225. " the following list :"
  226. "\n"
  227. ) ;
  228. for (k = 0 ; (cptr = src_get_name (k)) != NULL ; k++)
  229. printf (" %d : %s%s\n", k, cptr, k == DEFAULT_CONVERTER ? " (default)" : "") ;
  230. puts ("\n"
  231. " The --no-normalize option disables clipping check and normalization.") ;
  232. puts ("") ;
  233. exit (1) ;
  234. } /* usage_exit */
  235. /*==============================================================================
  236. */
  237. #else /* (HAVE_SNFILE == 0) */
  238. /* Alternative main function when libsndfile is not available. */
  239. int
  240. main (void)
  241. { puts (
  242. "\n"
  243. "****************************************************************\n"
  244. " This example program was compiled without libsndfile \n"
  245. " (http://www.mega-nerd.com/libsndfile/).\n"
  246. " It is therefore completely broken and non-functional.\n"
  247. "****************************************************************\n"
  248. "\n"
  249. ) ;
  250. return 0 ;
  251. } /* main */
  252. #endif