diff options
Diffstat (limited to 'apps/talk.c')
-rw-r--r-- | apps/talk.c | 66 |
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 */ | |||
128 | static int queue_read; /* read index of queue, by ISR context */ | 109 | static int queue_read; /* read index of queue, by ISR context */ |
129 | static enum talk_status talk_status = TALK_STATUS_OK; | 110 | static 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 */ |
131 | static struct mutex queue_mutex SHAREDBSS_ATTR; | 112 | static 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); }) |
134 | static int sent; /* how many bytes handed over to playback, owned by ISR */ | 115 | static 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 */ |
187 | static void sync_callback(int handle, bool sync_on) | 168 | static 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) | |||
735 | void talk_force_shutup(void) | 716 | void 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) | |||
1261 | int talk_value_decimal(long n, int unit, int decimals, bool enqueue) | 1241 | int 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) | |||
1411 | int talk_spell(const char* spell, bool enqueue) | 1391 | int 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 | ||