1 /**************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 Thom Johansen
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
17 ***************************************************************************/
19 #include <speex/speex.h>
20 #include <speex/speex_resampler.h>
28 /* Read an unaligned 32-bit little endian long from buffer. */
29 unsigned int get_long_le(unsigned char *p
)
31 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
34 void put_ushort_le(unsigned short x
, unsigned char *out
)
40 void put_uint_le(unsigned int x
, unsigned char *out
)
43 out
[1] = (x
>> 8) & 0xff;
44 out
[2] = (x
>> 16) & 0xff;
50 bool get_wave_metadata(FILE *fd
, int *numchan
, int *bps
, int *sr
, int *numsamples
)
52 unsigned char buf
[1024];
53 unsigned long totalsamples
= 0;
54 unsigned long channels
= 0;
55 unsigned long bitspersample
= 0;
56 unsigned long numbytes
= 0;
60 if ((read_bytes
= fread(buf
, 1, 12, fd
)) < 12)
63 if ((memcmp(buf
, "RIFF",4) != 0) || (memcmp(&buf
[8], "WAVE", 4) != 0))
66 /* iterate over WAVE chunks until 'data' chunk */
68 /* get chunk header */
69 if ((read_bytes
= fread(buf
, 1, 8, fd
)) < 8)
73 i
= get_long_le(&buf
[4]);
75 if (memcmp(buf
, "fmt ", 4) == 0) {
76 /* get rest of chunk */
77 if ((read_bytes
= fread(buf
, 1, 16, fd
)) < 16)
82 channels
= *numchan
= buf
[2] | (buf
[3] << 8);
83 *sr
= get_long_le(&buf
[4]);
85 bitspersample
= *bps
= buf
[14] | (buf
[15] << 8);
86 } else if (memcmp(buf
, "data", 4) == 0) {
89 } else if (memcmp(buf
, "fact", 4) == 0) {
92 /* get rest of chunk */
93 if ((read_bytes
= fread(buf
, 1, 4, fd
)) < 4)
97 totalsamples
= get_long_le(buf
);
101 /* seek to next chunk (even chunk sizes must be padded) */
105 if (fseek(fd
, i
, SEEK_CUR
) < 0)
109 if ((numbytes
== 0) || (channels
== 0))
112 if (totalsamples
== 0) {
114 totalsamples
= numbytes
/((((bitspersample
- 1) / 8) + 1)*channels
);
116 *numsamples
= totalsamples
;
120 /* We'll eat an entire WAV file here, and encode it with Speex, packing the
121 * bits as tightly as we can. Output is completely raw, with absolutely
122 * nothing to identify the contents. Files are left open, so remember to close
125 bool encode_file(FILE *fin
, FILE *fout
, float quality
, int complexity
,
126 bool narrowband
, float volume
, char *errstr
, size_t errlen
)
128 spx_int16_t
*in
= NULL
, *inpos
;
129 spx_int16_t enc_buf
[640]; /* Max frame size */
132 SpeexResamplerState
*resampler
= NULL
;
134 int i
, tmp
, target_sr
, numchan
, bps
, sr
, numsamples
, frame_size
, lookahead
;
138 if (!get_wave_metadata(fin
, &numchan
, &bps
, &sr
, &numsamples
)) {
139 snprintf(errstr
, errlen
, "invalid WAV file");
143 snprintf(errstr
, errlen
, "input file must be mono");
147 snprintf(errstr
, errlen
, "samples must be 16 bit");
151 /* Allocate an encoder of specified type, defaults to wideband */
152 st
= speex_encoder_init(narrowband
? &speex_nb_mode
: &speex_wb_mode
);
157 speex_bits_init(&bits
);
161 speex_encoder_ctl(st
, SPEEX_SET_VBR
, &tmp
);
163 speex_encoder_ctl(st
, SPEEX_SET_VBR_QUALITY
, &quality
);
164 /* Complexity, 0-10 */
165 speex_encoder_ctl(st
, SPEEX_SET_COMPLEXITY
, &complexity
);
166 speex_encoder_ctl(st
, SPEEX_GET_FRAME_SIZE
, &frame_size
);
167 speex_encoder_ctl(st
, SPEEX_GET_LOOKAHEAD
, &lookahead
);
169 /* Read input samples into a buffer */
170 in
= calloc(numsamples
+ lookahead
, sizeof(spx_int16_t
));
172 snprintf(errstr
, errlen
, "could not allocate clip memory");
176 if (fread(in
, 2, numsamples
, fin
) != numsamples
) {
177 snprintf(errstr
, errlen
, "could not read input file data");
182 if (volume
!= 1.0f
) {
183 for (i
= 0; i
< numsamples
; ++i
)
187 if (sr
!= target_sr
) {
188 resampler
= speex_resampler_init(1, sr
, target_sr
, 10, NULL
);
189 speex_resampler_skip_zeros(resampler
);
192 /* There will be 'lookahead' samples of zero at the end of the array, to
193 * make sure the Speex encoder is allowed to spit out all its data at clip
195 numsamples
+= lookahead
;
198 while (numsamples
> 0) {
199 int samples
= frame_size
;
201 /* Check if we need to resample */
202 if (sr
!= target_sr
) {
203 spx_uint32_t in_len
= numsamples
, out_len
= frame_size
;
204 double resample_factor
= (double)sr
/(double)target_sr
;
205 /* Calculate how many input samples are needed for one full frame
206 * out, and add some, just in case. */
207 spx_uint32_t samples_in
= frame_size
*resample_factor
+ 50;
209 /* Limit this or resampler will try to allocate it all on stack */
210 if (in_len
> samples_in
)
212 speex_resampler_process_int(resampler
, 0, inpos
, &in_len
,
216 numsamples
-= in_len
;
218 if (samples
> numsamples
)
219 samples
= numsamples
;
220 memcpy(enc_buf
, inpos
, samples
*2);
222 numsamples
-= frame_size
;
224 /* Pad out with zeros if we didn't fill all input */
225 memset(enc_buf
+ samples
, 0, (frame_size
- samples
)*2);
227 if (speex_encode_int(st
, enc_buf
, &bits
) < 0) {
228 snprintf(errstr
, errlen
, "encoder error");
233 /* Copy the bits to an array of char that can be written */
234 nbytes
= speex_bits_write_whole_bytes(&bits
, cbits
, 200);
236 /* Write the compressed data */
237 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
238 snprintf(errstr
, errlen
, "could not write output data");
243 /* Squeeze out the last bits */
244 nbytes
= speex_bits_write(&bits
, cbits
, 200);
245 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
246 snprintf(errstr
, errlen
, "could not write output data");
252 speex_encoder_destroy(st
);
253 speex_bits_destroy(&bits
);
254 if (resampler
!= NULL
)
255 speex_resampler_destroy(resampler
);