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
;
141 if (!get_wave_metadata(fin
, &numchan
, &bps
, &sr
, &numsamples
)) {
142 snprintf(errstr
, errlen
, "invalid WAV file");
146 snprintf(errstr
, errlen
, "input file must be mono");
150 snprintf(errstr
, errlen
, "samples must be 16 bit");
154 /* Allocate an encoder of specified type, defaults to wideband */
155 st
= speex_encoder_init(narrowband
? &speex_nb_mode
: &speex_wb_mode
);
160 speex_bits_init(&bits
);
164 speex_encoder_ctl(st
, SPEEX_SET_VBR
, &tmp
);
166 speex_encoder_ctl(st
, SPEEX_SET_VBR_QUALITY
, &quality
);
167 /* Complexity, 0-10 */
168 speex_encoder_ctl(st
, SPEEX_SET_COMPLEXITY
, &complexity
);
169 speex_encoder_ctl(st
, SPEEX_GET_FRAME_SIZE
, &frame_size
);
170 speex_encoder_ctl(st
, SPEEX_GET_LOOKAHEAD
, &lookahead
);
172 /* Read input samples into a buffer */
173 in
= calloc(numsamples
+ lookahead
, sizeof(spx_int16_t
));
175 snprintf(errstr
, errlen
, "could not allocate clip memory");
179 if (fread(in
, 2, numsamples
, fin
) != numsamples
) {
180 snprintf(errstr
, errlen
, "could not read input file data");
184 #if defined(__BIG_ENDIAN__)
185 /* byteswap read bytes to host endianess. */
188 *(in
+ a
) = ((unsigned short)(*(in
+ a
)) >> 8) & 0x00ff
189 | ((unsigned short)(*(in
+ a
)) << 8) & 0xff00;
193 if (volume
!= 1.0f
) {
194 for (i
= 0; i
< numsamples
; ++i
)
198 if (sr
!= target_sr
) {
199 resampler
= speex_resampler_init(1, sr
, target_sr
, 10, NULL
);
200 speex_resampler_skip_zeros(resampler
);
203 /* There will be 'lookahead' samples of zero at the end of the array, to
204 * make sure the Speex encoder is allowed to spit out all its data at clip
206 numsamples
+= lookahead
;
209 while (numsamples
> 0) {
210 int samples
= frame_size
;
212 /* Check if we need to resample */
213 if (sr
!= target_sr
) {
214 spx_uint32_t in_len
= numsamples
, out_len
= frame_size
;
215 double resample_factor
= (double)sr
/(double)target_sr
;
216 /* Calculate how many input samples are needed for one full frame
217 * out, and add some, just in case. */
218 spx_uint32_t samples_in
= frame_size
*resample_factor
+ 50;
220 /* Limit this or resampler will try to allocate it all on stack */
221 if (in_len
> samples_in
)
223 speex_resampler_process_int(resampler
, 0, inpos
, &in_len
,
227 numsamples
-= in_len
;
229 if (samples
> numsamples
)
230 samples
= numsamples
;
231 memcpy(enc_buf
, inpos
, samples
*2);
233 numsamples
-= frame_size
;
235 /* Pad out with zeros if we didn't fill all input */
236 memset(enc_buf
+ samples
, 0, (frame_size
- samples
)*2);
238 if (speex_encode_int(st
, enc_buf
, &bits
) < 0) {
239 snprintf(errstr
, errlen
, "encoder error");
244 /* Copy the bits to an array of char that can be written */
245 nbytes
= speex_bits_write_whole_bytes(&bits
, cbits
, 200);
247 /* Write the compressed data */
248 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
249 snprintf(errstr
, errlen
, "could not write output data");
254 /* Squeeze out the last bits */
255 nbytes
= speex_bits_write(&bits
, cbits
, 200);
256 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
257 snprintf(errstr
, errlen
, "could not write output data");
263 speex_encoder_destroy(st
);
264 speex_bits_destroy(&bits
);
265 if (resampler
!= NULL
)
266 speex_resampler_destroy(resampler
);