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 static unsigned int get_long_le(unsigned char *p
);
31 static bool get_wave_metadata(FILE *fd
, int *numchan
, int *bps
, int *sr
, int *numsamples
);
33 /* Read an unaligned 32-bit little endian long from buffer. */
34 unsigned int get_long_le(unsigned char *p
)
36 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
39 void put_ushort_le(unsigned short x
, unsigned char *out
)
45 void put_uint_le(unsigned int x
, unsigned char *out
)
48 out
[1] = (x
>> 8) & 0xff;
49 out
[2] = (x
>> 16) & 0xff;
55 bool get_wave_metadata(FILE *fd
, int *numchan
, int *bps
, int *sr
, int *numsamples
)
57 unsigned char buf
[1024];
58 unsigned long totalsamples
= 0;
59 unsigned long channels
= 0;
60 unsigned long bitspersample
= 0;
61 unsigned long numbytes
= 0;
65 if ((read_bytes
= fread(buf
, 1, 12, fd
)) < 12)
68 if ((memcmp(buf
, "RIFF",4) != 0) || (memcmp(&buf
[8], "WAVE", 4) != 0))
71 /* iterate over WAVE chunks until 'data' chunk */
73 /* get chunk header */
74 if ((read_bytes
= fread(buf
, 1, 8, fd
)) < 8)
78 i
= get_long_le(&buf
[4]);
80 if (memcmp(buf
, "fmt ", 4) == 0) {
81 /* get rest of chunk */
82 if ((read_bytes
= fread(buf
, 1, 16, fd
)) < 16)
87 channels
= *numchan
= buf
[2] | (buf
[3] << 8);
88 *sr
= get_long_le(&buf
[4]);
90 bitspersample
= *bps
= buf
[14] | (buf
[15] << 8);
91 } else if (memcmp(buf
, "data", 4) == 0) {
94 } else if (memcmp(buf
, "fact", 4) == 0) {
97 /* get rest of chunk */
98 if ((read_bytes
= fread(buf
, 1, 4, fd
)) < 4)
102 totalsamples
= get_long_le(buf
);
106 /* seek to next chunk (even chunk sizes must be padded) */
110 if (fseek(fd
, i
, SEEK_CUR
) < 0)
114 if ((numbytes
== 0) || (channels
== 0))
117 if (totalsamples
== 0) {
119 totalsamples
= numbytes
/((((bitspersample
- 1) / 8) + 1)*channels
);
121 *numsamples
= totalsamples
;
125 /* We'll eat an entire WAV file here, and encode it with Speex, packing the
126 * bits as tightly as we can. Output is completely raw, with absolutely
127 * nothing to identify the contents. Files are left open, so remember to close
130 bool encode_file(FILE *fin
, FILE *fout
, float quality
, int complexity
,
131 bool narrowband
, float volume
, char *errstr
, size_t errlen
)
133 spx_int16_t
*in
= NULL
, *inpos
;
134 spx_int16_t enc_buf
[640]; /* Max frame size */
137 SpeexResamplerState
*resampler
= NULL
;
139 int i
, tmp
, target_sr
, numchan
, bps
, sr
, numsamples
, frame_size
, lookahead
;
144 if (!get_wave_metadata(fin
, &numchan
, &bps
, &sr
, &numsamples
)) {
145 snprintf(errstr
, errlen
, "invalid WAV file");
149 snprintf(errstr
, errlen
, "input file must be mono");
153 snprintf(errstr
, errlen
, "samples must be 16 bit");
157 /* Allocate an encoder of specified type, defaults to wideband */
158 st
= speex_encoder_init(narrowband
? &speex_nb_mode
: &speex_wb_mode
);
163 speex_bits_init(&bits
);
167 speex_encoder_ctl(st
, SPEEX_SET_VBR
, &tmp
);
169 speex_encoder_ctl(st
, SPEEX_SET_VBR_QUALITY
, &quality
);
170 /* Complexity, 0-10 */
171 speex_encoder_ctl(st
, SPEEX_SET_COMPLEXITY
, &complexity
);
172 speex_encoder_ctl(st
, SPEEX_GET_FRAME_SIZE
, &frame_size
);
173 speex_encoder_ctl(st
, SPEEX_GET_LOOKAHEAD
, &lookahead
);
175 /* Read input samples into a buffer */
176 in
= calloc(numsamples
+ lookahead
, sizeof(spx_int16_t
));
178 snprintf(errstr
, errlen
, "could not allocate clip memory");
182 if (fread(in
, 2, numsamples
, fin
) != numsamples
) {
183 snprintf(errstr
, errlen
, "could not read input file data");
187 #if defined(__BIG_ENDIAN__)
188 /* byteswap read bytes to host endianess. */
191 *(in
+ a
) = ((unsigned short)(*(in
+ a
)) >> 8) & 0x00ff
192 | ((unsigned short)(*(in
+ a
)) << 8) & 0xff00;
196 if (volume
!= 1.0f
) {
197 for (i
= 0; i
< numsamples
; ++i
)
201 if (sr
!= target_sr
) {
202 resampler
= speex_resampler_init(1, sr
, target_sr
, 10, NULL
);
203 speex_resampler_skip_zeros(resampler
);
206 /* There will be 'lookahead' samples of zero at the end of the array, to
207 * make sure the Speex encoder is allowed to spit out all its data at clip
209 numsamples
+= lookahead
;
212 while (numsamples
> 0) {
213 int samples
= frame_size
;
215 /* Check if we need to resample */
216 if (sr
!= target_sr
) {
217 spx_uint32_t in_len
= numsamples
, out_len
= frame_size
;
218 double resample_factor
= (double)sr
/(double)target_sr
;
219 /* Calculate how many input samples are needed for one full frame
220 * out, and add some, just in case. */
221 spx_uint32_t samples_in
= frame_size
*resample_factor
+ 50;
223 /* Limit this or resampler will try to allocate it all on stack */
224 if (in_len
> samples_in
)
226 speex_resampler_process_int(resampler
, 0, inpos
, &in_len
,
230 numsamples
-= in_len
;
232 if (samples
> numsamples
)
233 samples
= numsamples
;
234 memcpy(enc_buf
, inpos
, samples
*2);
236 numsamples
-= frame_size
;
238 /* Pad out with zeros if we didn't fill all input */
239 memset(enc_buf
+ samples
, 0, (frame_size
- samples
)*2);
241 if (speex_encode_int(st
, enc_buf
, &bits
) < 0) {
242 snprintf(errstr
, errlen
, "encoder error");
247 /* Copy the bits to an array of char that can be written */
248 nbytes
= speex_bits_write_whole_bytes(&bits
, cbits
, 200);
250 /* Write the compressed data */
251 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
252 snprintf(errstr
, errlen
, "could not write output data");
257 /* Squeeze out the last bits */
258 nbytes
= speex_bits_write(&bits
, cbits
, 200);
259 if (fwrite(cbits
, 1, nbytes
, fout
) != nbytes
) {
260 snprintf(errstr
, errlen
, "could not write output data");
266 speex_encoder_destroy(st
);
267 speex_bits_destroy(&bits
);
268 if (resampler
!= NULL
)
269 speex_resampler_destroy(resampler
);