Speex encoder specially tailored to create voice UI snippets. Small fixups to libspeex to allow it to be built.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15640 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
88c4748a4b
commit
65458ee71c
9 changed files with 332 additions and 4 deletions
|
@ -14,7 +14,7 @@ ifdef APPEXTRA
|
|||
INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
|
||||
endif
|
||||
|
||||
SPEEXOPTS = -DHAVE_CONFIG_H -DSPEEX_DISABLE_ENCODER
|
||||
SPEEXOPTS = -DHAVE_CONFIG_H -DSPEEX_DISABLE_ENCODER -DROCKBOX
|
||||
|
||||
# We're faster on ARM-targets with -O1 instead of -O2
|
||||
ifeq ($(CPU),arm)
|
||||
|
|
|
@ -24,12 +24,22 @@ speex.c
|
|||
speex_callbacks.c
|
||||
speex_header.c
|
||||
#ifndef ROCKBOX_VOICE_CODEC
|
||||
#ifndef ROCKBOX_VOICE_ENCODER
|
||||
oggframing.c
|
||||
#endif
|
||||
stereo.c
|
||||
#endif
|
||||
#ifdef ROCKBOX_VOICE_ENCODER
|
||||
lpc.c
|
||||
vbr.c
|
||||
vq.c
|
||||
window.c
|
||||
resample.c
|
||||
#else
|
||||
#ifdef CPU_COLDFIRE
|
||||
filters_cf.S
|
||||
ltp_cf.S
|
||||
#elif defined(CPU_ARM)
|
||||
filters_arm4.S
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -106,7 +106,7 @@ void speex_bits_rewind(SpeexBits *bits)
|
|||
bits->overflow=0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifndef SPEEX_VOICE_ENCODER
|
||||
void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
#ifndef ROCKBOX_VOICE_ENCODER
|
||||
#include "../codec.h"
|
||||
#include "autoconf.h"
|
||||
#else
|
||||
#define ICODE_ATTR
|
||||
#define IDATA_ATTR
|
||||
#define IBSS_ATTR
|
||||
#define ICONST_ATTR
|
||||
#endif
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
#ifndef ROCKBOX_VOICE_ENCODER
|
||||
/* Make use of ARM4E assembly optimizations */
|
||||
#if defined(CPU_ARM)
|
||||
#define ARM4_ASM
|
||||
|
@ -15,6 +23,7 @@
|
|||
|
||||
/* Make use of Blackfin assembly optimizations */
|
||||
/* #undef BFIN_ASM */
|
||||
#endif /* ROCKBOX_VOICE_ENCODER */
|
||||
|
||||
/* Disable wideband codec */
|
||||
/* #undef DISABLE_WIDEBAND */
|
||||
|
@ -28,8 +37,13 @@
|
|||
/* Debug fixed-point implementation */
|
||||
/* #undef FIXED_DEBUG */
|
||||
|
||||
#ifndef ROCKBOX_VOICE_ENCODER
|
||||
/* Compile target codec as fixed point */
|
||||
#define FIXED_POINT
|
||||
#else
|
||||
/* Compile voice clip encoder as floating point */
|
||||
#define FLOATING_POINT
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
/* #undef HAVE_DLFCN_H */
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#ifndef SPEEX_ROCKBOX_H
|
||||
#define SPEEX_ROCKBOX_H
|
||||
|
||||
/* We don't want all this stuff if we're building encoder */
|
||||
#ifndef ROCKBOX_VOICE_ENCODER
|
||||
|
||||
#include "../codec.h"
|
||||
#include "../lib/codeclib.h"
|
||||
|
||||
|
@ -106,5 +109,7 @@ static inline void _speex_putc(int ch, void *file)
|
|||
//printf("%c", ch);
|
||||
}
|
||||
|
||||
#endif /* ROCKBOX_VOICE_ENCODER */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
/** Convert little endian */
|
||||
static inline spx_int32_t le_int(spx_int32_t i)
|
||||
{
|
||||
#if 1
|
||||
#ifdef ROCKBOX
|
||||
return letoh32(i);
|
||||
#elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
|
||||
spx_uint32_t ui, ret;
|
||||
|
|
|
@ -11,7 +11,7 @@ LDFLAGS := -g
|
|||
|
||||
CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \
|
||||
generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \
|
||||
lngdump telechips gigabeats mktccboot mknkboot
|
||||
lngdump telechips gigabeats mktccboot mknkboot rbspeexenc
|
||||
|
||||
all:
|
||||
@echo "Run make in your build directory!"
|
||||
|
@ -76,6 +76,9 @@ player_unifont: player_unifont.c ../firmware/drivers/lcd-charset-player.c
|
|||
uclpack:
|
||||
$(SILENT)$(MAKE) -C ucl
|
||||
|
||||
rbspeexenc:
|
||||
$(SILENT)$(MAKE) -C rbspeex
|
||||
|
||||
wavtrim: wavtrim.c
|
||||
$(SILENT)$(CC) -g $+ -o $@
|
||||
|
||||
|
@ -86,4 +89,5 @@ clean:
|
|||
@echo "Cleaning tools"
|
||||
$(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do echo $$f.exe $$f.o $$f.obj ; done) *.ajf *~
|
||||
$(SILENT)$(MAKE) -C ucl clean
|
||||
$(SILENT)$(MAKE) -C rbspeex clean
|
||||
|
||||
|
|
56
tools/rbspeex/Makefile
Normal file
56
tools/rbspeex/Makefile
Normal file
|
@ -0,0 +1,56 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id: Makefile,v 1.16 2006-09-02 22:34:13 bagder Exp $
|
||||
#
|
||||
|
||||
ifndef V
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
SPEEXSRC = ../../apps/codecs/libspeex
|
||||
|
||||
INCLUDES = -I $(SPEEXSRC) -iquote $(SPEEXSRC)
|
||||
SPEEXOPTS = -DHAVE_CONFIG_H -DROCKBOX_VOICE_ENCODER
|
||||
|
||||
CFLAGS = $(SPEEXOPTS) $(INCLUDES) -O3 -fomit-frame-pointer -Wno-unused-parameter
|
||||
|
||||
# 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
|
||||
OBJS := $(SRC:%.c=%.o) rbspeexenc.o
|
||||
DEPFILE = dep-speex
|
||||
DIRS =
|
||||
|
||||
.PHONY : all
|
||||
|
||||
all: ../rbspeexenc
|
||||
|
||||
$(DEPFILE): $(SOURCES)
|
||||
$(SILENT)rm -f $(DEPFILE)
|
||||
$(SILENT)(for each in $(SOURCES) x; do \
|
||||
if test "x" != "$$each"; then \
|
||||
obj=`echo $$each | sed -e 's/\.[cS]/.o/' | sed -e 's/^.*\///' `; \
|
||||
$(CC) -MG -MM -MT "$$obj" $(CFLAGS) $$each 2>/dev/null; \
|
||||
fi; \
|
||||
if test -n "$$del"; then \
|
||||
rm $$del; \
|
||||
del=""; \
|
||||
fi \
|
||||
done > $(DEPFILE); \
|
||||
echo "oo" > /dev/null )
|
||||
|
||||
../rbspeexenc: $(OBJS) $(DEPFILE)
|
||||
gcc -o ../rbspeexenc $(OBJS) -lm
|
||||
|
||||
%.o:
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) dep-speex
|
||||
|
||||
-include $(DEPFILE)
|
239
tools/rbspeex/rbspeexenc.c
Normal file
239
tools/rbspeex/rbspeexenc.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/**************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 <speex/speex.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.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);
|
||||
}
|
||||
|
||||
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 = read(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;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fin, *fout;
|
||||
spx_int16_t *in, *inpos;
|
||||
spx_int16_t enc_buf[640]; /* Max frame size */
|
||||
char cbits[200];
|
||||
int nbytes;
|
||||
void *st;
|
||||
SpeexResamplerState *resampler = NULL;
|
||||
SpeexBits bits;
|
||||
int i, tmp;
|
||||
float ftmp;
|
||||
int numchan, bps, sr, numsamples;
|
||||
int frame_size;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: rbspeexenc [options] infile outfile\n"
|
||||
"Options:\n"
|
||||
" -q x Quality, floating point number in the range [0-10]\n"
|
||||
" -c x Complexity, affects quality and encoding time, where\n"
|
||||
" both increase with increasing values, range [0-10]\n"
|
||||
" Defaults are as in speexenc.\n"
|
||||
"\nWARNING: This tool will create files that are only usable by Rockbox!\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Wideband encoding */
|
||||
st = speex_encoder_init(&speex_wb_mode);
|
||||
|
||||
/* VBR */
|
||||
tmp = 1;
|
||||
speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
|
||||
/* Quality, 0-10 */
|
||||
ftmp = 8.f;
|
||||
for (i = 1; i < argc - 2; ++i) {
|
||||
if (strncmp(argv[i], "-q", 2) == 0) {
|
||||
ftmp = atof(argv[i + 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &ftmp);
|
||||
/* Complexity, 0-10 */
|
||||
tmp = 3;
|
||||
for (i = 1; i < argc - 2; ++i) {
|
||||
if (strncmp(argv[i], "-c", 2) == 0) {
|
||||
tmp = atoi(argv[i + 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
|
||||
speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
|
||||
|
||||
fin = fopen(argv[argc - 2], "rb");
|
||||
if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) {
|
||||
printf("invalid wave file!\n");
|
||||
return 1;
|
||||
}
|
||||
if (sr != 16000) {
|
||||
resampler = speex_resampler_init(1, sr, 16000, 10, NULL);
|
||||
speex_resampler_skip_zeros(resampler);
|
||||
printf("Resampling from %i Hz to 16000 Hz\n", sr);
|
||||
}
|
||||
if (numchan != 1) {
|
||||
printf("Error: input file must be mono\n");
|
||||
return 1;
|
||||
}
|
||||
if (bps != 16) {
|
||||
printf("samples must be 16 bit!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read input samples into a buffer */
|
||||
in = malloc(numsamples*2);
|
||||
if (malloc == NULL) {
|
||||
printf("error on malloc\n");
|
||||
return 1;
|
||||
}
|
||||
fread(in, 2, numsamples, fin);
|
||||
fclose(fin);
|
||||
|
||||
speex_bits_init(&bits);
|
||||
inpos = in;
|
||||
fout = fopen(argv[argc - 1], "wb");
|
||||
|
||||
while (numsamples > 0) {
|
||||
int samples = frame_size;
|
||||
|
||||
/* Check if we need to resample */
|
||||
if (sr != 16000) {
|
||||
spx_uint32_t in_len = numsamples, out_len = frame_size;
|
||||
|
||||
/* Limit this or resampler will try to allocate it all on stack */
|
||||
if (in_len > 2000)
|
||||
in_len = 2000;
|
||||
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);
|
||||
|
||||
speex_encode_int(st, enc_buf, &bits);
|
||||
|
||||
/* 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 */
|
||||
fwrite(cbits, 1, nbytes, fout);
|
||||
}
|
||||
|
||||
/* Squeeze out the last bits */
|
||||
nbytes = speex_bits_write(&bits, cbits, 200);
|
||||
fwrite(cbits, 1, nbytes, fout);
|
||||
|
||||
/*Destroy the encoder state*/
|
||||
speex_encoder_destroy(st);
|
||||
/*Destroy the bit-packing struct*/
|
||||
speex_bits_destroy(&bits);
|
||||
if (resampler != NULL)
|
||||
speex_resampler_destroy(resampler);
|
||||
fclose(fout);
|
||||
free(in);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue