From ed047d9db1dcee92afb8fe6bacb5d90ccb39481e Mon Sep 17 00:00:00 2001 From: Dominik Wenger Date: Fri, 14 Dec 2007 16:04:38 +0000 Subject: refactor rbspeex, so we build a librbspeex.a for linking into rbutil. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15924 a1c6a512-1295-4272-9138-f99709370657 --- tools/rbspeex/Makefile | 19 ++-- tools/rbspeex/rbspeex.c | 261 +++++++++++++++++++++++++++++++++++++++++++++ tools/rbspeex/rbspeex.h | 34 ++++++ tools/rbspeex/rbspeexdec.c | 14 +-- tools/rbspeex/rbspeexenc.c | 221 +------------------------------------- 5 files changed, 309 insertions(+), 240 deletions(-) create mode 100644 tools/rbspeex/rbspeex.c create mode 100644 tools/rbspeex/rbspeex.h diff --git a/tools/rbspeex/Makefile b/tools/rbspeex/Makefile index f6e70def96..a2b6725f5d 100644 --- a/tools/rbspeex/Makefile +++ b/tools/rbspeex/Makefile @@ -26,7 +26,7 @@ endif # This sets up 'SRC' based on the files mentioned in SOURCES SRC := $(shell cat $(SPEEXSRC)/SOURCES | $(CC) $(CFLAGS) -E -P - | grep -v "^\#") -SOURCES = $(SRC:%.c=$(SPEEXSRC)/%.c) rbspeexenc.c rbspeexdec.c +SOURCES = $(SRC:%.c=$(SPEEXSRC)/%.c) rbspeex.c rbspeexenc.c rbspeexdec.c OBJS := $(SRC:%.c=%.o) DEPFILE = dep-speex DIRS = @@ -49,23 +49,24 @@ $(DEPFILE): $(SOURCES) done > $(DEPFILE); \ echo "oo" > /dev/null ) -libspeex.a: $(OBJS) $(DEPFILE) - @echo AR libspeex.a - $(SILENT)$(AR) ruv $@ $+ > /dev/null 2>&1 +librbspeex.a: $(OBJS) $(DEPFILE) rbspeex.o + @echo AR librbspeex.a + $(AR) ruv $@ $+ > /dev/null 2>&1 -../rbspeexenc: $(OBJS) libspeex.a rbspeexenc.o +../rbspeexenc: $(OBJS) rbspeexenc.o librbspeex.a @echo Linking ../rbspeexenc - $(SILENT)$(CC) $(CFLAGS) -o ../rbspeexenc rbspeexenc.o libspeex.a -lm + $(SILENT)$(CC) $(CFLAGS) -o ../rbspeexenc rbspeexenc.o librbspeex.a -lm -../rbspeexdec: $(OBJS) libspeex.a rbspeexdec.o +../rbspeexdec: $(OBJS) librbspeex.a rbspeexdec.o @echo Linking ../rbspeexdec - $(SILENT)$(CC) $(CFLAGS) -o ../rbspeexdec rbspeexdec.o libspeex.a -lm + $(SILENT)$(CC) $(CFLAGS) -o ../rbspeexdec rbspeexdec.o librbspeex.a -lm %.o: @echo CC $< $(SILENT)$(CC) $(CFLAGS) -c $< -o $@ + clean: - rm -f $(OBJS) libspeex.a rbspeexenc.o ../rbspeexenc dep-speex + rm -f $(OBJS) libspeex.a librbspeex.a rbspeexenc.o ../rbspeexenc dep-speex -include $(DEPFILE) diff --git a/tools/rbspeex/rbspeex.c b/tools/rbspeex/rbspeex.c new file mode 100644 index 0000000000..e211b9606a --- /dev/null +++ b/tools/rbspeex/rbspeex.c @@ -0,0 +1,261 @@ +/************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 Thom Johansen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "rbspeex.h" + +/* Read an unaligned 32-bit little endian long from buffer. */ +unsigned int get_long_le(unsigned char *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +void put_ushort_le(unsigned short x, unsigned char *out) +{ + out[0] = x & 0xff; + out[1] = x >> 8; +} + +void put_uint_le(unsigned int x, unsigned char *out) +{ + out[0] = x & 0xff; + out[1] = (x >> 8) & 0xff; + out[2] = (x >> 16) & 0xff; + out[3] = x >> 24; +} + + + +bool get_wave_metadata(FILE *fd, int *numchan, int *bps, int *sr, int *numsamples) +{ + unsigned char buf[1024]; + unsigned long totalsamples = 0; + unsigned long channels = 0; + unsigned long bitspersample = 0; + unsigned long numbytes = 0; + size_t read_bytes; + int i; + + if ((read_bytes = fread(buf, 1, 12, fd)) < 12) + return false; + + if ((memcmp(buf, "RIFF",4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) + return false; + + /* iterate over WAVE chunks until 'data' chunk */ + while (1) { + /* get chunk header */ + if ((read_bytes = fread(buf, 1, 8, fd)) < 8) + return false; + + /* chunkSize */ + i = get_long_le(&buf[4]); + + if (memcmp(buf, "fmt ", 4) == 0) { + /* get rest of chunk */ + if ((read_bytes = fread(buf, 1, 16, fd)) < 16) + return false; + + i -= 16; + + channels = *numchan = buf[2] | (buf[3] << 8); + *sr = get_long_le(&buf[4]); + /* wBitsPerSample */ + bitspersample = *bps = buf[14] | (buf[15] << 8); + } else if (memcmp(buf, "data", 4) == 0) { + numbytes = i; + break; + } else if (memcmp(buf, "fact", 4) == 0) { + /* dwSampleLength */ + if (i >= 4) { + /* get rest of chunk */ + if ((read_bytes = fread(buf, 1, 4, fd)) < 4) + return false; + + i -= 4; + totalsamples = get_long_le(buf); + } + } + + /* seek to next chunk (even chunk sizes must be padded) */ + if (i & 0x01) + i++; + + if (fseek(fd, i, SEEK_CUR) < 0) + return false; + } + + if ((numbytes == 0) || (channels == 0)) + return false; + + if (totalsamples == 0) { + /* for PCM only */ + totalsamples = numbytes/((((bitspersample - 1) / 8) + 1)*channels); + } + *numsamples = totalsamples; + return true; +} + +/* We'll eat an entire WAV file here, and encode it with Speex, packing the + * bits as tightly as we can. Output is completely raw, with absolutely + * nothing to identify the contents. Files are left open, so remember to close + * them. + */ +bool encode_file(FILE *fin, FILE *fout, float quality, int complexity, + bool narrowband, float volume, char *errstr, size_t errlen) +{ + spx_int16_t *in = NULL, *inpos; + spx_int16_t enc_buf[640]; /* Max frame size */ + char cbits[200]; + void *st = NULL; + SpeexResamplerState *resampler = NULL; + SpeexBits bits; + int i, tmp, target_sr, numchan, bps, sr, numsamples, frame_size, lookahead; + int nbytes; + bool ret = true; + + if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) { + snprintf(errstr, errlen, "invalid WAV file"); + return false; + } + if (numchan != 1) { + snprintf(errstr, errlen, "input file must be mono"); + return false; + } + if (bps != 16) { + snprintf(errstr, errlen, "samples must be 16 bit"); + return false; + } + + /* Allocate an encoder of specified type, defaults to wideband */ + st = speex_encoder_init(narrowband ? &speex_nb_mode : &speex_wb_mode); + if (narrowband) + target_sr = 8000; + else + target_sr = 16000; + speex_bits_init(&bits); + + /* VBR */ + tmp = 1; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + /* Quality, 0-10 */ + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &quality); + /* Complexity, 0-10 */ + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity); + speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); + + /* Read input samples into a buffer */ + in = calloc(numsamples + lookahead, sizeof(spx_int16_t)); + if (in == NULL) { + snprintf(errstr, errlen, "could not allocate clip memory"); + ret = false; + goto finish; + } + if (fread(in, 2, numsamples, fin) != numsamples) { + snprintf(errstr, errlen, "could not read input file data"); + ret = false; + goto finish; + } + + if (volume != 1.0f) { + for (i = 0; i < numsamples; ++i) + in[i] *= volume; + } + + if (sr != target_sr) { + resampler = speex_resampler_init(1, sr, target_sr, 10, NULL); + speex_resampler_skip_zeros(resampler); + } + + /* There will be 'lookahead' samples of zero at the end of the array, to + * make sure the Speex encoder is allowed to spit out all its data at clip + * end */ + numsamples += lookahead; + + inpos = in; + while (numsamples > 0) { + int samples = frame_size; + + /* Check if we need to resample */ + if (sr != target_sr) { + spx_uint32_t in_len = numsamples, out_len = frame_size; + double resample_factor = (double)sr/(double)target_sr; + /* Calculate how many input samples are needed for one full frame + * out, and add some, just in case. */ + spx_uint32_t samples_in = frame_size*resample_factor + 50; + + /* Limit this or resampler will try to allocate it all on stack */ + if (in_len > samples_in) + in_len = samples_in; + speex_resampler_process_int(resampler, 0, inpos, &in_len, + enc_buf, &out_len); + inpos += in_len; + samples = out_len; + numsamples -= in_len; + } else { + if (samples > numsamples) + samples = numsamples; + memcpy(enc_buf, inpos, samples*2); + inpos += frame_size; + numsamples -= frame_size; + } + /* Pad out with zeros if we didn't fill all input */ + memset(enc_buf + samples, 0, (frame_size - samples)*2); + + if (speex_encode_int(st, enc_buf, &bits) < 0) { + snprintf(errstr, errlen, "encoder error"); + ret = false; + goto finish; + } + + /* Copy the bits to an array of char that can be written */ + nbytes = speex_bits_write_whole_bytes(&bits, cbits, 200); + + /* Write the compressed data */ + if (fwrite(cbits, 1, nbytes, fout) != nbytes) { + snprintf(errstr, errlen, "could not write output data"); + ret = false; + goto finish; + } + } + /* Squeeze out the last bits */ + nbytes = speex_bits_write(&bits, cbits, 200); + if (fwrite(cbits, 1, nbytes, fout) != nbytes) { + snprintf(errstr, errlen, "could not write output data"); + ret = false; + } + +finish: + if (st != NULL) + speex_encoder_destroy(st); + speex_bits_destroy(&bits); + if (resampler != NULL) + speex_resampler_destroy(resampler); + if (in != NULL) + free(in); + return ret; +} + + diff --git a/tools/rbspeex/rbspeex.h b/tools/rbspeex/rbspeex.h new file mode 100644 index 0000000000..00d045c74a --- /dev/null +++ b/tools/rbspeex/rbspeex.h @@ -0,0 +1,34 @@ +/************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 Thom Johansen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#ifndef RBSPEEX_H +#define RBSPEEX_H + +#include + +unsigned int get_long_le(unsigned char *p); +bool get_wave_metadata(FILE *fd, int *numchan, int *bps, int *sr, int *numsamples); +bool encode_file(FILE *fin, FILE *fout, float quality, int complexity, + bool narrowband, float volume, char *errstr, size_t errlen); + +void put_ushort_le(unsigned short x, unsigned char *out); +void put_uint_le(unsigned int x, unsigned char *out); + + +#endif + diff --git a/tools/rbspeex/rbspeexdec.c b/tools/rbspeex/rbspeexdec.c index 90562f7309..a29361da3a 100644 --- a/tools/rbspeex/rbspeexdec.c +++ b/tools/rbspeex/rbspeexdec.c @@ -20,25 +20,13 @@ #include #include #include "string.h" +#include "rbspeex.h" #define USAGE_TEXT \ "Usage: rbspeexdec infile outfile\n"\ "rbspeexdec outputs mono 16 bit 16 kHz WAV files.\n"\ "WARNING: This tool will only decode files made with rbspeexenc!\n" -void put_ushort_le(unsigned short x, unsigned char *out) -{ - out[0] = x & 0xff; - out[1] = x >> 8; -} - -void put_uint_le(unsigned int x, unsigned char *out) -{ - out[0] = x & 0xff; - out[1] = (x >> 8) & 0xff; - out[2] = (x >> 16) & 0xff; - out[3] = x >> 24; -} int main(int argc, char **argv) { diff --git a/tools/rbspeex/rbspeexenc.c b/tools/rbspeex/rbspeexenc.c index e919bc8990..c7ea6e429a 100644 --- a/tools/rbspeex/rbspeexenc.c +++ b/tools/rbspeex/rbspeexenc.c @@ -16,13 +16,13 @@ * ***************************************************************************/ -#include -#include #include #include #include #include +#include "rbspeex.h" + #define USAGE_TEXT \ "Usage: rbspeexenc [options] infile outfile\n"\ "Options:\n"\ @@ -35,222 +35,6 @@ "to either 16 kHz by default, or 8 kHz if narrowband mode is enabled.\n"\ "WARNING: This tool will create files that are only usable by Rockbox!\n" -/* Read an unaligned 32-bit little endian long from buffer. */ -unsigned int get_long_le(unsigned char *p) -{ - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - -bool get_wave_metadata(FILE *fd, int *numchan, int *bps, int *sr, int *numsamples) -{ - unsigned char buf[1024]; - unsigned long totalsamples = 0; - unsigned long channels = 0; - unsigned long bitspersample = 0; - unsigned long numbytes = 0; - size_t read_bytes; - int i; - - if ((read_bytes = fread(buf, 1, 12, fd)) < 12) - return false; - - if ((memcmp(buf, "RIFF",4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) - return false; - - /* iterate over WAVE chunks until 'data' chunk */ - while (1) { - /* get chunk header */ - if ((read_bytes = fread(buf, 1, 8, fd)) < 8) - return false; - - /* chunkSize */ - i = get_long_le(&buf[4]); - - if (memcmp(buf, "fmt ", 4) == 0) { - /* get rest of chunk */ - if ((read_bytes = fread(buf, 1, 16, fd)) < 16) - return false; - - i -= 16; - - channels = *numchan = buf[2] | (buf[3] << 8); - *sr = get_long_le(&buf[4]); - /* wBitsPerSample */ - bitspersample = *bps = buf[14] | (buf[15] << 8); - } else if (memcmp(buf, "data", 4) == 0) { - numbytes = i; - break; - } else if (memcmp(buf, "fact", 4) == 0) { - /* dwSampleLength */ - if (i >= 4) { - /* get rest of chunk */ - if ((read_bytes = fread(buf, 1, 4, fd)) < 4) - return false; - - i -= 4; - totalsamples = get_long_le(buf); - } - } - - /* seek to next chunk (even chunk sizes must be padded) */ - if (i & 0x01) - i++; - - if (fseek(fd, i, SEEK_CUR) < 0) - return false; - } - - if ((numbytes == 0) || (channels == 0)) - return false; - - if (totalsamples == 0) { - /* for PCM only */ - totalsamples = numbytes/((((bitspersample - 1) / 8) + 1)*channels); - } - *numsamples = totalsamples; - return true; -} - -/* We'll eat an entire WAV file here, and encode it with Speex, packing the - * bits as tightly as we can. Output is completely raw, with absolutely - * nothing to identify the contents. Files are left open, so remember to close - * them. - */ -bool encode_file(FILE *fin, FILE *fout, float quality, int complexity, - bool narrowband, float volume, char *errstr, size_t errlen) -{ - spx_int16_t *in = NULL, *inpos; - spx_int16_t enc_buf[640]; /* Max frame size */ - char cbits[200]; - void *st = NULL; - SpeexResamplerState *resampler = NULL; - SpeexBits bits; - int i, tmp, target_sr, numchan, bps, sr, numsamples, frame_size, lookahead; - int nbytes; - bool ret = true; - - if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) { - snprintf(errstr, errlen, "invalid WAV file"); - return false; - } - if (numchan != 1) { - snprintf(errstr, errlen, "input file must be mono"); - return false; - } - if (bps != 16) { - snprintf(errstr, errlen, "samples must be 16 bit"); - return false; - } - - /* Allocate an encoder of specified type, defaults to wideband */ - st = speex_encoder_init(narrowband ? &speex_nb_mode : &speex_wb_mode); - if (narrowband) - target_sr = 8000; - else - target_sr = 16000; - speex_bits_init(&bits); - - /* VBR */ - tmp = 1; - speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); - /* Quality, 0-10 */ - speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &quality); - /* Complexity, 0-10 */ - speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity); - speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); - speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); - - /* Read input samples into a buffer */ - in = calloc(numsamples + lookahead, sizeof(spx_int16_t)); - if (in == NULL) { - snprintf(errstr, errlen, "could not allocate clip memory"); - ret = false; - goto finish; - } - if (fread(in, 2, numsamples, fin) != numsamples) { - snprintf(errstr, errlen, "could not read input file data"); - ret = false; - goto finish; - } - - if (volume != 1.0f) { - for (i = 0; i < numsamples; ++i) - in[i] *= volume; - } - - if (sr != target_sr) { - resampler = speex_resampler_init(1, sr, target_sr, 10, NULL); - speex_resampler_skip_zeros(resampler); - } - - /* There will be 'lookahead' samples of zero at the end of the array, to - * make sure the Speex encoder is allowed to spit out all its data at clip - * end */ - numsamples += lookahead; - - inpos = in; - while (numsamples > 0) { - int samples = frame_size; - - /* Check if we need to resample */ - if (sr != target_sr) { - spx_uint32_t in_len = numsamples, out_len = frame_size; - double resample_factor = (double)sr/(double)target_sr; - /* Calculate how many input samples are needed for one full frame - * out, and add some, just in case. */ - spx_uint32_t samples_in = frame_size*resample_factor + 50; - - /* Limit this or resampler will try to allocate it all on stack */ - if (in_len > samples_in) - in_len = samples_in; - speex_resampler_process_int(resampler, 0, inpos, &in_len, - enc_buf, &out_len); - inpos += in_len; - samples = out_len; - numsamples -= in_len; - } else { - if (samples > numsamples) - samples = numsamples; - memcpy(enc_buf, inpos, samples*2); - inpos += frame_size; - numsamples -= frame_size; - } - /* Pad out with zeros if we didn't fill all input */ - memset(enc_buf + samples, 0, (frame_size - samples)*2); - - if (speex_encode_int(st, enc_buf, &bits) < 0) { - snprintf(errstr, errlen, "encoder error"); - ret = false; - goto finish; - } - - /* Copy the bits to an array of char that can be written */ - nbytes = speex_bits_write_whole_bytes(&bits, cbits, 200); - - /* Write the compressed data */ - if (fwrite(cbits, 1, nbytes, fout) != nbytes) { - snprintf(errstr, errlen, "could not write output data"); - ret = false; - goto finish; - } - } - /* Squeeze out the last bits */ - nbytes = speex_bits_write(&bits, cbits, 200); - if (fwrite(cbits, 1, nbytes, fout) != nbytes) { - snprintf(errstr, errlen, "could not write output data"); - ret = false; - } - -finish: - if (st != NULL) - speex_encoder_destroy(st); - speex_bits_destroy(&bits); - if (resampler != NULL) - speex_resampler_destroy(resampler); - if (in != NULL) - free(in); - return ret; -} int main(int argc, char **argv) { @@ -308,3 +92,4 @@ int main(int argc, char **argv) } return 0; } + -- cgit v1.2.3