1 /**************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 Thom Johansen
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ***************************************************************************/
21 #include <speex/speex.h>
22 #include <speex/speex_resampler.h>
30 /* Read an unaligned 32-bit little endian long from buffer. */
31 unsigned int get_long_le(unsigned char *p
)
33 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
36 void put_ushort_le(unsigned short x
, unsigned char *out
)
42 void put_uint_le(unsigned int x
, unsigned char *out
)
45 out
[1] = (x
>> 8) & 0xff;
46 out
[2] = (x
>> 16) & 0xff;
52 bool get_wave_metadata(FILE *fd
, int *numchan
, int *bps
, int *sr
, int *numsamples
)
54 unsigned char buf
[1024];
55 unsigned long totalsamples
= 0;
56 unsigned long channels
= 0;
57 unsigned long bitspersample
= 0;
58 unsigned long numbytes
= 0;
62 if ((read_bytes
= fread(buf
, 1, 12, fd
)) < 12)
65 if ((memcmp(buf
, "RIFF",4) != 0) || (memcmp(&buf
[8], "WAVE", 4) != 0))
68 /* iterate over WAVE chunks until 'data' chunk */
70 /* get chunk header */
71 if ((read_bytes
= fread(buf
, 1, 8, fd
)) < 8)
75 i
= get_long_le(&buf
[4]);
77 if (memcmp(buf
, "fmt ", 4) == 0) {
78 /* get rest of chunk */
79 if ((read_bytes
= fread(buf
, 1, 16, fd
)) < 16)
84 channels
= *numchan
= buf
[2] | (buf
[3] << 8);
85 *sr
= get_long_le(&buf
[4]);
87 bitspersample
= *bps
= buf
[14] | (buf
[15] << 8);
88 } else if (memcmp(buf
, "data", 4) == 0) {
91 } else if (memcmp(buf
, "fact", 4) == 0) {
94 /* get rest of chunk */
95 if ((read_bytes
= fread(buf
, 1, 4, fd
)) < 4)
99 totalsamples
= get_long_le(buf
);
103 /* seek to next chunk (even chunk sizes must be padded) */
107 if (fseek(fd
, i
, SEEK_CUR
) < 0)
111 if ((numbytes
== 0) || (channels
== 0))
114 if (totalsamples
== 0) {
116 totalsamples
= numbytes
/((((bitspersample
- 1) / 8) + 1)*channels
);
118 *numsamples
= totalsamples
;
122 /* We'll eat an entire WAV file here, and encode it with Speex, packing the
123 * bits as tightly as we can. Output is completely raw, with absolutely
124 * nothing to identify the contents. Files are left open, so remember to close
127 bool encode_file(FILE *fin
, FILE *fout
, float quality
, int complexity
,
128 bool narrowband
, float volume
, char *errstr
, size_t errlen
)
130 spx_int16_t
*in
= NULL
, *inpos
;
131 spx_int16_t enc_buf
[640]; /* Max frame size */
134 SpeexResamplerState
*resampler
= NULL
;
136 int i
, tmp
, target_sr
, numchan
, bps
, sr
, numsamples
, frame_size
, lookahead
;
140 if (!get_wave_metadata(fin
, &numchan
, &bps
, &sr
, &numsamples
)) {
141 snprintf(errstr
, errlen
, "invalid WAV file");
145 snprintf(errstr
, errlen
, "input file must be mono");
149 snprintf(errstr
, errlen
, "samples must be 16 bit");
153 /* Allocate an encoder of specified type, defaults to wideband */
154 st
= speex_encoder_init(narrowband
? &speex_nb_mode
: &speex_wb_mode
);
159 speex_bits_init(&bits
);
163 speex_encoder_ctl(st
, SPEEX_SET_VBR
, &tmp
);
165 speex_encoder_ctl(st
, SPEEX_SET_VBR_QUALITY
, &quality
);
166 /* Complexity, 0-10 */
167 speex_encoder_ctl(st
, SPEEX_SET_COMPLEXITY
, &complexity
);
168 speex_encoder_ctl(st
, SPEEX_GET_FRAME_SIZE
, &frame_size
);
169 speex_encoder_ctl(st
, SPEEX_GET_LOOKAHEAD
, &lookahead
);
171 /* Read input samples into a buffer */
172 in
= calloc(numsamples
+ lookahead
, sizeof(spx_int16_t
));
174 snprintf(errstr
, errlen
, "could not allocate clip memory");
178 if (fread(in
, 2, numsamples
, fin
) != numsamples
) {
179 snprintf(errstr
, errlen
, "could not read input file data");
184 if (volume
!= 1.0f
) {
185 for (i
= 0; i
< numsamples
; ++i
)
189 if (sr
!= target_sr
) {
190 resampler
= speex_resampler_init(1, sr
, target_sr
, 10, NULL
);
191 speex_resampler_skip_zeros(resampler
);
194 /* There will be 'lookahead' samples of zero at the end of the array, to
195 * make sure the Speex encoder is allowed to spit out all its data at clip
197 numsamples
+= lookahead
;
200 while (numsamples
> 0) {
201 int samples
= frame_size
;
203 /* Check if we need to resample */
204 if (sr
!= target_sr
) {
205 spx_uint32_t in_len
= numsamples
, out_len
= frame_size
;
206 double resample_factor
= (double)sr
/(double)target_sr
;
207 /* Calculate how many input samples are needed for one full frame
208 * out, and add some, just in case. */
209 spx_uint32_t samples_in
= frame_size
*resample_factor
+ 50;
211 /* Limit this or resampler will try to allocate it all on stack */
212 if (in_len
> samples_in
)
214 speex_resampler_process_int(resampler
, 0, inpos
, &in_len
,
218 numsamples
-= in_len
;
220 if (samples
> numsamples
)
221 samples
= numsamples
;
222 memcpy(enc_buf
, inpos
, samples
*2);
224 numsamples
-= frame_size
;
226 /* Pad out with zeros if we didn't fill all input */
227 memset(enc_buf
+ samples
, 0, (frame_size
- samples
)*2);
229 if (speex_encode_int(st
, enc_buf
, &bits
) < 0) {
230 snprintf(errstr
, errlen
, "encoder error");
235 /* Copy the bits to an array of char that can be written */
236 nbytes
= speex_bits_write_whole_bytes(&bits
, cbits
, 200);
238 /* Write the compressed data */
239 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
240 snprintf(errstr
, errlen
, "could not write output data");
245 /* Squeeze out the last bits */
246 nbytes
= speex_bits_write(&bits
, cbits
, 200);
247 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
248 snprintf(errstr
, errlen
, "could not write output data");
254 speex_encoder_destroy(st
);
255 speex_bits_destroy(&bits
);
256 if (resampler
!= NULL
)
257 speex_resampler_destroy(resampler
);