Prepare new maemo release
[maemo-rb.git] / tools / rbspeex / rbspeex.c
blob88b18c7c8582958e109c0e25757557d5f3bd5f25
1 /**************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
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>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdbool.h>
28 #include "rbspeex.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)
41 out[0] = x & 0xff;
42 out[1] = x >> 8;
45 void put_uint_le(unsigned int x, unsigned char *out)
47 out[0] = x & 0xff;
48 out[1] = (x >> 8) & 0xff;
49 out[2] = (x >> 16) & 0xff;
50 out[3] = x >> 24;
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;
62 size_t read_bytes;
63 int i;
65 if ((read_bytes = fread(buf, 1, 12, fd)) < 12)
66 return false;
68 if ((memcmp(buf, "RIFF",4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0))
69 return false;
71 /* iterate over WAVE chunks until 'data' chunk */
72 while (1) {
73 /* get chunk header */
74 if ((read_bytes = fread(buf, 1, 8, fd)) < 8)
75 return false;
77 /* chunkSize */
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)
83 return false;
85 i -= 16;
87 channels = *numchan = buf[2] | (buf[3] << 8);
88 *sr = get_long_le(&buf[4]);
89 /* wBitsPerSample */
90 bitspersample = *bps = buf[14] | (buf[15] << 8);
91 } else if (memcmp(buf, "data", 4) == 0) {
92 numbytes = i;
93 break;
94 } else if (memcmp(buf, "fact", 4) == 0) {
95 /* dwSampleLength */
96 if (i >= 4) {
97 /* get rest of chunk */
98 if ((read_bytes = fread(buf, 1, 4, fd)) < 4)
99 return false;
101 i -= 4;
102 totalsamples = get_long_le(buf);
106 /* seek to next chunk (even chunk sizes must be padded) */
107 if (i & 0x01)
108 i++;
110 if (fseek(fd, i, SEEK_CUR) < 0)
111 return false;
114 if ((numbytes == 0) || (channels == 0))
115 return false;
117 if (totalsamples == 0) {
118 /* for PCM only */
119 totalsamples = numbytes/((((bitspersample - 1) / 8) + 1)*channels);
121 *numsamples = totalsamples;
122 return true;
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
128 * them.
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 */
135 char cbits[200];
136 void *st = NULL;
137 SpeexResamplerState *resampler = NULL;
138 SpeexBits bits;
139 int i, tmp, target_sr, numchan, bps, sr, numsamples, frame_size, lookahead;
140 int nbytes;
141 bool ret = true;
142 int a;
144 if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) {
145 snprintf(errstr, errlen, "invalid WAV file");
146 return false;
148 if (numchan != 1) {
149 snprintf(errstr, errlen, "input file must be mono");
150 return false;
152 if (bps != 16) {
153 snprintf(errstr, errlen, "samples must be 16 bit");
154 return false;
157 /* Allocate an encoder of specified type, defaults to wideband */
158 st = speex_encoder_init(narrowband ? &speex_nb_mode : &speex_wb_mode);
159 if (narrowband)
160 target_sr = 8000;
161 else
162 target_sr = 16000;
163 speex_bits_init(&bits);
165 /* VBR */
166 tmp = 1;
167 speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
168 /* Quality, 0-10 */
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));
177 if (in == NULL) {
178 snprintf(errstr, errlen, "could not allocate clip memory");
179 ret = false;
180 goto finish;
182 if (fread(in, 2, numsamples, fin) != numsamples) {
183 snprintf(errstr, errlen, "could not read input file data");
184 ret = false;
185 goto finish;
187 #if defined(__BIG_ENDIAN__)
188 /* byteswap read bytes to host endianess. */
189 a = numsamples;
190 while(a--) {
191 *(in + a) = ((unsigned short)(*(in + a)) >> 8) & 0x00ff
192 | ((unsigned short)(*(in + a)) << 8) & 0xff00;
194 #endif
196 if (volume != 1.0f) {
197 for (i = 0; i < numsamples; ++i)
198 in[i] *= volume;
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
208 * end */
209 numsamples += lookahead;
211 inpos = in;
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)
225 in_len = samples_in;
226 speex_resampler_process_int(resampler, 0, inpos, &in_len,
227 enc_buf, &out_len);
228 inpos += in_len;
229 samples = out_len;
230 numsamples -= in_len;
231 } else {
232 if (samples > numsamples)
233 samples = numsamples;
234 memcpy(enc_buf, inpos, samples*2);
235 inpos += frame_size;
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");
243 ret = false;
244 goto finish;
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");
253 ret = false;
254 goto finish;
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");
261 ret = false;
264 finish:
265 if (st != NULL)
266 speex_encoder_destroy(st);
267 speex_bits_destroy(&bits);
268 if (resampler != NULL)
269 speex_resampler_destroy(resampler);
270 if (in != NULL)
271 free(in);
272 return ret;