summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom Johansen <thomj@rockbox.org>2007-11-16 15:35:37 +0000
committerThom Johansen <thomj@rockbox.org>2007-11-16 15:35:37 +0000
commit65458ee71ca741fbed1bff7e358760bb480b85e9 (patch)
treebe9262a5c2560e5e0710d41e6c94d0c3a4e86b77
parent88c4748a4b93b6dcf0a8288c030bf93ae571ce5e (diff)
downloadrockbox-65458ee71ca741fbed1bff7e358760bb480b85e9.tar.gz
rockbox-65458ee71ca741fbed1bff7e358760bb480b85e9.zip
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
-rw-r--r--apps/codecs/libspeex/Makefile2
-rw-r--r--apps/codecs/libspeex/SOURCES10
-rw-r--r--apps/codecs/libspeex/bits.c2
-rw-r--r--apps/codecs/libspeex/config-speex.h14
-rw-r--r--apps/codecs/libspeex/rockbox.h5
-rw-r--r--apps/codecs/libspeex/speex_header.c2
-rw-r--r--tools/Makefile6
-rw-r--r--tools/rbspeex/Makefile56
-rw-r--r--tools/rbspeex/rbspeexenc.c239
9 files changed, 332 insertions, 4 deletions
diff --git a/apps/codecs/libspeex/Makefile b/apps/codecs/libspeex/Makefile
index 35a8535369..3bda53dca7 100644
--- a/apps/codecs/libspeex/Makefile
+++ b/apps/codecs/libspeex/Makefile
@@ -14,7 +14,7 @@ ifdef APPEXTRA
14 INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) 14 INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
15endif 15endif
16 16
17SPEEXOPTS = -DHAVE_CONFIG_H -DSPEEX_DISABLE_ENCODER 17SPEEXOPTS = -DHAVE_CONFIG_H -DSPEEX_DISABLE_ENCODER -DROCKBOX
18 18
19# We're faster on ARM-targets with -O1 instead of -O2 19# We're faster on ARM-targets with -O1 instead of -O2
20ifeq ($(CPU),arm) 20ifeq ($(CPU),arm)
diff --git a/apps/codecs/libspeex/SOURCES b/apps/codecs/libspeex/SOURCES
index 40ea5380b9..f036734589 100644
--- a/apps/codecs/libspeex/SOURCES
+++ b/apps/codecs/libspeex/SOURCES
@@ -24,12 +24,22 @@ speex.c
24speex_callbacks.c 24speex_callbacks.c
25speex_header.c 25speex_header.c
26#ifndef ROCKBOX_VOICE_CODEC 26#ifndef ROCKBOX_VOICE_CODEC
27#ifndef ROCKBOX_VOICE_ENCODER
27oggframing.c 28oggframing.c
29#endif
28stereo.c 30stereo.c
29#endif 31#endif
32#ifdef ROCKBOX_VOICE_ENCODER
33lpc.c
34vbr.c
35vq.c
36window.c
37resample.c
38#else
30#ifdef CPU_COLDFIRE 39#ifdef CPU_COLDFIRE
31filters_cf.S 40filters_cf.S
32ltp_cf.S 41ltp_cf.S
33#elif defined(CPU_ARM) 42#elif defined(CPU_ARM)
34filters_arm4.S 43filters_arm4.S
35#endif 44#endif
45#endif
diff --git a/apps/codecs/libspeex/bits.c b/apps/codecs/libspeex/bits.c
index d4b02a5a86..e460a39cf2 100644
--- a/apps/codecs/libspeex/bits.c
+++ b/apps/codecs/libspeex/bits.c
@@ -106,7 +106,7 @@ void speex_bits_rewind(SpeexBits *bits)
106 bits->overflow=0; 106 bits->overflow=0;
107} 107}
108 108
109#if 0 109#ifndef SPEEX_VOICE_ENCODER
110void speex_bits_read_from(SpeexBits *bits, char *chars, int len) 110void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
111{ 111{
112 int i; 112 int i;
diff --git a/apps/codecs/libspeex/config-speex.h b/apps/codecs/libspeex/config-speex.h
index 1378fc2a69..ad1393fc60 100644
--- a/apps/codecs/libspeex/config-speex.h
+++ b/apps/codecs/libspeex/config-speex.h
@@ -1,8 +1,16 @@
1#ifndef ROCKBOX_VOICE_ENCODER
1#include "../codec.h" 2#include "../codec.h"
2#include "autoconf.h" 3#include "autoconf.h"
4#else
5#define ICODE_ATTR
6#define IDATA_ATTR
7#define IBSS_ATTR
8#define ICONST_ATTR
9#endif
3/* config.h. Generated from config.h.in by configure. */ 10/* config.h. Generated from config.h.in by configure. */
4/* config.h.in. Generated from configure.ac by autoheader. */ 11/* config.h.in. Generated from configure.ac by autoheader. */
5 12
13#ifndef ROCKBOX_VOICE_ENCODER
6/* Make use of ARM4E assembly optimizations */ 14/* Make use of ARM4E assembly optimizations */
7#if defined(CPU_ARM) 15#if defined(CPU_ARM)
8#define ARM4_ASM 16#define ARM4_ASM
@@ -15,6 +23,7 @@
15 23
16/* Make use of Blackfin assembly optimizations */ 24/* Make use of Blackfin assembly optimizations */
17/* #undef BFIN_ASM */ 25/* #undef BFIN_ASM */
26#endif /* ROCKBOX_VOICE_ENCODER */
18 27
19/* Disable wideband codec */ 28/* Disable wideband codec */
20/* #undef DISABLE_WIDEBAND */ 29/* #undef DISABLE_WIDEBAND */
@@ -28,8 +37,13 @@
28/* Debug fixed-point implementation */ 37/* Debug fixed-point implementation */
29/* #undef FIXED_DEBUG */ 38/* #undef FIXED_DEBUG */
30 39
40#ifndef ROCKBOX_VOICE_ENCODER
31/* Compile target codec as fixed point */ 41/* Compile target codec as fixed point */
32#define FIXED_POINT 42#define FIXED_POINT
43#else
44/* Compile voice clip encoder as floating point */
45#define FLOATING_POINT
46#endif
33 47
34/* Define to 1 if you have the <dlfcn.h> header file. */ 48/* Define to 1 if you have the <dlfcn.h> header file. */
35/* #undef HAVE_DLFCN_H */ 49/* #undef HAVE_DLFCN_H */
diff --git a/apps/codecs/libspeex/rockbox.h b/apps/codecs/libspeex/rockbox.h
index 0f8c6d932f..0e0d3ed647 100644
--- a/apps/codecs/libspeex/rockbox.h
+++ b/apps/codecs/libspeex/rockbox.h
@@ -19,6 +19,9 @@
19#ifndef SPEEX_ROCKBOX_H 19#ifndef SPEEX_ROCKBOX_H
20#define SPEEX_ROCKBOX_H 20#define SPEEX_ROCKBOX_H
21 21
22/* We don't want all this stuff if we're building encoder */
23#ifndef ROCKBOX_VOICE_ENCODER
24
22#include "../codec.h" 25#include "../codec.h"
23#include "../lib/codeclib.h" 26#include "../lib/codeclib.h"
24 27
@@ -106,5 +109,7 @@ static inline void _speex_putc(int ch, void *file)
106 //printf("%c", ch); 109 //printf("%c", ch);
107} 110}
108 111
112#endif /* ROCKBOX_VOICE_ENCODER */
113
109#endif 114#endif
110 115
diff --git a/apps/codecs/libspeex/speex_header.c b/apps/codecs/libspeex/speex_header.c
index eb4c199d46..30f47206c4 100644
--- a/apps/codecs/libspeex/speex_header.c
+++ b/apps/codecs/libspeex/speex_header.c
@@ -47,7 +47,7 @@
47/** Convert little endian */ 47/** Convert little endian */
48static inline spx_int32_t le_int(spx_int32_t i) 48static inline spx_int32_t le_int(spx_int32_t i)
49{ 49{
50#if 1 50#ifdef ROCKBOX
51 return letoh32(i); 51 return letoh32(i);
52#elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) 52#elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
53 spx_uint32_t ui, ret; 53 spx_uint32_t ui, ret;
diff --git a/tools/Makefile b/tools/Makefile
index 4b72b4c638..50d05abda8 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -11,7 +11,7 @@ LDFLAGS := -g
11 11
12CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ 12CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \
13 generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \ 13 generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \
14 lngdump telechips gigabeats mktccboot mknkboot 14 lngdump telechips gigabeats mktccboot mknkboot rbspeexenc
15 15
16all: 16all:
17 @echo "Run make in your build directory!" 17 @echo "Run make in your build directory!"
@@ -76,6 +76,9 @@ player_unifont: player_unifont.c ../firmware/drivers/lcd-charset-player.c
76uclpack: 76uclpack:
77 $(SILENT)$(MAKE) -C ucl 77 $(SILENT)$(MAKE) -C ucl
78 78
79rbspeexenc:
80 $(SILENT)$(MAKE) -C rbspeex
81
79wavtrim: wavtrim.c 82wavtrim: wavtrim.c
80 $(SILENT)$(CC) -g $+ -o $@ 83 $(SILENT)$(CC) -g $+ -o $@
81 84
@@ -86,4 +89,5 @@ clean:
86 @echo "Cleaning tools" 89 @echo "Cleaning tools"
87 $(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do echo $$f.exe $$f.o $$f.obj ; done) *.ajf *~ 90 $(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do echo $$f.exe $$f.o $$f.obj ; done) *.ajf *~
88 $(SILENT)$(MAKE) -C ucl clean 91 $(SILENT)$(MAKE) -C ucl clean
92 $(SILENT)$(MAKE) -C rbspeex clean
89 93
diff --git a/tools/rbspeex/Makefile b/tools/rbspeex/Makefile
new file mode 100644
index 0000000000..4771fe4ea2
--- /dev/null
+++ b/tools/rbspeex/Makefile
@@ -0,0 +1,56 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id: Makefile,v 1.16 2006-09-02 22:34:13 bagder Exp $
8#
9
10ifndef V
11SILENT = @
12endif
13
14SPEEXSRC = ../../apps/codecs/libspeex
15
16INCLUDES = -I $(SPEEXSRC) -iquote $(SPEEXSRC)
17SPEEXOPTS = -DHAVE_CONFIG_H -DROCKBOX_VOICE_ENCODER
18
19CFLAGS = $(SPEEXOPTS) $(INCLUDES) -O3 -fomit-frame-pointer -Wno-unused-parameter
20
21# This sets up 'SRC' based on the files mentioned in SOURCES
22SRC := $(shell cat $(SPEEXSRC)/SOURCES | $(CC) $(CFLAGS) -E -P - | grep -v "^\#")
23
24SOURCES = $(SRC:%.c=$(SPEEXSRC)/%.c) rbspeexenc.c
25OBJS := $(SRC:%.c=%.o) rbspeexenc.o
26DEPFILE = dep-speex
27DIRS =
28
29.PHONY : all
30
31all: ../rbspeexenc
32
33$(DEPFILE): $(SOURCES)
34 $(SILENT)rm -f $(DEPFILE)
35 $(SILENT)(for each in $(SOURCES) x; do \
36 if test "x" != "$$each"; then \
37 obj=`echo $$each | sed -e 's/\.[cS]/.o/' | sed -e 's/^.*\///' `; \
38 $(CC) -MG -MM -MT "$$obj" $(CFLAGS) $$each 2>/dev/null; \
39 fi; \
40 if test -n "$$del"; then \
41 rm $$del; \
42 del=""; \
43 fi \
44 done > $(DEPFILE); \
45 echo "oo" > /dev/null )
46
47../rbspeexenc: $(OBJS) $(DEPFILE)
48 gcc -o ../rbspeexenc $(OBJS) -lm
49
50%.o:
51 $(CC) $(CFLAGS) -c $< -o $@
52
53clean:
54 rm -f $(OBJS) dep-speex
55
56-include $(DEPFILE)
diff --git a/tools/rbspeex/rbspeexenc.c b/tools/rbspeex/rbspeexenc.c
new file mode 100644
index 0000000000..5d301998da
--- /dev/null
+++ b/tools/rbspeex/rbspeexenc.c
@@ -0,0 +1,239 @@
1/**************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 Thom Johansen
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ***************************************************************************/
18
19#include <speex/speex.h>
20#include <speex/speex_resampler.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdbool.h>
25
26/* Read an unaligned 32-bit little endian long from buffer. */
27unsigned int get_long_le(unsigned char *p)
28{
29 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
30}
31
32bool get_wave_metadata(FILE *fd, int *numchan, int *bps, int *sr, int *numsamples)
33{
34 unsigned char buf[1024];
35 unsigned long totalsamples = 0;
36 unsigned long channels = 0;
37 unsigned long bitspersample = 0;
38 unsigned long numbytes = 0;
39 size_t read_bytes;
40 int i;
41
42 if ((read_bytes = fread(buf, 1, 12, fd)) < 12)
43 return false;
44
45 if ((memcmp(buf, "RIFF",4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0))
46 return false;
47
48 /* iterate over WAVE chunks until 'data' chunk */
49 while (1) {
50 /* get chunk header */
51 if ((read_bytes = fread(buf, 1, 8, fd)) < 8)
52 return false;
53
54 /* chunkSize */
55 i = get_long_le(&buf[4]);
56
57 if (memcmp(buf, "fmt ", 4) == 0) {
58 /* get rest of chunk */
59 if ((read_bytes = fread(buf, 1, 16, fd)) < 16)
60 return false;
61
62 i -= 16;
63
64 channels = *numchan = buf[2] | (buf[3] << 8);
65 *sr = get_long_le(&buf[4]);
66 /* wBitsPerSample */
67 bitspersample = *bps = buf[14] | (buf[15] << 8);
68 } else if (memcmp(buf, "data", 4) == 0) {
69 numbytes = i;
70 break;
71 } else if (memcmp(buf, "fact", 4) == 0) {
72 /* dwSampleLength */
73 if (i >= 4) {
74 /* get rest of chunk */
75 if ((read_bytes = read(buf, 1, 4, fd)) < 4)
76 return false;
77
78 i -= 4;
79 totalsamples = get_long_le(buf);
80 }
81 }
82
83 /* seek to next chunk (even chunk sizes must be padded) */
84 if (i & 0x01)
85 i++;
86
87 if (fseek(fd, i, SEEK_CUR) < 0)
88 return false;
89 }
90
91 if ((numbytes == 0) || (channels == 0))
92 return false;
93
94 if (totalsamples == 0) {
95 /* for PCM only */
96 totalsamples = numbytes/((((bitspersample - 1) / 8) + 1)*channels);
97 }
98 *numsamples = totalsamples;
99 return true;
100}
101
102int main(int argc, char **argv)
103{
104 FILE *fin, *fout;
105 spx_int16_t *in, *inpos;
106 spx_int16_t enc_buf[640]; /* Max frame size */
107 char cbits[200];
108 int nbytes;
109 void *st;
110 SpeexResamplerState *resampler = NULL;
111 SpeexBits bits;
112 int i, tmp;
113 float ftmp;
114 int numchan, bps, sr, numsamples;
115 int frame_size;
116
117 if (argc < 3) {
118 printf("Usage: rbspeexenc [options] infile outfile\n"
119 "Options:\n"
120 " -q x Quality, floating point number in the range [0-10]\n"
121 " -c x Complexity, affects quality and encoding time, where\n"
122 " both increase with increasing values, range [0-10]\n"
123 " Defaults are as in speexenc.\n"
124 "\nWARNING: This tool will create files that are only usable by Rockbox!\n"
125 );
126 return 1;
127 }
128
129 /* We'll eat an entire WAV file here, and encode it with Speex, packing the
130 * bits as tightly as we can. Output is completely raw, with absolutely
131 * nothing to identify the contents.
132 */
133
134 /* Wideband encoding */
135 st = speex_encoder_init(&speex_wb_mode);
136
137 /* VBR */
138 tmp = 1;
139 speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
140 /* Quality, 0-10 */
141 ftmp = 8.f;
142 for (i = 1; i < argc - 2; ++i) {
143 if (strncmp(argv[i], "-q", 2) == 0) {
144 ftmp = atof(argv[i + 1]);
145 break;
146 }
147 }
148 speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &ftmp);
149 /* Complexity, 0-10 */
150 tmp = 3;
151 for (i = 1; i < argc - 2; ++i) {
152 if (strncmp(argv[i], "-c", 2) == 0) {
153 tmp = atoi(argv[i + 1]);
154 break;
155 }
156 }
157 speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
158 speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
159
160 fin = fopen(argv[argc - 2], "rb");
161 if (!get_wave_metadata(fin, &numchan, &bps, &sr, &numsamples)) {
162 printf("invalid wave file!\n");
163 return 1;
164 }
165 if (sr != 16000) {
166 resampler = speex_resampler_init(1, sr, 16000, 10, NULL);
167 speex_resampler_skip_zeros(resampler);
168 printf("Resampling from %i Hz to 16000 Hz\n", sr);
169 }
170 if (numchan != 1) {
171 printf("Error: input file must be mono\n");
172 return 1;
173 }
174 if (bps != 16) {
175 printf("samples must be 16 bit!\n");
176 return 1;
177 }
178
179 /* Read input samples into a buffer */
180 in = malloc(numsamples*2);
181 if (malloc == NULL) {
182 printf("error on malloc\n");
183 return 1;
184 }
185 fread(in, 2, numsamples, fin);
186 fclose(fin);
187
188 speex_bits_init(&bits);
189 inpos = in;
190 fout = fopen(argv[argc - 1], "wb");
191
192 while (numsamples > 0) {
193 int samples = frame_size;
194
195 /* Check if we need to resample */
196 if (sr != 16000) {
197 spx_uint32_t in_len = numsamples, out_len = frame_size;
198
199 /* Limit this or resampler will try to allocate it all on stack */
200 if (in_len > 2000)
201 in_len = 2000;
202 speex_resampler_process_int(resampler, 0, inpos, &in_len,
203 enc_buf, &out_len);
204 inpos += in_len;
205 samples = out_len;
206 numsamples -= in_len;
207 } else {
208 if (samples > numsamples)
209 samples = numsamples;
210 memcpy(enc_buf, inpos, samples*2);
211 inpos += frame_size;
212 numsamples -= frame_size;
213 }
214 /* Pad out with zeros if we didn't fill all input */
215 memset(enc_buf + samples, 0, (frame_size - samples)*2);
216
217 speex_encode_int(st, enc_buf, &bits);
218
219 /* Copy the bits to an array of char that can be written */
220 nbytes = speex_bits_write_whole_bytes(&bits, cbits, 200);
221
222 /* Write the compressed data */
223 fwrite(cbits, 1, nbytes, fout);
224 }
225
226 /* Squeeze out the last bits */
227 nbytes = speex_bits_write(&bits, cbits, 200);
228 fwrite(cbits, 1, nbytes, fout);
229
230 /*Destroy the encoder state*/
231 speex_encoder_destroy(st);
232 /*Destroy the bit-packing struct*/
233 speex_bits_destroy(&bits);
234 if (resampler != NULL)
235 speex_resampler_destroy(resampler);
236 fclose(fout);
237 free(in);
238 return 0;
239}