summaryrefslogtreecommitdiff
path: root/apps/talk.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/talk.c')
-rw-r--r--apps/talk.c66
1 files changed, 23 insertions, 43 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 4b65700a5d..5d292b05d1 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -46,25 +46,6 @@
46#include "panic.h" 46#include "panic.h"
47#include "misc.h" /* time_split_units() */ 47#include "misc.h" /* time_split_units() */
48 48
49/* Memory layout varies between targets because the
50 Archos (MASCODEC) devices cannot mix voice and audio playback
51
52 MASCODEC | MASCODEC | SWCODEC
53 (playing) | (stopped) |
54 voicebuf-----------+-----------+------------
55 audio | voice | voice
56 |-----------|------------
57 | thumbnail | thumbnail
58 | |------------
59 | | filebuf
60 | |------------
61 | | audio
62 voicebufend----------+-----------+------------
63
64 SWCODEC allocates dedicated buffers (except voice and thumbnail are together
65 in the talkbuf), MASCODEC reuses audiobuf. */
66
67
68/***************** Constants *****************/ 49/***************** Constants *****************/
69 50
70#define QUEUE_SIZE 64 /* must be a power of two */ 51#define QUEUE_SIZE 64 /* must be a power of two */
@@ -128,7 +109,7 @@ static int queue_write; /* write index of queue, by application */
128static int queue_read; /* read index of queue, by ISR context */ 109static int queue_read; /* read index of queue, by ISR context */
129static enum talk_status talk_status = TALK_STATUS_OK; 110static enum talk_status talk_status = TALK_STATUS_OK;
130/* protects queue_read, queue_write and thumbnail_buf_used */ 111/* protects queue_read, queue_write and thumbnail_buf_used */
131static struct mutex queue_mutex SHAREDBSS_ATTR; 112static struct mutex queue_mutex SHAREDBSS_ATTR;
132#define talk_queue_lock() ({ mutex_lock(&queue_mutex); }) 113#define talk_queue_lock() ({ mutex_lock(&queue_mutex); })
133#define talk_queue_unlock() ({ mutex_unlock(&queue_mutex); }) 114#define talk_queue_unlock() ({ mutex_unlock(&queue_mutex); })
134static int sent; /* how many bytes handed over to playback, owned by ISR */ 115static int sent; /* how many bytes handed over to playback, owned by ISR */
@@ -182,7 +163,7 @@ static inline bool check_audio_status(void)
182 return true; 163 return true;
183} 164}
184 165
185/* ISR (mp3_callback()) must not run during moving of the clip buffer, 166/* ISR (voice_callback()) must not run during moving of the clip buffer,
186 * because the MAS may get out-of-sync */ 167 * because the MAS may get out-of-sync */
187static void sync_callback(int handle, bool sync_on) 168static void sync_callback(int handle, bool sync_on)
188{ 169{
@@ -269,13 +250,13 @@ static int open_voicefile(void)
269 char* p_lang = DEFAULT_VOICE_LANG; /* default */ 250 char* p_lang = DEFAULT_VOICE_LANG; /* default */
270 251
271 if ( global_settings.lang_file[0] && 252 if ( global_settings.lang_file[0] &&
272 global_settings.lang_file[0] != 0xff ) 253 global_settings.lang_file[0] != 0xff )
273 { /* try to open the voice file of the selected language */ 254 { /* try to open the voice file of the selected language */
274 p_lang = (char *)global_settings.lang_file; 255 p_lang = (char *)global_settings.lang_file;
275 } 256 }
276 257
277 snprintf(buf, sizeof(buf), LANG_DIR "/%s.voice", p_lang); 258 snprintf(buf, sizeof(buf), LANG_DIR "/%s.voice", p_lang);
278 259
279 return open(buf, O_RDONLY); 260 return open(buf, O_RDONLY);
280} 261}
281 262
@@ -725,7 +706,7 @@ static void mp3_callback(const void** start, size_t* size)
725 curr_hd[1] = commit_buffer[2]; 706 curr_hd[1] = commit_buffer[2];
726 curr_hd[2] = commit_buffer[3]; 707 curr_hd[2] = commit_buffer[3];
727 } 708 }
728 709
729 talk_queue_unlock(); 710 talk_queue_unlock();
730} 711}
731 712
@@ -735,7 +716,7 @@ static void mp3_callback(const void** start, size_t* size)
735void talk_force_shutup(void) 716void talk_force_shutup(void)
736{ 717{
737 /* Had nothing to do (was frame boundary or not our clip) */ 718 /* Had nothing to do (was frame boundary or not our clip) */
738 mp3_play_stop(); 719 voice_play_stop();
739 talk_queue_lock(); 720 talk_queue_lock();
740 queue_write = queue_read = 0; /* reset the queue */ 721 queue_write = queue_read = 0; /* reset the queue */
741 thumbnail_buf_used = 0; 722 thumbnail_buf_used = 0;
@@ -761,7 +742,7 @@ static void queue_clip(struct queue_entry *clip, bool enqueue)
761 /* Something is being enqueued, force_enqueue_next override is no 742 /* Something is being enqueued, force_enqueue_next override is no
762 longer in effect. */ 743 longer in effect. */
763 force_enqueue_next = false; 744 force_enqueue_next = false;
764 745
765 if (!clip->length) 746 if (!clip->length)
766 return; /* safety check */ 747 return; /* safety check */
767 talk_queue_lock(); 748 talk_queue_lock();
@@ -780,11 +761,10 @@ static void queue_clip(struct queue_entry *clip, bool enqueue)
780 size_t size; 761 size_t size;
781 void *buf = commit_transfer(qe, &size); 762 void *buf = commit_transfer(qe, &size);
782 last_clip = qe; 763 last_clip = qe;
783 mp3_play_data(buf, size, mp3_callback); 764 voice_play_data(buf, size, mp3_callback);
784 curr_hd[0] = commit_buffer[1]; 765 curr_hd[0] = commit_buffer[1];
785 curr_hd[1] = commit_buffer[2]; 766 curr_hd[1] = commit_buffer[2];
786 curr_hd[2] = commit_buffer[3]; 767 curr_hd[2] = commit_buffer[3];
787 mp3_play_pause(true); /* kickoff audio */
788 } 768 }
789 769
790 need_shutup = true; 770 need_shutup = true;
@@ -864,7 +844,7 @@ void talk_init(void)
864 } 844 }
865 avg_size = total_size / non_empty; 845 avg_size = total_size / non_empty;
866 max_clips = MIN((int)(MAX_CLIP_BUFFER_SIZE/avg_size) + 1, non_empty); 846 max_clips = MIN((int)(MAX_CLIP_BUFFER_SIZE/avg_size) + 1, non_empty);
867 /* account for possible thumb clips */ 847 /* account for possible thumb clips */
868 total_size += THUMBNAIL_RESERVE; 848 total_size += THUMBNAIL_RESERVE;
869 max_clips += 16; 849 max_clips += 16;
870 voicefile_size = total_size; 850 voicefile_size = total_size;
@@ -1156,19 +1136,19 @@ int talk_number(long n, bool enqueue)
1156 1136
1157 if (!enqueue) 1137 if (!enqueue)
1158 talk_shutup(); /* cut off all the pending stuff */ 1138 talk_shutup(); /* cut off all the pending stuff */
1159 1139
1160 if (n==0) 1140 if (n==0)
1161 { /* special case */ 1141 { /* special case */
1162 talk_id(VOICE_ZERO, true); 1142 talk_id(VOICE_ZERO, true);
1163 return 0; 1143 return 0;
1164 } 1144 }
1165 1145
1166 if (n<0) 1146 if (n<0)
1167 { 1147 {
1168 talk_id(VOICE_MINUS, true); 1148 talk_id(VOICE_MINUS, true);
1169 n = -n; 1149 n = -n;
1170 } 1150 }
1171 1151
1172 while (n) 1152 while (n)
1173 { 1153 {
1174 int segment = n / mil; /* extract in groups of 3 digits */ 1154 int segment = n / mil; /* extract in groups of 3 digits */
@@ -1197,7 +1177,7 @@ int talk_number(long n, bool enqueue)
1197 /* direct indexing */ 1177 /* direct indexing */
1198 if (ones) 1178 if (ones)
1199 talk_id(VOICE_ZERO + ones, true); 1179 talk_id(VOICE_ZERO + ones, true);
1200 1180
1201 /* add billion, million, thousand */ 1181 /* add billion, million, thousand */
1202 if (mil) 1182 if (mil)
1203 talk_id(VOICE_THOUSAND + level, true); 1183 talk_id(VOICE_THOUSAND + level, true);
@@ -1261,21 +1241,21 @@ int talk_value(long n, int unit, bool enqueue)
1261int talk_value_decimal(long n, int unit, int decimals, bool enqueue) 1241int talk_value_decimal(long n, int unit, int decimals, bool enqueue)
1262{ 1242{
1263 int unit_id; 1243 int unit_id;
1264 static const int unit_voiced[] = 1244 static const int unit_voiced[] =
1265 { /* lookup table for the voice ID of the units */ 1245 { /* lookup table for the voice ID of the units */
1266 [0 ... UNIT_LAST-1] = -1, /* regular ID, int, signed */ 1246 [0 ... UNIT_LAST-1] = -1, /* regular ID, int, signed */
1267 [UNIT_MS] 1247 [UNIT_MS]
1268 = VOICE_MILLISECONDS, /* here come the "real" units */ 1248 = VOICE_MILLISECONDS, /* here come the "real" units */
1269 [UNIT_SEC] 1249 [UNIT_SEC]
1270 = VOICE_SECONDS, 1250 = VOICE_SECONDS,
1271 [UNIT_MIN] 1251 [UNIT_MIN]
1272 = VOICE_MINUTES, 1252 = VOICE_MINUTES,
1273 [UNIT_HOUR] 1253 [UNIT_HOUR]
1274 = VOICE_HOURS, 1254 = VOICE_HOURS,
1275 [UNIT_KHZ] 1255 [UNIT_KHZ]
1276 = VOICE_KHZ, 1256 = VOICE_KHZ,
1277 [UNIT_DB] 1257 [UNIT_DB]
1278 = VOICE_DB, 1258 = VOICE_DB,
1279 [UNIT_PERCENT] 1259 [UNIT_PERCENT]
1280 = VOICE_PERCENT, 1260 = VOICE_PERCENT,
1281 [UNIT_MAH] 1261 [UNIT_MAH]
@@ -1411,7 +1391,7 @@ int talk_time_intervals(long time, int unit_idx, bool enqueue)
1411int talk_spell(const char* spell, bool enqueue) 1391int talk_spell(const char* spell, bool enqueue)
1412{ 1392{
1413 char c; /* currently processed char */ 1393 char c; /* currently processed char */
1414 1394
1415 if (talk_temp_disable_count > 0) 1395 if (talk_temp_disable_count > 0)
1416 return -1; /* talking has been disabled */ 1396 return -1; /* talking has been disabled */
1417 if (!check_audio_status()) 1397 if (!check_audio_status())
@@ -1419,7 +1399,7 @@ int talk_spell(const char* spell, bool enqueue)
1419 1399
1420 if (!enqueue) 1400 if (!enqueue)
1421 talk_shutup(); /* cut off all the pending stuff */ 1401 talk_shutup(); /* cut off all the pending stuff */
1422 1402
1423 while ((c = *spell++) != '\0') 1403 while ((c = *spell++) != '\0')
1424 { 1404 {
1425 /* if this grows into too many cases, I should use a table */ 1405 /* if this grows into too many cases, I should use a table */
@@ -1434,7 +1414,7 @@ int talk_spell(const char* spell, bool enqueue)
1434 else if (c == '+') 1414 else if (c == '+')
1435 talk_id(VOICE_PLUS, true); 1415 talk_id(VOICE_PLUS, true);
1436 else if (c == '.') 1416 else if (c == '.')
1437 talk_id(VOICE_DOT, true); 1417 talk_id(VOICE_DOT, true);
1438 else if (c == ' ') 1418 else if (c == ' ')
1439 talk_id(VOICE_PAUSE, true); 1419 talk_id(VOICE_PAUSE, true);
1440 else if (c == '/') 1420 else if (c == '/')
@@ -1448,7 +1428,7 @@ void talk_disable(bool disable)
1448{ 1428{
1449 if (disable) 1429 if (disable)
1450 talk_temp_disable_count++; 1430 talk_temp_disable_count++;
1451 else 1431 else
1452 talk_temp_disable_count--; 1432 talk_temp_disable_count--;
1453} 1433}
1454 1434