FS#7994 - Rename talk.c API, make talk_disable() affect all talking (not just menus), hopefully save some space.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15206 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/alarm_menu.c b/apps/alarm_menu.c
index 5709c5a..391558a 100644
--- a/apps/alarm_menu.c
+++ b/apps/alarm_menu.c
@@ -44,7 +44,7 @@
 
 static void speak_time(int hours, int minutes, bool speak_hours)
 {
-    if (talk_menus_enabled()){
+    if (global_settings.talk_menu){
         if(speak_hours) {
             talk_value(hours, UNIT_HOUR, false);
             talk_value(minutes, UNIT_MIN, true);
@@ -86,7 +86,7 @@
                 screens[i].puts(0, 3, str(LANG_ALARM_MOD_KEYS));
             }
             /* Talk when entering the wakeup screen */
-            if (talk_menus_enabled())
+            if (global_settings.talk_menu)
             {
                 talk_value(h, UNIT_HOUR, true);
                 talk_value(m, UNIT_MIN, true);
@@ -113,7 +113,7 @@
                 rtc_init();
                 rtc_set_alarm(h,m);
                 rtc_enable_alarm(true);
-                if (talk_menus_enabled())
+                if (global_settings.talk_menu)
                 {
                     talk_id(LANG_ALARM_MOD_TIME_TO_GO, true);
                     talk_value(togo / 60, UNIT_HOUR, true);
@@ -164,7 +164,7 @@
          case ACTION_STD_NEXTREPEAT:
              h = (h+1) % 24;
 
-             if (talk_menus_enabled())
+             if (global_settings.talk_menu)
                  talk_value(h, UNIT_HOUR, false);
              break;
 
@@ -173,7 +173,7 @@
         case ACTION_STD_PREVREPEAT:
              h = (h+23) % 24;
              
-             if (talk_menus_enabled())
+             if (global_settings.talk_menu)
                  talk_value(h, UNIT_HOUR, false);
              break;
 
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 4522859..184281b 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -667,7 +667,7 @@
             item--;
         }
         
-        if (item != last_item && talk_menus_enabled())
+        if (item != last_item && global_settings.talk_menu)
         {
             last_item = item;
             
diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c
index 4f446fc..3b26ab1 100644
--- a/apps/gui/option_select.c
+++ b/apps/gui/option_select.c
@@ -133,7 +133,7 @@
 
 static void option_talk(struct settings_list *setting, int temp_var)
 {
-    if (!talk_menus_enabled())
+    if (!global_settings.talk_menu)
         return;
     if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
     {
diff --git a/apps/gui/yesno.c b/apps/gui/yesno.c
index 7c8afb3..4e86b01 100644
--- a/apps/gui/yesno.c
+++ b/apps/gui/yesno.c
@@ -145,7 +145,7 @@
     while (result==-1)
     {
         /* Repeat the question every 5secs (more or less) */
-        if (talk_menus_enabled()
+        if (global_settings.talk_menu
             && (talked_tick==0 || TIME_AFTER(current_tick, talked_tick+HZ*5)))
         {
             talked_tick = current_tick;
@@ -175,7 +175,7 @@
     FOR_NB_SCREENS(i)
         result_displayed=gui_yesno_draw_result(&(yn[i]), result);
 
-    if (talk_menus_enabled())
+    if (global_settings.talk_menu)
     {
         talk_idarray(voice_ids, false);
         talk_force_enqueue_next();
diff --git a/apps/main.c b/apps/main.c
index e4fd6bc..366fed9 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -225,7 +225,7 @@
             /* hwcodec can't use voice here, as the database commit
              * uses the audio buffer. */
             static long talked_tick = 0;
-            if(talk_menus_enabled()
+            if(global_settings.talk_menu
                && (talked_tick == 0
                    || TIME_AFTER(current_tick, talked_tick+7*HZ)))
             {
diff --git a/apps/menu.c b/apps/menu.c
index 1dedc42..55f1938 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -225,7 +225,7 @@
     unsigned char *str;
     int sel;
     
-    if (talk_menus_enabled())
+    if (global_settings.talk_menu)
     {
         sel = get_menu_selection(gui_synclist_get_sel_pos(lists),menu);
         if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index 2e9d0d0..1940c14 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -161,7 +161,7 @@
                 size2 = 0;
 #endif
 
-            if (talk_menus_enabled())
+            if (global_settings.talk_menu)
             {   
                 /* say whatever is reasonable, no real connection to the screen */
                 bool enqueue = false; /* enqueue all but the first */
diff --git a/apps/misc.c b/apps/misc.c
index 3a47d2f..3c6ffd3 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -685,7 +685,7 @@
             audio_close_recording();       
 #endif
 
-            if(talk_menus_enabled())
+            if(global_settings.talk_menu)
             {
                 bool enqueue = false;
                 if(msg_id != -1)
diff --git a/apps/playback.c b/apps/playback.c
index c0a8c5a..5443ef5 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -677,7 +677,7 @@
 #ifdef PLAYBACK_VOICE
     /* Truncate any existing voice output so we don't have spelling
      * etc. over the first part of the played track */
-    do_shutup();
+    talk_force_shutup();
 #endif
 
     /* Start playback */
@@ -960,7 +960,7 @@
     if (!voice_codec_loaded)
         return;
 
-    do_shutup();
+    talk_force_shutup();
 
     /* Loop until voice empties it's queue, stops and picks up on the new
        track; the voice thread must be stopped and waiting for messages
diff --git a/apps/player/keyboard.c b/apps/player/keyboard.c
index c89161c..dad8fc0 100644
--- a/apps/player/keyboard.c
+++ b/apps/player/keyboard.c
@@ -74,7 +74,7 @@
 /* helper function to spell a char if voice UI is enabled */
 static void kbd_spellchar(char c)
 {
-    if (talk_menus_enabled()) /* voice UI? */
+    if (global_settings.talk_menu) /* voice UI? */
     {
         unsigned char tmp[5];
         /* store char to pass to talk_spell */
@@ -90,7 +90,7 @@
 
 static void say_edit(void)
 {
-    if (talk_menus_enabled())
+    if (global_settings.talk_menu)
         talk_id(VOICE_EDIT, false);
 }
 
@@ -112,7 +112,7 @@
 
     editpos = utf8length(text);
 
-    if (talk_menus_enabled()) /* voice UI? */
+    if (global_settings.talk_menu) /* voice UI? */
         talk_spell(text, true); /* spell initial text */ 
 
     while (!done)
@@ -284,7 +284,7 @@
                         editpos++;
                     }
                 }
-                if (talk_menus_enabled()) /* voice UI? */
+                if (global_settings.talk_menu) /* voice UI? */
                     talk_spell(text, false); /* speak revised text */
                 break;
 
diff --git a/apps/playlist.c b/apps/playlist.c
index 025e07d..ad60c84 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1664,7 +1664,7 @@
 {
     static long talked_tick = 0;
     long id = P2ID(fmt);
-    if(talk_menus_enabled() && id>=0)
+    if(global_settings.talk_menu && id>=0)
     {
         if(final || (count && (talked_tick == 0
                                || TIME_AFTER(current_tick, talked_tick+5*HZ))))
diff --git a/apps/plugin.c b/apps/plugin.c
index c06ae25..bbb6d6f 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -468,8 +468,7 @@
 #endif
     &global_settings,
     &global_status,
-    talk_disable_menus,
-    talk_enable_menus,
+    talk_disable,
 #if CONFIG_CODEC == SWCODEC
     codec_load_file,
     get_codec_filename,
diff --git a/apps/plugin.h b/apps/plugin.h
index e36c99c..ee58687 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -112,12 +112,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 83
+#define PLUGIN_API_VERSION 84
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 83
+#define PLUGIN_MIN_API_VERSION 84
 
 /* plugin return codes */
 enum plugin_status {
@@ -579,8 +579,7 @@
 #endif
     struct user_settings* global_settings;
     struct system_status *global_status;
-    void (*talk_disable_menus)(void);
-    void (*talk_enable_menus)(void);
+    void (*talk_disable)(bool disable);
 #if CONFIG_CODEC == SWCODEC
     int (*codec_load_file)(const char* codec, struct codec_api *api);
     const char *(*get_codec_filename)(int cod_spec);
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 8b6d1e2..37ac1fa 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -1170,7 +1170,7 @@
                 str_send_msg(&video_str, STREAM_QUIT, 0);
                 audio_str.status = STREAM_STOPPED;
             }
-    }
+        }
     }
 quit:
     return audio_str.status;
@@ -2227,6 +2227,7 @@
         api->splash(HZ*2, "No File");
         return PLUGIN_ERROR;        
     }
+    api->talk_disable(true);
 
     /* Initialize IRAM - stops audio and voice as well */
     PLUGIN_IRAM_INIT(api)
@@ -2253,6 +2254,7 @@
     audiosize -= graysize;
     if (grayscales < 33 || audiosize <= 0)
     {
+        rb->talk_disable(false);
         rb->splash(HZ, "gray buf error");
         return PLUGIN_ERROR;
     }
@@ -2261,7 +2263,10 @@
     /* Initialise our malloc buffer */
     audiosize = mpeg_alloc_init(audiobuf,audiosize, LIBMPEG2BUFFER_SIZE);
     if (audiosize == 0)
+    {
+        rb->talk_disable(false);
         return PLUGIN_ERROR;
+    }
 
     /* Set disk pointers to NULL */
     disk_buf_end = disk_buf_start = NULL;
@@ -2275,13 +2280,21 @@
     disk_buf_start = mpeg_malloc(disk_buf_size,-1);
 
     if (disk_buf_start == NULL)
+    {
+        rb->talk_disable(false);
         return PLUGIN_ERROR;
+    }
 
     if (!init_mpabuf())
+    {
+        rb->talk_disable(false);
         return PLUGIN_ERROR;
-
+    }
     if (!init_pcmbuf())
+    {
+        rb->talk_disable(false);
         return PLUGIN_ERROR;
+    }
 
     /* The remaining buffer is for use by libmpeg2 */
 
@@ -2290,6 +2303,7 @@
 
     if (in_file < 0){
         DEBUGF("Could not open %s\n",(char*)parameter);
+        rb->talk_disable(false);
         return PLUGIN_ERROR;
     }
     filename = (char*)parameter;
@@ -2322,6 +2336,7 @@
     switch (result)
     {
         case MPEG_START_QUIT:
+            rb->talk_disable(false);
             return 0;
         default:
             start_time = settings.resume_time;
@@ -2336,7 +2351,6 @@
 
     /* Turn off backlight timeout */
     backlight_force_on(rb); /* backlight control in lib/helper.c */
-    rb->talk_disable_menus();
 
 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
     rb->cpu_boost(true);
@@ -2463,8 +2477,7 @@
                         n = rb->read(in_file, disk_buf_tail,bytes_to_read);
                         if (n==0)
                             rb->splash(30,"buffer fill error");
-                    }
-                    
+                    }                   
 
                     bytes_to_read -= n;
                     file_remaining -= n;
@@ -2531,7 +2544,6 @@
 
     /* Turn on backlight timeout (revert to settings) */
     backlight_use_settings(rb); /* backlight control in lib/helper.c */
-    rb->talk_enable_menus();
-
+    rb->talk_disable(false);
     return status;
 }
diff --git a/apps/recorder/keyboard.c b/apps/recorder/keyboard.c
index 9c35f28..6c75d07 100644
--- a/apps/recorder/keyboard.c
+++ b/apps/recorder/keyboard.c
@@ -191,7 +191,7 @@
 /* helper function to spell a char if voice UI is enabled */
 static void kbd_spellchar(unsigned short c)
 {
-    if (talk_menus_enabled()) /* voice UI? */
+    if (global_settings.talk_menu) /* voice UI? */
     {
         unsigned char tmp[5];
         /* store char to pass to talk_spell */
@@ -208,7 +208,7 @@
 #ifdef KBD_MODES
 static void say_edit(void)
 {
-    if(talk_menus_enabled())
+    if(global_settings.talk_menu)
         talk_id(VOICE_EDIT, false);
 }
 #endif
@@ -527,7 +527,7 @@
     /* Initial edit position is after last character */
     editpos = utf8length(text);
 
-    if (talk_menus_enabled()) /* voice UI? */
+    if (global_settings.talk_menu) /* voice UI? */
         talk_spell(text, true); /* spell initial text */
 
 
@@ -832,7 +832,7 @@
                         kbd_spellchar(text[c]);
                     } 
 #if CONFIG_CODEC == SWCODEC
-                    else if (talk_menus_enabled())
+                    else if (global_settings.talk_menu)
                         pcmbuf_beep(1000, 150, 1500);
 #endif
                 }
@@ -877,7 +877,7 @@
                         kbd_spellchar(text[c]);
                     } 
 #if CONFIG_CODEC == SWCODEC
-                    else if (talk_menus_enabled())
+                    else if (global_settings.talk_menu)
                         pcmbuf_beep(1000, 150, 1500);
 #endif
                 }
@@ -1124,7 +1124,7 @@
                     kbd_inschar(text, buflen, &editpos, ch);
                 }
 
-                if (talk_menus_enabled()) /* voice UI? */
+                if (global_settings.talk_menu) /* voice UI? */
                     talk_spell(text, false);
 
                 /* speak revised text */
@@ -1153,7 +1153,7 @@
                     kbd_inschar(text, buflen, &editpos, ch);
                 }
 
-                if (talk_menus_enabled()) /* voice UI? */
+                if (global_settings.talk_menu) /* voice UI? */
                     talk_spell(text, false);   /* speak revised text */
                 break;
 
@@ -1166,7 +1166,7 @@
                     kbd_spellchar(text[c]);
                 }
 #if CONFIG_CODEC == SWCODEC
-                else if (talk_menus_enabled())
+                else if (global_settings.talk_menu)
                     pcmbuf_beep(1000, 150, 1500);
 #endif
                 break;
@@ -1180,7 +1180,7 @@
                     kbd_spellchar(text[c]);
                 }
 #if CONFIG_CODEC == SWCODEC
-                else if (talk_menus_enabled())
+                else if (global_settings.talk_menu)
                     pcmbuf_beep(1000, 150, 1500);
 #endif
                 break;
@@ -1212,7 +1212,7 @@
                         param[l].hangul = false;
                     kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
 
-                    if (talk_menus_enabled()) /* voice UI? */
+                    if (global_settings.talk_menu) /* voice UI? */
                         talk_spell(text, false);   /* speak revised text */
                 }
 #endif /* KBD_MORSE_INPUT */
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 3b706e1..84207c7 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -889,7 +889,7 @@
 
 #if CONFIG_CODEC == SWCODEC
     /* recording_menu gets messed up: so prevent manus talking */
-    talk_disable_menus();
+    talk_disable(true);
     /* audio_init_recording stops anything playing when it takes the audio
        buffer */
 #else
@@ -1873,8 +1873,8 @@
         /* Go back to playback mode */
         rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
 
-    /* restore talk_menu setting */
-    talk_enable_menus();
+    /* restore talking */
+    talk_disable(false);
 #else /* !SWCODEC */
     audio_init_playback();
 #endif /* CONFIG_CODEC == SWCODEC */
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 1c6c868..5acaabe 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -160,7 +160,7 @@
 
                     /* Display building progress */
                     static long talked_tick = 0;
-                    if(talk_menus_enabled() &&
+                    if(global_settings.talk_menu &&
                        (talked_tick == 0
                         || TIME_AFTER(current_tick, talked_tick+7*HZ)))
                     {
@@ -238,7 +238,7 @@
     (void)param;
     if (audio_status())
     {
-        shutup();
+        talk_shutup();
         ret_val = gui_wps_show();
     }
     else if ( global_status.resume_index != -1 )
diff --git a/apps/screens.c b/apps/screens.c
index ce62911..8cdacd7 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -158,7 +158,7 @@
     FOR_NB_SCREENS(i)
         screens[i].clear_display();
     gui_syncsplash(1, str(LANG_REMOVE_MMC));
-    if (talk_menus_enabled())
+    if (global_settings.talk_menu)
         talk_id(LANG_REMOVE_MMC, false);
 
     while (1)
@@ -822,7 +822,7 @@
     static const int unit[] = { UNIT_HOUR, UNIT_MIN, UNIT_SEC, 0, 0, 0 };
     int value = 0;
 
-    if (!talk_menus_enabled())
+    if (!global_settings.talk_menu)
         return;
 
     switch(cursorpos)
diff --git a/apps/settings.c b/apps/settings.c
index 6656b84..add2b24 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -949,7 +949,7 @@
 void talk_setting(void *global_settings_variable)
 {
     const struct settings_list *setting;
-    if (!talk_menus_enabled())
+    if (!global_settings.talk_menu)
         return;
     setting = find_setting(global_settings_variable, NULL);
     if (setting == NULL)
diff --git a/apps/talk.c b/apps/talk.c
index 4741012..ede0aff 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -80,10 +80,6 @@
 #define MAX_THUMBNAIL_BUFSIZE 0x10000
 #endif
 
-#ifndef SIMULATOR
-extern bool audio_is_initialized;
-#endif
-
 /***************** Data types *****************/
 
 struct clip_entry /* one entry of the index table */
@@ -118,8 +114,7 @@
 static struct voicefile* p_voicefile; /* loaded voicefile */
 static bool has_voicefile; /* a voicefile file is present */
 static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
-/* enqueue next utterance even if enqueue is false. */
-static bool force_enqueue_next;
+static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */
 static int queue_write; /* write index of queue, by application */
 static int queue_read; /* read index of queue, by ISR context */
 static int sent; /* how many bytes handed over to playback, owned by ISR */
@@ -131,16 +126,8 @@
 static unsigned long voicefile_size = 0; /* size of the loaded voice file */
 static unsigned char last_lang[MAX_FILENAME+1]; /* name of last used lang file (in talk_init) */
 static bool talk_initialized; /* true if talk_init has been called */
-static int talk_menu_disable; /* if non-zero, temporarily disable voice UI (not saved) */
+static int talk_temp_disable_count; /* if positive, temporarily disable voice UI (not saved) */
 
-/***************** Private prototypes *****************/
-
-static void load_voicefile(void);
-static void mp3_callback(unsigned char** start, size_t* size);
-static int queue_clip(unsigned char* buf, long size, bool enqueue);
-static int open_voicefile(void);
-static unsigned char* get_clip(long id, long* p_size);
-int shutup(void); /* Interrupt voice, as when enqueue is false */
 
 /***************** Private implementation *****************/
 
@@ -161,6 +148,50 @@
 }
 
 
+/* fetch a clip from the voice file */
+static unsigned char* get_clip(long id, long* p_size)
+{
+    long clipsize;
+    unsigned char* clipbuf;
+    
+    if (id > VOICEONLY_DELIMITER)
+    {   /* voice-only entries use the second part of the table */
+        id -= VOICEONLY_DELIMITER + 1;
+        if (id >= p_voicefile->id2_max)
+            return NULL; /* must be newer than we have */
+        id += p_voicefile->id1_max; /* table 2 is behind table 1 */
+    }
+    else
+    {   /* normal use of the first table */
+        if (id >= p_voicefile->id1_max)
+            return NULL; /* must be newer than we have */
+    }
+    
+    clipsize = p_voicefile->index[id].size;
+    if (clipsize == 0) /* clip not included in voicefile */
+        return NULL;
+    clipbuf = (unsigned char *) p_voicefile + p_voicefile->index[id].offset;
+
+#ifdef HAVE_MMC /* dynamic loading, on demand */
+    if (!(clipsize & LOADED_MASK))
+    {   /* clip used for the first time, needs loading */
+        lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
+        if (read(filehandle, clipbuf, clipsize) != clipsize)
+            return NULL; /* read error */
+
+        p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
+    }
+    else
+    {   /* clip is in memory already */
+        clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
+    }
+#endif
+
+    *p_size = clipsize;
+    return clipbuf;
+}
+
+
 /* load the voice file into the mp3 buffer */
 static void load_voicefile(void)
 {
@@ -252,7 +283,7 @@
 /* Are more voice clips queued and waiting? */
 bool is_voice_queued()
 {
-    return !!QUEUE_LEVEL;
+    return (QUEUE_LEVEL != 0);
 }
 
 
@@ -280,7 +311,7 @@
 
 re_check:
 
-    if (QUEUE_LEVEL) /* queue is not empty? */
+    if (QUEUE_LEVEL != 0) /* queue is not empty? */
     {   /* start next clip */
 #if CONFIG_CODEC != SWCODEC
         sent = MIN(queue[queue_read].len, 0xFFFF);
@@ -309,26 +340,22 @@
     }
 }
 
+/***************** Public routines *****************/
+
 /* stop the playback and the pending clips */
-int do_shutup(void)
+void talk_force_shutup(void)
 {
+    /* Most of this is MAS only */
 #if CONFIG_CODEC != SWCODEC
     unsigned char* pos;
     unsigned char* search;
     unsigned char* end;
-#endif
-
     if (QUEUE_LEVEL == 0) /* has ended anyway */
-    {
-#if CONFIG_CODEC == SWCODEC
-        mp3_play_stop();
-#endif
-        return 0;
-    }
-#if CONFIG_CODEC != SWCODEC
+        return;
+
 #if CONFIG_CPU == SH7034
     CHCR3 &= ~0x0001; /* disable the DMA (and therefore the interrupt also) */
-#endif
+#endif /* CONFIG_CPU == SH7034 */
     /* search next frame boundary and continue up to there */
     pos = search = mp3_get_pos();
     end = queue[queue_read].buf + queue[queue_read].len;
@@ -362,41 +389,38 @@
 #if CONFIG_CPU == SH7034
             DTCR3 = sent; /* let the DMA finish this frame */
             CHCR3 |= 0x0001; /* re-enable DMA */
-#endif
-            return 0;
+#endif /* CONFIG_CPU == SH7034 */
+            return;
         }
     }
-#endif
+#endif /* CONFIG_CODEC != SWCODEC */
 
-    /* nothing to do, was frame boundary or not our clip */
+    /* Either SWCODEC, or MAS had nothing to do (was frame boundary or not our clip) */
     mp3_play_stop();
-
     queue_write = queue_read = 0; /* reset the queue */
-    
-    return 0;
+    return;
 }
 
 /* Shutup the voice, except if force_enqueue_next is set. */
-int shutup(void)
+void talk_shutup(void)
 {
     if (!force_enqueue_next)
-        return do_shutup();
-    return 0;
+        talk_force_shutup();
 }
 
 /* schedule a clip, at the end or discard the existing queue */
-static int queue_clip(unsigned char* buf, long size, bool enqueue)
+static void queue_clip(unsigned char* buf, long size, bool enqueue)
 {
     int queue_level;
 
     if (!enqueue)
-        shutup(); /* cut off all the pending stuff */
+        talk_shutup(); /* cut off all the pending stuff */
     /* Something is being enqueued, force_enqueue_next override is no
        longer in effect. */
     force_enqueue_next = false;
     
     if (!size)
-        return 0; /* safety check */
+        return; /* safety check */
 #if CONFIG_CPU == SH7034
     /* disable the DMA temporarily, to be safe of race condition */
     CHCR3 &= ~0x0001;
@@ -431,50 +455,7 @@
 #endif
     }
 
-    return 0;
-}
-
-/* fetch a clip from the voice file */
-static unsigned char* get_clip(long id, long* p_size)
-{
-    long clipsize;
-    unsigned char* clipbuf;
-    
-    if (id > VOICEONLY_DELIMITER)
-    {   /* voice-only entries use the second part of the table */
-        id -= VOICEONLY_DELIMITER + 1;
-        if (id >= p_voicefile->id2_max)
-            return NULL; /* must be newer than we have */
-        id += p_voicefile->id1_max; /* table 2 is behind table 1 */
-    }
-    else
-    {   /* normal use of the first table */
-        if (id >= p_voicefile->id1_max)
-            return NULL; /* must be newer than we have */
-    }
-    
-    clipsize = p_voicefile->index[id].size;
-    if (clipsize == 0) /* clip not included in voicefile */
-        return NULL;
-    clipbuf = (unsigned char *) p_voicefile + p_voicefile->index[id].offset;
-
-#ifdef HAVE_MMC /* dynamic loading, on demand */
-    if (!(clipsize & LOADED_MASK))
-    {   /* clip used for the first time, needs loading */
-        lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
-        if (read(filehandle, clipbuf, clipsize) != clipsize)
-            return NULL; /* read error */
-
-        p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
-    }
-    else
-    {   /* clip is in memory already */
-        clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
-    }
-#endif
-
-    *p_size = clipsize;
-    return clipbuf;
+    return;
 }
 
 
@@ -500,11 +481,12 @@
     p_silence = NULL; /* pause clip not accessible */
 }
 
+
 /***************** Public implementation *****************/
 
 void talk_init(void)
 {
-    talk_menu_disable = 0;
+    talk_temp_disable_count = 0;
     if (talk_initialized && !strcasecmp(last_lang, global_settings.lang_file))
     {
         /* not a new file, nothing to do */
@@ -558,7 +540,7 @@
 }
 
 /* somebody else claims the mp3 buffer, e.g. for regular play/record */
-int talk_buffer_steal(void)
+void talk_buffer_steal(void)
 {
 #if CONFIG_CODEC != SWCODEC
     mp3_play_stop();
@@ -570,9 +552,7 @@
         filehandle = -1;
     }
 #endif
-    reset_state();
-
-    return 0;
+    reset_state();;
 }
 
 
@@ -583,6 +563,8 @@
     unsigned char* clipbuf;
     int unit;
 
+    if (talk_temp_disable_count > 0)
+        return -1;  /* talking has been disabled */
 #if CONFIG_CODEC != SWCODEC
     if (audio_status()) /* busy, buffer in use */
         return -1; 
@@ -644,6 +626,8 @@
     int size;
     struct mp3entry info;
 
+    if (talk_temp_disable_count > 0)
+        return -1;  /* talking has been disabled */
 #if CONFIG_CODEC != SWCODEC
     if (audio_status()) /* busy, buffer in use */
         return -1; 
@@ -689,13 +673,15 @@
     int level = 2; /* mille count */
     long mil = 1000000000; /* highest possible "-illion" */
 
+    if (talk_temp_disable_count > 0)
+        return -1;  /* talking has been disabled */
 #if CONFIG_CODEC != SWCODEC
     if (audio_status()) /* busy, buffer in use */
         return -1; 
 #endif
 
     if (!enqueue)
-        shutup(); /* cut off all the pending stuff */
+        talk_shutup(); /* cut off all the pending stuff */
     
     if (n==0)
     {   /* special case */
@@ -785,6 +771,8 @@
             = VOICE_PM_UNITS_PER_TICK,
     };
 
+    if (talk_temp_disable_count > 0)
+        return -1;  /* talking has been disabled */
 #if CONFIG_CODEC != SWCODEC
     if (audio_status()) /* busy, buffer in use */
         return -1; 
@@ -819,13 +807,15 @@
 {
     char c; /* currently processed char */
     
+    if (talk_temp_disable_count > 0)
+        return -1;  /* talking has been disabled */
 #if CONFIG_CODEC != SWCODEC
     if (audio_status()) /* busy, buffer in use */
         return -1; 
 #endif
 
     if (!enqueue)
-        shutup(); /* cut off all the pending stuff */
+        talk_shutup(); /* cut off all the pending stuff */
     
     while ((c = *spell++) != '\0')
     {
@@ -849,26 +839,18 @@
     return 0;
 }
 
-bool talk_menus_enabled(void)
+void talk_disable(bool disable)
 {
-    return (global_settings.talk_menu && talk_menu_disable == 0);
-}
-
-
-void talk_disable_menus(void)
-{
-    talk_menu_disable++;
-}
-
-void talk_enable_menus(void)
-{    
-    talk_menu_disable--;
+    if (disable)
+        talk_temp_disable_count++;
+    else 
+        talk_temp_disable_count--;
 }
 
 #if CONFIG_RTC
 void talk_date_time(struct tm *tm, bool speak_current_time_string)
 {
-    if(talk_menus_enabled ())
+    if(global_settings.talk_menu)
     {
         if(speak_current_time_string)
             talk_id(VOICE_CURRENT_TIME, true);
diff --git a/apps/talk.h b/apps/talk.h
index e25a11c..a939c1f 100644
--- a/apps/talk.h
+++ b/apps/talk.h
@@ -66,19 +66,16 @@
 bool talk_voice_required(void); /* returns true if voice codec required */
 #endif
 int talk_get_bufsize(void); /* get the loaded voice file size */
-/* talk_buffer_steal - on SWCODEC, for use by buffer functions only */
-int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
+void talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
 bool is_voice_queued(void); /* Are there more voice clips to be spoken? */
 int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */
 int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */
 int talk_number(long n, bool enqueue); /* say a number */
 int talk_value(long n, int unit, bool enqueue); /* say a numeric value */
 int talk_spell(const char* spell, bool enqueue); /* spell a string */
-bool talk_menus_enabled(void); /* returns true if menus should be voiced */
-void talk_disable_menus(void); /* disable voice menus (temporarily, not persisted) */
-void talk_enable_menus(void); /* re-enable voice menus */
-int do_shutup(void); /* kill voice unconditionally */
-int shutup(void); /* Interrupt voice, as when enqueue is false */
+void talk_disable(bool disable); /* temporarily disable (or re-enable) talking (temporarily, not persisted) */
+void talk_force_shutup(void); /* kill voice unconditionally */
+void talk_shutup(void); /* Interrupt voice, as when enqueue is false */
 
 #if CONFIG_RTC
 /* this is in talk.c which isnt compiled for hwcodec simulator */
@@ -94,12 +91,14 @@
 
 /* We don't build talk.c for hwcodec sims so we need to define these as empty */
 #if defined(SIMULATOR) && !(CONFIG_CODEC == SWCODEC)
+#define talk_init(...)
+#define talk_buffer_steal(...)
+#define talk_shutup(...)
 #define talk_force_enqueue_next(...)
 #define talk_idarray(...)
 #define talk_ids(...)
 #define cond_talk_ids(...)
 #define cond_talk_ids_fq(...)
-#define shutup(...)
 #else
 
 /* Enqueue next utterance even if enqueue parameter is false: don't
@@ -116,18 +115,18 @@
 /* This version talks only if talking menus are enabled, and does not
    enqueue the initial id. */
 #define cond_talk_ids(ids...) do { \
-        if (talk_menus_enabled()) \
+        if (global_settings.talk_menu) \
             talk_ids(false, ids); \
     } while(0)
 /* And a version that takes the array parameter... */
 #define cond_talk_idarray(idarray) do { \
-        if (talk_menus_enabled() \
+        if (global_settings.talk_menu \
             talk_idarray(idarray, false); \
     } while(0)
 /* Convenience macro to conditionally speak something and not have
    it interrupted. */
 #define cond_talk_ids_fq(ids...) do { \
-        if (talk_menus_enabled()) { \
+        if (global_settings.talk_menu) { \
             talk_ids(false, ids);                 \
             talk_force_enqueue_next(); \
         } \
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index 840b142..00716b3 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -302,14 +302,6 @@
 }
 
 #if CONFIG_CODEC != SWCODEC
-void talk_init(void)
-{
-}
-
-int talk_buffer_steal(void)
-{
-    return 0;
-}
 
 int talk_id(int id, bool enqueue)
 {
@@ -347,17 +339,9 @@
     return 0;
 }
 
-bool talk_menus_enabled(void)
+void talk_disable(bool disable)
 {
-    return false;
-}
-
-void talk_enable_menus(void)
-{
-}
-
-void talk_disable_menus(void)
-{
+    (void) disable;
 }
 
 const char* const dir_thumbnail_name = "_dirname.talk";