diff options
-rw-r--r-- | tools/rbspeex/rbspeexenc.c | 193 |
1 files changed, 114 insertions, 79 deletions
diff --git a/tools/rbspeex/rbspeexenc.c b/tools/rbspeex/rbspeexenc.c index d3c3f7712c..e919bc8990 100644 --- a/tools/rbspeex/rbspeexenc.c +++ b/tools/rbspeex/rbspeexenc.c | |||
@@ -29,8 +29,8 @@ | |||
29 | " -q x Quality, floating point number in the range [0-10], default 8.0\n"\ | 29 | " -q x Quality, floating point number in the range [0-10], default 8.0\n"\ |
30 | " -c x Complexity, increases quality for a given bitrate, but encodes\n"\ | 30 | " -c x Complexity, increases quality for a given bitrate, but encodes\n"\ |
31 | " slower, range [0-10], default 3\n"\ | 31 | " slower, range [0-10], default 3\n"\ |
32 | " -n Enable narrowband mode, will resample input to 8 kHz\n\n"\ | 32 | " -n Enable narrowband mode, will resample input to 8 kHz\n"\ |
33 | " -v x Volume, amplitude multiplier, default 1.0\n"\ | 33 | " -v x Volume, amplitude multiplier, default 1.0\n\n"\ |
34 | "rbspeexenc expects a mono 16 bit WAV file as input. Files will be resampled\n"\ | 34 | "rbspeexenc expects a mono 16 bit WAV file as input. Files will be resampled\n"\ |
35 | "to either 16 kHz by default, or 8 kHz if narrowband mode is enabled.\n"\ | 35 | "to either 16 kHz by default, or 8 kHz if narrowband mode is enabled.\n"\ |
36 | "WARNING: This tool will create files that are only usable by Rockbox!\n" | 36 | "WARNING: This tool will create files that are only usable by Rockbox!\n" |
@@ -111,46 +111,35 @@ bool get_wave_metadata(FILE *fd, int *numchan, int *bps, int *sr, int *numsample | |||
111 | return true; | 111 | return true; |
112 | } | 112 | } |
113 | 113 | ||
114 | int main(int argc, char **argv) | 114 | /* We'll eat an entire WAV file here, and encode it with Speex, packing the |
115 | * bits as tightly as we can. Output is completely raw, with absolutely | ||
116 | * nothing to identify the contents. Files are left open, so remember to close | ||
117 | * them. | ||
118 | */ | ||
119 | bool encode_file(FILE *fin, FILE *fout, float quality, int complexity, | ||
120 | bool narrowband, float volume, char *errstr, size_t errlen) | ||
115 | { | 121 | { |
116 | FILE *fin, *fout; | 122 | spx_int16_t *in = NULL, *inpos; |
117 | spx_int16_t *in, *inpos; | ||
118 | spx_int16_t enc_buf[640]; /* Max frame size */ | 123 | spx_int16_t enc_buf[640]; /* Max frame size */ |
119 | char cbits[200]; | 124 | char cbits[200]; |
120 | int nbytes; | 125 | void *st = NULL; |
121 | void *st; | ||
122 | SpeexResamplerState *resampler = NULL; | 126 | SpeexResamplerState *resampler = NULL; |
123 | SpeexBits bits; | 127 | SpeexBits bits; |
124 | int i, tmp; | 128 | int i, tmp, target_sr, numchan, bps, sr, numsamples, frame_size, lookahead; |
125 | int complexity = 3; | 129 | int nbytes; |
126 | float quality = 8.f; | 130 | bool ret = true; |
127 | bool narrowband = false; | ||
128 | float volume = 1.0f; | ||
129 | int target_sr; | ||
130 | int numchan, bps, sr, numsamples; | ||
131 | int frame_size; | ||
132 | int lookahead; | ||
133 | 131 | ||
134 | if (argc < 3) { | 132 | if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) { |
135 | printf(USAGE_TEXT); | 133 | snprintf(errstr, errlen, "invalid WAV file"); |
136 | return 1; | 134 | return false; |
137 | } | 135 | } |
138 | 136 | if (numchan != 1) { | |
139 | i = 1; | 137 | snprintf(errstr, errlen, "input file must be mono"); |
140 | while (i < argc - 2) { | 138 | return false; |
141 | if (strncmp(argv[i], "-q", 2) == 0) | 139 | } |
142 | quality = atof(argv[++i]); | 140 | if (bps != 16) { |
143 | else if (strncmp(argv[i], "-c", 2) == 0) | 141 | snprintf(errstr, errlen, "samples must be 16 bit"); |
144 | complexity = atoi(argv[++i]); | 142 | return false; |
145 | else if (strncmp(argv[i], "-v", 2) == 0) | ||
146 | volume = atof(argv[++i]); | ||
147 | else if (strncmp(argv[i], "-n", 2) == 0) | ||
148 | narrowband = true; | ||
149 | else { | ||
150 | printf("Error: unrecognized option '%s'\n", argv[i]); | ||
151 | return 1; | ||
152 | } | ||
153 | ++i; | ||
154 | } | 143 | } |
155 | 144 | ||
156 | /* Allocate an encoder of specified type, defaults to wideband */ | 145 | /* Allocate an encoder of specified type, defaults to wideband */ |
@@ -159,11 +148,7 @@ int main(int argc, char **argv) | |||
159 | target_sr = 8000; | 148 | target_sr = 8000; |
160 | else | 149 | else |
161 | target_sr = 16000; | 150 | target_sr = 16000; |
162 | 151 | speex_bits_init(&bits); | |
163 | /* We'll eat an entire WAV file here, and encode it with Speex, packing the | ||
164 | * bits as tightly as we can. Output is completely raw, with absolutely | ||
165 | * nothing to identify the contents. | ||
166 | */ | ||
167 | 152 | ||
168 | /* VBR */ | 153 | /* VBR */ |
169 | tmp = 1; | 154 | tmp = 1; |
@@ -175,50 +160,35 @@ int main(int argc, char **argv) | |||
175 | speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); | 160 | speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); |
176 | speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); | 161 | speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); |
177 | 162 | ||
178 | fin = fopen(argv[argc - 2], "rb"); | ||
179 | if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) { | ||
180 | printf("Error: invalid WAV file\n"); | ||
181 | return 1; | ||
182 | } | ||
183 | if (sr != target_sr) { | ||
184 | resampler = speex_resampler_init(1, sr, target_sr, 10, NULL); | ||
185 | speex_resampler_skip_zeros(resampler); | ||
186 | } | ||
187 | if (numchan != 1) { | ||
188 | printf("Error: input file must be mono\n"); | ||
189 | return 1; | ||
190 | } | ||
191 | if (bps != 16) { | ||
192 | printf("Error: samples must be 16 bit\n"); | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | /* Read input samples into a buffer */ | 163 | /* Read input samples into a buffer */ |
197 | in = calloc(numsamples + lookahead, sizeof(spx_int16_t)); | 164 | in = calloc(numsamples + lookahead, sizeof(spx_int16_t)); |
198 | if (in == NULL) { | 165 | if (in == NULL) { |
199 | printf("Error: could not allocate clip memory\n"); | 166 | snprintf(errstr, errlen, "could not allocate clip memory"); |
200 | return 1; | 167 | ret = false; |
168 | goto finish; | ||
201 | } | 169 | } |
202 | fread(in, 2, numsamples, fin); | 170 | if (fread(in, 2, numsamples, fin) != numsamples) { |
203 | fclose(fin); | 171 | snprintf(errstr, errlen, "could not read input file data"); |
204 | 172 | ret = false; | |
205 | if(volume != 1.0f) { | 173 | goto finish; |
206 | for(i=0; i<numsamples; i++) | 174 | } |
175 | |||
176 | if (volume != 1.0f) { | ||
177 | for (i = 0; i < numsamples; ++i) | ||
207 | in[i] *= volume; | 178 | in[i] *= volume; |
208 | } | 179 | } |
209 | 180 | ||
181 | if (sr != target_sr) { | ||
182 | resampler = speex_resampler_init(1, sr, target_sr, 10, NULL); | ||
183 | speex_resampler_skip_zeros(resampler); | ||
184 | } | ||
185 | |||
210 | /* There will be 'lookahead' samples of zero at the end of the array, to | 186 | /* There will be 'lookahead' samples of zero at the end of the array, to |
211 | * make sure the Speex encoder is allowed to spit out all its data at clip | 187 | * make sure the Speex encoder is allowed to spit out all its data at clip |
212 | * end */ | 188 | * end */ |
213 | numsamples += lookahead; | 189 | numsamples += lookahead; |
214 | 190 | ||
215 | speex_bits_init(&bits); | ||
216 | inpos = in; | 191 | inpos = in; |
217 | if ((fout = fopen(argv[argc - 1], "wb")) == NULL) { | ||
218 | printf("Error: could not open output file\n"); | ||
219 | return 1; | ||
220 | } | ||
221 | |||
222 | while (numsamples > 0) { | 192 | while (numsamples > 0) { |
223 | int samples = frame_size; | 193 | int samples = frame_size; |
224 | 194 | ||
@@ -249,27 +219,92 @@ int main(int argc, char **argv) | |||
249 | memset(enc_buf + samples, 0, (frame_size - samples)*2); | 219 | memset(enc_buf + samples, 0, (frame_size - samples)*2); |
250 | 220 | ||
251 | if (speex_encode_int(st, enc_buf, &bits) < 0) { | 221 | if (speex_encode_int(st, enc_buf, &bits) < 0) { |
252 | printf("Error: encoder error\n"); | 222 | snprintf(errstr, errlen, "encoder error"); |
253 | return 1; | 223 | ret = false; |
224 | goto finish; | ||
254 | } | 225 | } |
255 | 226 | ||
256 | /* Copy the bits to an array of char that can be written */ | 227 | /* Copy the bits to an array of char that can be written */ |
257 | nbytes = speex_bits_write_whole_bytes(&bits, cbits, 200); | 228 | nbytes = speex_bits_write_whole_bytes(&bits, cbits, 200); |
258 | 229 | ||
259 | /* Write the compressed data */ | 230 | /* Write the compressed data */ |
260 | fwrite(cbits, 1, nbytes, fout); | 231 | if (fwrite(cbits, 1, nbytes, fout) != nbytes) { |
232 | snprintf(errstr, errlen, "could not write output data"); | ||
233 | ret = false; | ||
234 | goto finish; | ||
235 | } | ||
261 | } | 236 | } |
262 | /* Squeeze out the last bits */ | 237 | /* Squeeze out the last bits */ |
263 | nbytes = speex_bits_write(&bits, cbits, 200); | 238 | nbytes = speex_bits_write(&bits, cbits, 200); |
264 | fwrite(cbits, 1, nbytes, fout); | 239 | if (fwrite(cbits, 1, nbytes, fout) != nbytes) { |
240 | snprintf(errstr, errlen, "could not write output data"); | ||
241 | ret = false; | ||
242 | } | ||
265 | 243 | ||
266 | /*Destroy the encoder state*/ | 244 | finish: |
267 | speex_encoder_destroy(st); | 245 | if (st != NULL) |
268 | /*Destroy the bit-packing struct*/ | 246 | speex_encoder_destroy(st); |
269 | speex_bits_destroy(&bits); | 247 | speex_bits_destroy(&bits); |
270 | if (resampler != NULL) | 248 | if (resampler != NULL) |
271 | speex_resampler_destroy(resampler); | 249 | speex_resampler_destroy(resampler); |
250 | if (in != NULL) | ||
251 | free(in); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int main(int argc, char **argv) | ||
256 | { | ||
257 | char *inname, *outname; | ||
258 | FILE *fin, *fout; | ||
259 | int i; | ||
260 | int complexity = 3; | ||
261 | float quality = 8.f, volume = 1.0f; | ||
262 | bool narrowband = false; | ||
263 | bool ret; | ||
264 | char errstr[512]; | ||
265 | |||
266 | if (argc < 3) { | ||
267 | printf(USAGE_TEXT); | ||
268 | return 1; | ||
269 | } | ||
270 | |||
271 | i = 1; | ||
272 | while (i < argc - 2) { | ||
273 | if (strncmp(argv[i], "-q", 2) == 0) | ||
274 | quality = atof(argv[++i]); | ||
275 | else if (strncmp(argv[i], "-c", 2) == 0) | ||
276 | complexity = atoi(argv[++i]); | ||
277 | else if (strncmp(argv[i], "-v", 2) == 0) | ||
278 | volume = atof(argv[++i]); | ||
279 | else if (strncmp(argv[i], "-n", 2) == 0) | ||
280 | narrowband = true; | ||
281 | else { | ||
282 | printf("Error: unrecognized option '%s'\n", argv[i]); | ||
283 | return 1; | ||
284 | } | ||
285 | ++i; | ||
286 | } | ||
287 | inname = argv[argc - 2]; | ||
288 | outname = argv[argc - 1]; | ||
289 | |||
290 | if ((fin = fopen(inname, "rb")) == NULL) { | ||
291 | printf("Error: could not open input file\n"); | ||
292 | return 1; | ||
293 | } | ||
294 | if ((fout = fopen(outname, "wb")) == NULL) { | ||
295 | printf("Error: could not open output file\n"); | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | ret = encode_file(fin, fout, quality, complexity, narrowband, volume, | ||
300 | errstr, sizeof(errstr)); | ||
301 | fclose(fin); | ||
272 | fclose(fout); | 302 | fclose(fout); |
273 | free(in); | 303 | if (!ret) { |
304 | /* Attempt to delete unfinished output */ | ||
305 | printf("Error: %s\n", errstr); | ||
306 | remove(outname); | ||
307 | return 1; | ||
308 | } | ||
274 | return 0; | 309 | return 0; |
275 | } | 310 | } |