Chris@0
|
1 /*
|
Chris@0
|
2 ** Copyright (C) 2005-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
|
Chris@0
|
3 **
|
Chris@0
|
4 ** This program is free software; you can redistribute it and/or modify
|
Chris@0
|
5 ** it under the terms of the GNU General Public License as published by
|
Chris@0
|
6 ** the Free Software Foundation; either version 2 of the License, or
|
Chris@0
|
7 ** (at your option) any later version.
|
Chris@0
|
8 **
|
Chris@0
|
9 ** This program is distributed in the hope that it will be useful,
|
Chris@0
|
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@0
|
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@0
|
12 ** GNU General Public License for more details.
|
Chris@0
|
13 **
|
Chris@0
|
14 ** You should have received a copy of the GNU General Public License
|
Chris@0
|
15 ** along with this program; if not, write to the Free Software
|
Chris@0
|
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
Chris@0
|
17 */
|
Chris@0
|
18
|
Chris@0
|
19 #include "config.h"
|
Chris@0
|
20
|
Chris@0
|
21 #include <stdio.h>
|
Chris@0
|
22 #include <stdlib.h>
|
Chris@0
|
23 #include <unistd.h>
|
Chris@0
|
24 #include <string.h>
|
Chris@0
|
25 #include <math.h>
|
Chris@0
|
26
|
Chris@0
|
27 #if (HAVE_SNDFILE)
|
Chris@0
|
28
|
Chris@0
|
29 #include <samplerate.h>
|
Chris@0
|
30 #include <sndfile.h>
|
Chris@0
|
31
|
Chris@0
|
32 #define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
|
Chris@0
|
33
|
Chris@0
|
34 #define DEFAULT_CONVERTER SRC_SINC_MEDIUM_QUALITY
|
Chris@0
|
35
|
Chris@0
|
36 #define BUFFER_LEN 1024
|
Chris@0
|
37 #define INPUT_STEP_SIZE 8
|
Chris@0
|
38
|
Chris@0
|
39 typedef struct
|
Chris@0
|
40 { sf_count_t index ;
|
Chris@0
|
41 double ratio ;
|
Chris@0
|
42 } TIMEWARP_FACTOR ;
|
Chris@0
|
43
|
Chris@0
|
44 static void usage_exit (const char *progname) ;
|
Chris@0
|
45 static sf_count_t timewarp_convert (SNDFILE *infile, SNDFILE *outfile, int converter, int channels) ;
|
Chris@0
|
46
|
Chris@0
|
47 int
|
Chris@0
|
48 main (int argc, char *argv [])
|
Chris@0
|
49 { SNDFILE *infile, *outfile ;
|
Chris@0
|
50 SF_INFO sfinfo ;
|
Chris@0
|
51 sf_count_t count ;
|
Chris@0
|
52
|
Chris@0
|
53 if (argc != 3)
|
Chris@0
|
54 usage_exit (argv [0]) ;
|
Chris@0
|
55
|
Chris@0
|
56 putchar ('\n') ;
|
Chris@0
|
57 printf ("Input File : %s\n", argv [argc - 2]) ;
|
Chris@0
|
58 if ((infile = sf_open (argv [argc - 2], SFM_READ, &sfinfo)) == NULL)
|
Chris@0
|
59 { printf ("Error : Not able to open input file '%s'\n", argv [argc - 2]) ;
|
Chris@0
|
60 exit (1) ;
|
Chris@0
|
61 } ;
|
Chris@0
|
62
|
Chris@0
|
63 if (INPUT_STEP_SIZE * sfinfo.channels > BUFFER_LEN)
|
Chris@0
|
64 { printf ("\n\nError : INPUT_STEP_SIZE * sfinfo.channels > BUFFER_LEN\n\n") ;
|
Chris@0
|
65 exit (1) ;
|
Chris@0
|
66 } ;
|
Chris@0
|
67
|
Chris@0
|
68
|
Chris@0
|
69 /* Delete the output file length to zero if already exists. */
|
Chris@0
|
70 remove (argv [argc - 1]) ;
|
Chris@0
|
71
|
Chris@0
|
72 if ((outfile = sf_open (argv [argc - 1], SFM_WRITE, &sfinfo)) == NULL)
|
Chris@0
|
73 { printf ("Error : Not able to open output file '%s'\n", argv [argc - 1]) ;
|
Chris@0
|
74 sf_close (infile) ;
|
Chris@0
|
75 exit (1) ;
|
Chris@0
|
76 } ;
|
Chris@0
|
77
|
Chris@0
|
78 sf_command (outfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ;
|
Chris@0
|
79
|
Chris@0
|
80 printf ("Output file : %s\n", argv [argc - 1]) ;
|
Chris@0
|
81 printf ("Converter : %s\n", src_get_name (DEFAULT_CONVERTER)) ;
|
Chris@0
|
82
|
Chris@0
|
83 count = timewarp_convert (infile, outfile, DEFAULT_CONVERTER, sfinfo.channels) ;
|
Chris@0
|
84
|
Chris@0
|
85 printf ("Output Frames : %ld\n\n", (long) count) ;
|
Chris@0
|
86
|
Chris@0
|
87 sf_close (infile) ;
|
Chris@0
|
88 sf_close (outfile) ;
|
Chris@0
|
89
|
Chris@0
|
90 return 0 ;
|
Chris@0
|
91 } /* main */
|
Chris@0
|
92
|
Chris@0
|
93 /*==============================================================================
|
Chris@0
|
94 */
|
Chris@0
|
95
|
Chris@0
|
96 static TIMEWARP_FACTOR warp [] =
|
Chris@0
|
97 { { 0 , 1.00000001 },
|
Chris@0
|
98 { 20000 , 1.01000000 },
|
Chris@0
|
99 { 20200 , 1.00000001 },
|
Chris@0
|
100 { 40000 , 1.20000000 },
|
Chris@0
|
101 { 40300 , 1.00000001 },
|
Chris@0
|
102 { 60000 , 1.10000000 },
|
Chris@0
|
103 { 60400 , 1.00000001 },
|
Chris@0
|
104 { 80000 , 1.50000000 },
|
Chris@0
|
105 { 81000 , 1.00000001 },
|
Chris@0
|
106 } ;
|
Chris@0
|
107
|
Chris@0
|
108 static sf_count_t
|
Chris@0
|
109 timewarp_convert (SNDFILE *infile, SNDFILE *outfile, int converter, int channels)
|
Chris@0
|
110 { static float input [BUFFER_LEN] ;
|
Chris@0
|
111 static float output [BUFFER_LEN] ;
|
Chris@0
|
112
|
Chris@0
|
113 SRC_STATE *src_state ;
|
Chris@0
|
114 SRC_DATA src_data ;
|
Chris@0
|
115 int error, warp_index = 0 ;
|
Chris@0
|
116 sf_count_t input_count = 0, output_count = 0 ;
|
Chris@0
|
117
|
Chris@0
|
118 sf_seek (infile, 0, SEEK_SET) ;
|
Chris@0
|
119 sf_seek (outfile, 0, SEEK_SET) ;
|
Chris@0
|
120
|
Chris@0
|
121 /* Initialize the sample rate converter. */
|
Chris@0
|
122 if ((src_state = src_new (converter, channels, &error)) == NULL)
|
Chris@0
|
123 { printf ("\n\nError : src_new() failed : %s.\n\n", src_strerror (error)) ;
|
Chris@0
|
124 exit (1) ;
|
Chris@0
|
125 } ;
|
Chris@0
|
126
|
Chris@0
|
127 src_data.end_of_input = 0 ; /* Set this later. */
|
Chris@0
|
128
|
Chris@0
|
129 /* Start with zero to force load in while loop. */
|
Chris@0
|
130 src_data.input_frames = 0 ;
|
Chris@0
|
131 src_data.data_in = input ;
|
Chris@0
|
132
|
Chris@0
|
133 if (warp [0].index > 0)
|
Chris@0
|
134 src_data.src_ratio = 1.0 ;
|
Chris@0
|
135 else
|
Chris@0
|
136 { src_data.src_ratio = warp [0].ratio ;
|
Chris@0
|
137 warp_index ++ ;
|
Chris@0
|
138 } ;
|
Chris@0
|
139
|
Chris@0
|
140 src_data.data_out = output ;
|
Chris@0
|
141 src_data.output_frames = BUFFER_LEN /channels ;
|
Chris@0
|
142
|
Chris@0
|
143 while (1)
|
Chris@0
|
144 {
|
Chris@0
|
145 if (warp_index < ARRAY_LEN (warp) - 1 && input_count >= warp [warp_index].index)
|
Chris@0
|
146 { src_data.src_ratio = warp [warp_index].ratio ;
|
Chris@0
|
147 warp_index ++ ;
|
Chris@0
|
148 } ;
|
Chris@0
|
149
|
Chris@0
|
150 /* If the input buffer is empty, refill it. */
|
Chris@0
|
151 if (src_data.input_frames == 0)
|
Chris@0
|
152 { src_data.input_frames = sf_readf_float (infile, input, INPUT_STEP_SIZE) ;
|
Chris@0
|
153 input_count += src_data.input_frames ;
|
Chris@0
|
154 src_data.data_in = input ;
|
Chris@0
|
155
|
Chris@0
|
156 /* The last read will not be a full buffer, so snd_of_input. */
|
Chris@0
|
157 if (src_data.input_frames < INPUT_STEP_SIZE)
|
Chris@0
|
158 src_data.end_of_input = SF_TRUE ;
|
Chris@0
|
159 } ;
|
Chris@0
|
160
|
Chris@0
|
161 /* Process current block. */
|
Chris@0
|
162 if ((error = src_process (src_state, &src_data)))
|
Chris@0
|
163 { printf ("\nError : %s\n", src_strerror (error)) ;
|
Chris@0
|
164 exit (1) ;
|
Chris@0
|
165 } ;
|
Chris@0
|
166
|
Chris@0
|
167 /* Terminate if done. */
|
Chris@0
|
168 if (src_data.end_of_input && src_data.output_frames_gen == 0)
|
Chris@0
|
169 break ;
|
Chris@0
|
170
|
Chris@0
|
171 /* Write output. */
|
Chris@0
|
172 sf_writef_float (outfile, output, src_data.output_frames_gen) ;
|
Chris@0
|
173 output_count += src_data.output_frames_gen ;
|
Chris@0
|
174
|
Chris@0
|
175 src_data.data_in += src_data.input_frames_used * channels ;
|
Chris@0
|
176 src_data.input_frames -= src_data.input_frames_used ;
|
Chris@0
|
177 } ;
|
Chris@0
|
178
|
Chris@0
|
179 src_state = src_delete (src_state) ;
|
Chris@0
|
180
|
Chris@0
|
181 return output_count ;
|
Chris@0
|
182 } /* timewarp_convert */
|
Chris@0
|
183
|
Chris@0
|
184 /*------------------------------------------------------------------------------
|
Chris@0
|
185 */
|
Chris@0
|
186
|
Chris@0
|
187 static void
|
Chris@0
|
188 usage_exit (const char *progname)
|
Chris@0
|
189 { const char *cptr ;
|
Chris@0
|
190
|
Chris@0
|
191 if ((cptr = strrchr (progname, '/')) != NULL)
|
Chris@0
|
192 progname = cptr + 1 ;
|
Chris@0
|
193
|
Chris@0
|
194 if ((cptr = strrchr (progname, '\\')) != NULL)
|
Chris@0
|
195 progname = cptr + 1 ;
|
Chris@0
|
196
|
Chris@0
|
197 printf ("\n"
|
Chris@0
|
198 " A program demonstrating the time warping capabilities of libsamplerate."
|
Chris@0
|
199 " It uses libsndfile for file I/O and Secret Rabbit Code (aka libsamplerate)"
|
Chris@0
|
200 " for performing the warping.\n"
|
Chris@0
|
201 " It works on any file format supported by libsndfile with any \n"
|
Chris@0
|
202 " number of channels (limited only by host memory).\n"
|
Chris@0
|
203 "\n"
|
Chris@0
|
204 " The warping is dependant on a table hard code into the source code.\n"
|
Chris@0
|
205 "\n"
|
Chris@0
|
206 " libsamplerate version : %s\n"
|
Chris@0
|
207 "\n"
|
Chris@0
|
208 " Usage : \n"
|
Chris@0
|
209 " %s <input file> <output file>\n"
|
Chris@0
|
210 "\n", src_get_version (), progname) ;
|
Chris@0
|
211
|
Chris@0
|
212 puts ("") ;
|
Chris@0
|
213
|
Chris@0
|
214 exit (1) ;
|
Chris@0
|
215 } /* usage_exit */
|
Chris@0
|
216
|
Chris@0
|
217 /*==============================================================================
|
Chris@0
|
218 */
|
Chris@0
|
219
|
Chris@0
|
220 #else /* (HAVE_SNFILE == 0) */
|
Chris@0
|
221
|
Chris@0
|
222 /* Alternative main function when libsndfile is not available. */
|
Chris@0
|
223
|
Chris@0
|
224 int
|
Chris@0
|
225 main (void)
|
Chris@0
|
226 { puts (
|
Chris@0
|
227 "\n"
|
Chris@0
|
228 "****************************************************************\n"
|
Chris@0
|
229 " This example program was compiled without libsndfile \n"
|
Chris@0
|
230 " (http://www.mega-nerd.com/libsndfile/).\n"
|
Chris@0
|
231 " It is therefore completely broken and non-functional.\n"
|
Chris@0
|
232 "****************************************************************\n"
|
Chris@0
|
233 "\n"
|
Chris@0
|
234 ) ;
|
Chris@0
|
235
|
Chris@0
|
236 return 0 ;
|
Chris@0
|
237 } /* main */
|
Chris@0
|
238
|
Chris@0
|
239 #endif
|
Chris@0
|
240
|