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