]>
Commit | Line | Data |
---|---|---|
8529da43 MG |
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 | ||
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <unistd.h> | |
12 | #include <string.h> | |
13 | ||
14 | #include "config.h" | |
15 | ||
16 | #include <float_cast.h> | |
17 | ||
18 | #if (HAVE_SNDFILE) | |
19 | ||
20 | #include <samplerate.h> | |
21 | #include <sndfile.h> | |
22 | ||
23 | #include "audio_out.h" | |
24 | ||
25 | #define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0]))) | |
26 | ||
27 | #define BUFFER_LEN 4096 | |
28 | #define VARISPEED_BLOCK_LEN 64 | |
29 | ||
30 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | |
31 | ||
32 | #define SRC_MAGIC ((int) ('S' << 16) + ('R' << 8) + ('C')) | |
33 | #define SNDFILE_MAGIC ((int) ('s' << 24) + ('n' << 20) + ('d' << 16) + ('f' << 12) + ('i' << 8) + ('l' << 4) + 'e') | |
34 | ||
35 | #ifndef M_PI | |
36 | #define M_PI 3.14159265358979323846264338 | |
37 | #endif | |
38 | ||
39 | ||
40 | typedef struct | |
41 | { int magic ; | |
42 | SNDFILE *sndfile ; | |
43 | SF_INFO sfinfo ; | |
44 | ||
45 | float buffer [BUFFER_LEN] ; | |
46 | } SNDFILE_CB_DATA ; | |
47 | ||
48 | typedef struct | |
49 | { int magic ; | |
50 | ||
51 | SNDFILE_CB_DATA sf ; | |
52 | ||
53 | int freq_point ; | |
54 | ||
55 | SRC_STATE *src_state ; | |
56 | ||
57 | } SRC_CB_DATA ; | |
58 | ||
59 | static int varispeed_get_data (SRC_CB_DATA *data, float *samples, int frames) ; | |
60 | static void varispeed_play (const char *filename, int converter) ; | |
61 | ||
62 | static long src_input_callback (void *cb_data, float **data) ; | |
63 | ||
64 | int | |
65 | main (int argc, char *argv []) | |
66 | { const char *cptr, *progname, *filename ; | |
67 | int k, converter ; | |
68 | ||
69 | converter = SRC_SINC_FASTEST ; | |
70 | ||
71 | progname = argv [0] ; | |
72 | ||
73 | if ((cptr = strrchr (progname, '/')) != NULL) | |
74 | progname = cptr + 1 ; | |
75 | ||
76 | if ((cptr = strrchr (progname, '\\')) != NULL) | |
77 | progname = cptr + 1 ; | |
78 | ||
79 | printf ("\n" | |
80 | " %s\n" | |
81 | "\n" | |
82 | " This is a demo program which plays the given file at a slowly \n" | |
83 | " varying speed. Lots of fun with drum loops and full mixes.\n" | |
84 | "\n" | |
85 | " It uses Secret Rabbit Code (aka libsamplerate) to perform the \n" | |
86 | " vari-speeding and libsndfile for file I/O.\n" | |
87 | "\n", progname) ; | |
88 | ||
89 | if (argc == 2) | |
90 | filename = argv [1] ; | |
91 | else if (argc == 4 && strcmp (argv [1], "-c") == 0) | |
92 | { filename = argv [3] ; | |
93 | converter = atoi (argv [2]) ; | |
94 | } | |
95 | else | |
96 | { printf (" Usage :\n\n %s [-c <number>] <input file>\n\n", progname) ; | |
97 | puts ( | |
98 | " The optional -c argument allows the converter type to be chosen from\n" | |
99 | " the following list :" | |
100 | "\n" | |
101 | ) ; | |
102 | ||
103 | for (k = 0 ; (cptr = src_get_name (k)) != NULL ; k++) | |
104 | printf (" %d : %s\n", k, cptr) ; | |
105 | ||
106 | puts ("") ; | |
107 | exit (1) ; | |
108 | } ; | |
109 | ||
110 | varispeed_play (filename, converter) ; | |
111 | ||
112 | return 0 ; | |
113 | } /* main */ | |
114 | ||
115 | /*============================================================================== | |
116 | */ | |
117 | ||
118 | static void | |
119 | varispeed_play (const char *filename, int converter) | |
120 | { SRC_CB_DATA data ; | |
121 | AUDIO_OUT *audio_out ; | |
122 | int error ; | |
123 | ||
124 | memset (&data, 0, sizeof (data)) ; | |
125 | ||
126 | data.magic = SRC_MAGIC ; | |
127 | data.sf.magic = SNDFILE_MAGIC ; | |
128 | ||
129 | if ((data.sf.sndfile = sf_open (filename, SFM_READ, &data.sf.sfinfo)) == NULL) | |
130 | { puts (sf_strerror (NULL)) ; | |
131 | exit (1) ; | |
132 | } ; | |
133 | ||
134 | /* Initialize the sample rate converter. */ | |
135 | if ((data.src_state = src_callback_new (src_input_callback, converter, data.sf.sfinfo.channels, &error, &data.sf)) == NULL) | |
136 | { printf ("\n\nError : src_new() failed : %s.\n\n", src_strerror (error)) ; | |
137 | exit (1) ; | |
138 | } ; | |
139 | ||
140 | printf ( | |
141 | ||
142 | " Playing : %s\n" | |
143 | " Converter : %s\n" | |
144 | "\n" | |
145 | " Press <control-c> to exit.\n" | |
146 | "\n", | |
147 | filename, src_get_name (converter)) ; | |
148 | ||
149 | if ((audio_out = audio_open (data.sf.sfinfo.channels, data.sf.sfinfo.samplerate)) == NULL) | |
150 | { printf ("\n\nError : audio_open () failed.\n") ; | |
151 | exit (1) ; | |
152 | } ; | |
153 | ||
154 | /* Pass the data and the callbacl function to audio_play */ | |
155 | audio_play ((get_audio_callback_t) varispeed_get_data, audio_out, &data) ; | |
156 | ||
157 | /* Cleanup */ | |
158 | audio_close (audio_out) ; | |
159 | sf_close (data.sf.sndfile) ; | |
160 | src_delete (data.src_state) ; | |
161 | ||
162 | } /* varispeed_play */ | |
163 | ||
164 | static long | |
165 | src_input_callback (void *cb_data, float **audio) | |
166 | { SNDFILE_CB_DATA * data = (SNDFILE_CB_DATA *) cb_data ; | |
167 | const int input_frames = ARRAY_LEN (data->buffer) / data->sfinfo.channels ; | |
168 | int read_frames ; | |
169 | ||
170 | if (data->magic != SNDFILE_MAGIC) | |
171 | { printf ("\n\n%s:%d Eeeek, something really bad happened!\n", __FILE__, __LINE__) ; | |
172 | exit (1) ; | |
173 | } ; | |
174 | ||
175 | for (read_frames = 0 ; read_frames < input_frames ; ) | |
176 | { sf_count_t position ; | |
177 | ||
178 | read_frames += sf_readf_float (data->sndfile, data->buffer + read_frames * data->sfinfo.channels, input_frames - read_frames) ; | |
179 | ||
180 | position = sf_seek (data->sndfile, 0, SEEK_CUR) ; | |
181 | ||
182 | if (position < 0 || position == data->sfinfo.frames) | |
183 | sf_seek (data->sndfile, 0, SEEK_SET) ; | |
184 | } ; | |
185 | ||
186 | *audio = & (data->buffer [0]) ; | |
187 | ||
188 | return input_frames ; | |
189 | } /* src_input_callback */ | |
190 | ||
191 | ||
192 | /*============================================================================== | |
193 | */ | |
194 | ||
195 | static int | |
196 | varispeed_get_data (SRC_CB_DATA *data, float *samples, int out_frames) | |
197 | { float *output ; | |
198 | int rc, out_frame_count ; | |
199 | ||
200 | if (data->magic != SRC_MAGIC) | |
201 | { printf ("\n\n%s:%d Eeeek, something really bad happened!\n", __FILE__, __LINE__) ; | |
202 | exit (1) ; | |
203 | } ; | |
204 | ||
205 | for (out_frame_count = 0 ; out_frame_count < out_frames ; out_frame_count += VARISPEED_BLOCK_LEN) | |
206 | { double src_ratio = 1.0 - 0.5 * sin (data->freq_point * 2 * M_PI / 20000) ; | |
207 | ||
208 | data->freq_point ++ ; | |
209 | ||
210 | output = samples + out_frame_count * data->sf.sfinfo.channels ; | |
211 | ||
212 | if ((rc = src_callback_read (data->src_state, src_ratio, VARISPEED_BLOCK_LEN, output)) < VARISPEED_BLOCK_LEN) | |
213 | { printf ("\nError : src_callback_read short output (%d instead of %d)\n\n", rc, VARISPEED_BLOCK_LEN) ; | |
214 | exit (1) ; | |
215 | } ; | |
216 | } ; | |
217 | ||
218 | return out_frames ; | |
219 | } /* varispeed_get_data */ | |
220 | ||
221 | /*============================================================================== | |
222 | */ | |
223 | ||
224 | #else /* (HAVE_SNFILE == 0) */ | |
225 | ||
226 | /* Alternative main function when libsndfile is not available. */ | |
227 | ||
228 | int | |
229 | main (void) | |
230 | { puts ( | |
231 | "\n" | |
232 | "****************************************************************\n" | |
233 | " This example program was compiled without libsndfile \n" | |
234 | " (http://www.zip.com.au/~erikd/libsndfile/).\n" | |
235 | " It is therefore completely broken and non-functional.\n" | |
236 | "****************************************************************\n" | |
237 | "\n" | |
238 | ) ; | |
239 | ||
240 | return 0 ; | |
241 | } /* main */ | |
242 | ||
243 | #endif | |
244 |