summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2004-03-14 21:33:53 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2004-03-14 21:33:53 +0000
commit4f36ea8fbf877e8af938c0bb16591f3c6cffd4f8 (patch)
treec0dbd4a148a54c8c2851d95149ed6d4e91053bd6 /firmware
parent62b095d02972ac8c6fb63ab0a38d1fa0c483b85b (diff)
downloadrockbox-4f36ea8fbf877e8af938c0bb16591f3c6cffd4f8.tar.gz
rockbox-4f36ea8fbf877e8af938c0bb16591f3c6cffd4f8.zip
First step of the voice-UI: the menus can talk. You need a "voicefont" file in .rockbox to use this.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4381 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/talk.h34
-rw-r--r--firmware/mpeg.c3
-rw-r--r--firmware/talk.c209
3 files changed, 246 insertions, 0 deletions
diff --git a/firmware/export/talk.h b/firmware/export/talk.h
new file mode 100644
index 0000000000..b2af46f15e
--- /dev/null
+++ b/firmware/export/talk.h
@@ -0,0 +1,34 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Jörg Hohensohn
11 *
12 * This module collects the Talkbox and voice UI functions.
13 * (Talkbox reads directory names from mp3 clips called thumbnails,
14 * the voice UI lets menus and screens "talk" from a voicefont in memory.
15 *
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#ifndef __TALK_H__
25#define __TALK_H__
26
27#include <stdbool.h>
28
29void talk_init(void);
30int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
31int talk_id(int id, bool block); /* play a voice ID from voicefont */
32int talk_file(char* filename, bool block); /* play a thumbnail from file */
33
34#endif /* __TALK_H__ */
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index ff545f03d0..0f676f1612 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2134,6 +2134,7 @@ void mpeg_record(char *filename)
2134 recording_filename[MAX_PATH - 1] = 0; 2134 recording_filename[MAX_PATH - 1] = 0;
2135 2135
2136 disable_xing_header = false; 2136 disable_xing_header = false;
2137 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2137 queue_post(&mpeg_queue, MPEG_RECORD, NULL); 2138 queue_post(&mpeg_queue, MPEG_RECORD, NULL);
2138} 2139}
2139 2140
@@ -2148,6 +2149,7 @@ static void start_prerecording(void)
2148 prerecord_timeout = current_tick + HZ; 2149 prerecord_timeout = current_tick + HZ;
2149 memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); 2150 memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
2150 reset_mp3_buffer(); 2151 reset_mp3_buffer();
2152 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2151 2153
2152 is_prerecording = true; 2154 is_prerecording = true;
2153 2155
@@ -2404,6 +2406,7 @@ void mpeg_play(int offset)
2404#else 2406#else
2405 is_playing = true; 2407 is_playing = true;
2406 2408
2409 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2407 queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset); 2410 queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
2408#endif /* #ifdef SIMULATOR */ 2411#endif /* #ifdef SIMULATOR */
2409 2412
diff --git a/firmware/talk.c b/firmware/talk.c
new file mode 100644
index 0000000000..d02a4efd7f
--- /dev/null
+++ b/firmware/talk.c
@@ -0,0 +1,209 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Jörg Hohensohn
11 *
12 * This module collects the Talkbox and voice UI functions.
13 * (Talkbox reads directory names from mp3 clips called thumbnails,
14 * the voice UI lets menus and screens "talk" from a voicefont in memory.
15 *
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include <stdio.h>
25#include <stddef.h>
26#include "file.h"
27#include "buffer.h"
28#include "kernel.h"
29#include "mp3_playback.h"
30#include "mpeg.h"
31#include "talk.h"
32extern void bitswap(unsigned char *data, int length); /* no header for this */
33
34/***************** Constants *****************/
35
36#define VOICEFONT_FILENAME "/.rockbox/voicefont"
37
38
39/***************** Data types *****************/
40
41struct clip_entry /* one entry of the index table */
42{
43 int offset; /* offset from start of voicefont file */
44 int size; /* size of the clip */
45};
46
47struct voicefont /* file format of our "voicefont" */
48{
49 int version; /* version of the voicefont */
50 int headersize; /* size of the header, =offset to index */
51 int id_max; /* number of clips contained */
52 struct clip_entry index[]; /* followed by the index table */
53 /* and finally the bitswapped mp3 clips, not visible here */
54};
55
56
57/***************** Globals *****************/
58
59static unsigned char* p_thumbnail; /* buffer for thumbnail */
60static long size_for_thumbnail; /* leftover buffer size for it */
61static struct voicefont* p_voicefont; /* loaded voicefont */
62static bool has_voicefont; /* a voicefont file is present */
63static bool is_playing; /* we're currently playing */
64
65
66
67/***************** Private implementation *****************/
68
69static int load_voicefont(void)
70{
71 int fd;
72 int size;
73
74 p_voicefont = NULL; /* indicate no voicefont if we fail below */
75
76 fd = open(VOICEFONT_FILENAME, O_RDONLY);
77 if (fd < 0) /* failed to open */
78 {
79 p_voicefont = NULL; /* indicate no voicefont */
80 has_voicefont = false; /* don't try again */
81 return 0;
82 }
83
84 size = read(fd, mp3buf, mp3end - mp3buf);
85 if (size > 1000
86 && ((struct voicefont*)mp3buf)->headersize
87 == offsetof(struct voicefont, index))
88 {
89 p_voicefont = (struct voicefont*)mp3buf;
90
91 /* thumbnail buffer is the remaining space behind */
92 p_thumbnail = mp3buf + size;
93 p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */
94 size_for_thumbnail = mp3end - p_thumbnail;
95
96 /* max. DMA size, fixme */
97 if (size_for_thumbnail > 0xFFFF)
98 size_for_thumbnail = 0xFFFF;
99 }
100 else
101 {
102 has_voicefont = false; /* don't try again */
103 }
104 close(fd);
105
106 return size;
107}
108
109
110/* called in ISR context if mp3 data got consumed */
111void mp3_callback(unsigned char** start, int* size)
112{
113 (void)start; /* unused parameter, avoid warning */
114 *size = 0; /* end of data */
115 is_playing = false;
116 mp3_play_stop(); /* fixme: should be done by caller */
117}
118
119/***************** Public implementation *****************/
120
121void talk_init(void)
122{
123 has_voicefont = true; /* unless we fail later, assume we have one */
124 talk_buffer_steal();
125}
126
127
128/* somebody else claims the mp3 buffer, e.g. for regular play/record */
129int talk_buffer_steal(void)
130{
131 p_voicefont = NULL; /* indicate no voicefont (trashed) */
132 p_thumbnail = mp3buf; /* whole space for thumbnail */
133 size_for_thumbnail = mp3end - mp3buf;
134 /* max. DMA size, fixme */
135 if (size_for_thumbnail > 0xFFFF)
136 size_for_thumbnail = 0xFFFF;
137 return 0;
138}
139
140
141/* play a voice ID from voicefont */
142int talk_id(int id, bool block)
143{
144 int clipsize;
145
146 if (mpeg_status()) /* busy, buffer in use */
147 return -1;
148
149 if (p_voicefont == NULL && has_voicefont)
150 load_voicefont(); /* reload needed */
151
152 if (p_voicefont == NULL) /* still no voices? */
153 return -1;
154
155 if (id >= p_voicefont->id_max)
156 return -1;
157
158 clipsize = p_voicefont->index[id].size;
159 if (clipsize == 0) /* clip not included in voicefont */
160 return -1;
161
162 is_playing = true;
163 mp3_play_data(mp3buf + p_voicefont->index[id].offset,
164 clipsize, mp3_callback);
165 mp3_play_pause(true); /* kickoff audio */
166
167 while(block && is_playing)
168 sleep(1);
169
170 return 0;
171}
172
173
174/* play a thumbnail from file */
175int talk_file(char* filename, bool block)
176{
177 int fd;
178 int size;
179
180 if (mpeg_status()) /* busy, buffer in use */
181 return -1;
182
183 if (p_thumbnail == NULL || size_for_thumbnail <= 0)
184 return -1;
185
186 fd = open(filename, O_RDONLY);
187 if (fd < 0) /* failed to open */
188 {
189 return 0;
190 }
191
192 size = read(fd, p_thumbnail, size_for_thumbnail);
193 close(fd);
194
195 /* ToDo: find audio, skip ID headers and trailers */
196
197 if (size)
198 {
199 bitswap(p_thumbnail, size);
200 is_playing = true;
201 mp3_play_data(p_thumbnail, size, mp3_callback);
202 mp3_play_pause(true); /* kickoff audio */
203
204 while(block && is_playing)
205 sleep(1);
206 }
207
208 return size;
209}