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
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 51b720b..e832165 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -93,9 +93,9 @@
bool result;
struct menu_items items[] = {
- { str(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu},
- { str(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu},
- { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load},
+ { STR(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu},
+ { STR(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu},
+ { STR(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load},
};
m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index b77014a..d0c575b 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1476,36 +1476,36 @@
bool result;
struct menu_items items[] = {
- { "Dump ROM contents", dbg_save_roms },
- { "View I/O ports", dbg_ports },
+ { "Dump ROM contents", -1, dbg_save_roms },
+ { "View I/O ports", -1, dbg_ports },
#ifdef HAVE_LCD_BITMAP
#ifdef HAVE_RTC
- { "View/clr RTC RAM", dbg_rtc },
+ { "View/clr RTC RAM", -1, dbg_rtc },
#endif /* HAVE_RTC */
#endif /* HAVE_LCD_BITMAP */
- { "View OS stacks", dbg_os },
+ { "View OS stacks", -1, dbg_os },
#ifdef HAVE_MAS3507D
- { "View MAS info", dbg_mas_info },
+ { "View MAS info", -1, dbg_mas_info },
#endif
- { "View MAS regs", dbg_mas },
+ { "View MAS regs", -1, dbg_mas },
#ifdef HAVE_MAS3587F
- { "View MAS codec", dbg_mas_codec },
+ { "View MAS codec", -1, dbg_mas_codec },
#endif
#ifdef HAVE_LCD_BITMAP
- { "View battery", view_battery },
+ { "View battery", -1, view_battery },
#endif
- { "View HW info", dbg_hw_info },
- { "View partitions", dbg_partitions },
- { "View disk info", dbg_disk_info },
+ { "View HW info", -1, dbg_hw_info },
+ { "View partitions", -1, dbg_partitions },
+ { "View disk info", -1, dbg_disk_info },
#ifdef HAVE_LCD_BITMAP
- { "View mpeg thread", dbg_mpeg_thread },
+ { "View mpeg thread", -1, dbg_mpeg_thread },
#ifdef PM_DEBUG
- { "pm histogram", peak_meter_histogram},
+ { "pm histogram", -1, peak_meter_histogram},
#endif /* PM_DEBUG */
#endif /* HAVE_LCD_BITMAP */
- { "View runtime", view_runtime },
+ { "View runtime", -1, view_runtime },
#ifdef HAVE_FMRADIO
- { "FM Radio", dbg_fm_radio },
+ { "FM Radio", -1, dbg_fm_radio },
#endif
};
diff --git a/apps/main.c b/apps/main.c
index d6be594..2c2f9ac 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -54,6 +54,7 @@
#include "rolo.h"
#include "screens.h"
#include "power.h"
+#include "talk.h"
char appsversion[]=APPSVERSION;
@@ -208,6 +209,7 @@
global_settings.avc,
global_settings.channel_config );
mpeg_init();
+ talk_init();
/* no auto-rolo on startup any more, but I leave it here for reference */
#if 0
diff --git a/apps/main_menu.c b/apps/main_menu.c
index f42655b..ade6e7b 100644
--- a/apps/main_menu.c
+++ b/apps/main_menu.c
@@ -262,8 +262,8 @@
/* recording menu */
struct menu_items items[] = {
- { str(LANG_RECORDING_MENU), recording_screen },
- { str(LANG_RECORDING_SETTINGS), recording_settings},
+ { STR(LANG_RECORDING_MENU), recording_screen },
+ { STR(LANG_RECORDING_SETTINGS), recording_settings},
};
m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
@@ -281,13 +281,13 @@
/* info menu */
struct menu_items items[] = {
- { str(LANG_MENU_SHOW_ID3_INFO), browse_id3 },
- { str(LANG_INFO_MENU), show_info },
- { str(LANG_VERSION), show_credits },
+ { STR(LANG_MENU_SHOW_ID3_INFO), browse_id3 },
+ { STR(LANG_INFO_MENU), show_info },
+ { STR(LANG_VERSION), show_credits },
#ifndef SIMULATOR
- { str(LANG_DEBUG), debug_menu },
+ { STR(LANG_DEBUG), debug_menu },
#else
- { str(LANG_USB), simulate_usb },
+ { STR(LANG_USB), simulate_usb },
#endif
};
@@ -308,33 +308,41 @@
struct menu_items items[8];
items[i].desc = str(LANG_BOOKMARK_MENU);
+ items[i].voice_id = LANG_BOOKMARK_MENU;
items[i++].function = bookmark_menu;
items[i].desc = str(LANG_SOUND_SETTINGS);
+ items[i].voice_id = LANG_SOUND_SETTINGS;
items[i++].function = sound_menu;
items[i].desc = str(LANG_GENERAL_SETTINGS);
+ items[i].voice_id = LANG_GENERAL_SETTINGS;
items[i++].function = settings_menu;
#ifdef HAVE_FMRADIO
if(radio_hardware_present()) {
items[i].desc = str(LANG_FM_RADIO);
+ items[i].voice_id = LANG_FM_RADIO;
items[i++].function = radio_screen;
}
#endif
#ifdef HAVE_MAS3587F
items[i].desc = str(LANG_RECORDING);
+ items[i].voice_id = LANG_RECORDING;
items[i++].function = rec_menu;
#endif
items[i].desc = str(LANG_PLAYLIST_MENU);
+ items[i].voice_id = LANG_PLAYLIST_MENU;
items[i++].function = playlist_menu;
items[i].desc = str(LANG_PLUGINS);
+ items[i].voice_id = LANG_PLUGINS;
items[i++].function = plugin_browse;
items[i].desc = str(LANG_INFO);
+ items[i].voice_id = LANG_INFO;
items[i++].function = info_menu;
m=menu_init( items, i, NULL );
diff --git a/apps/menu.c b/apps/menu.c
index f187b5d..f944354 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -32,6 +32,7 @@
#include "settings.h"
#include "status.h"
#include "screens.h"
+#include "talk.h"
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
@@ -216,6 +217,13 @@
lcd_update();
}
+ if (do_update)
+ { /* "say" the entry under the cursor */
+ int voice_id = menus[m].items[menus[m].cursor].voice_id;
+ if (voice_id >= 0) /* valid ID given? */
+ talk_id(voice_id, false); /* say it */
+ }
+
}
int menu_init(struct menu_items* mitems, int count, int (*callback)(int, int))
@@ -250,6 +258,7 @@
{
bool exit = false;
int key;
+ int voice_id;
#ifdef HAVE_LCD_BITMAP
int fw, fh;
int menu_lines;
@@ -263,9 +272,16 @@
menu_draw(m);
+ /* say current entry */
+ voice_id = menus[m].items[menus[m].cursor].voice_id;
+ if (voice_id >= 0) /* valid ID given? */
+ talk_id(voice_id, false); /* say it */
+
while (!exit) {
key = button_get_w_tmo(HZ/2);
+
+
/*
* "short-circuit" the default keypresses by running the callback function
*/
@@ -274,6 +290,7 @@
key = menus[m].callback(key, m); /* make sure there's no match in the switch */
switch( key ) {
+
#ifdef HAVE_RECORDER_KEYPAD
case BUTTON_UP:
case BUTTON_UP | BUTTON_REPEAT:
diff --git a/apps/menu.h b/apps/menu.h
index 827de1d..dbe5151 100644
--- a/apps/menu.h
+++ b/apps/menu.h
@@ -23,10 +23,14 @@
#include <stdbool.h>
struct menu_items {
- unsigned char *desc;
+ unsigned char *desc; /* string */
+ int voice_id; /* the associated voice clip, -1 if none */
bool (*function) (void); /* return true if USB was connected */
};
+/* convenience macro to have both string and ID as arguments */
+#define STR(id) str(id), id
+
int menu_init(struct menu_items* items, int count, int (*callback) (int keycode, int menu));
void menu_exit(int menu);
diff --git a/apps/onplay.c b/apps/onplay.c
index e4733fb..9dab34c 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -41,6 +41,7 @@
#include "settings.h"
#include "status.h"
#include "playlist_viewer.h"
+#include "talk.h"
#include "onplay.h"
static char* selected_file = NULL;
@@ -147,6 +148,7 @@
if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)
{
menu[i].desc = str(LANG_VIEW);
+ menu[i].voice_id = LANG_VIEW;
menu[i].function = view_playlist;
i++;
pstart++;
@@ -155,31 +157,37 @@
if (mpeg_status() & MPEG_STATUS_PLAY)
{
menu[i].desc = str(LANG_INSERT);
+ menu[i].voice_id = LANG_INSERT;
args[i].position = PLAYLIST_INSERT;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_INSERT_FIRST);
+ menu[i].voice_id = LANG_INSERT_FIRST;
args[i].position = PLAYLIST_INSERT_FIRST;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_INSERT_LAST);
+ menu[i].voice_id = LANG_INSERT_LAST;
args[i].position = PLAYLIST_INSERT_LAST;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_QUEUE);
+ menu[i].voice_id = LANG_QUEUE;
args[i].position = PLAYLIST_INSERT;
args[i].queue = true;
i++;
menu[i].desc = str(LANG_QUEUE_FIRST);
+ menu[i].voice_id = LANG_QUEUE_FIRST;
args[i].position = PLAYLIST_INSERT_FIRST;
args[i].queue = true;
i++;
menu[i].desc = str(LANG_QUEUE_LAST);
+ menu[i].voice_id = LANG_QUEUE_LAST;
args[i].position = PLAYLIST_INSERT_LAST;
args[i].queue = true;
i++;
@@ -188,6 +196,7 @@
(selected_file_attr & ATTR_DIRECTORY))
{
menu[i].desc = str(LANG_INSERT);
+ menu[i].voice_id = LANG_INSERT;
args[i].position = PLAYLIST_INSERT;
args[i].queue = false;
i++;
@@ -283,6 +292,8 @@
int orig_fd, fd;
char tmpname[MAX_PATH];
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
+
snprintf(tmpname, MAX_PATH, "%s.tmp", fname);
orig_fd = open(fname, O_RDONLY);
@@ -384,6 +395,8 @@
return onplay_result;
}
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
+
lcd_clear_display();
lcd_puts_scroll(0, 0, selected_file);
lcd_update();
@@ -552,17 +565,20 @@
((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U))
{
menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST);
+ menu[i].voice_id = LANG_PLAYINDICES_PLAYLIST;
menu[i].function = playlist_options;
i++;
}
menu[i].desc = str(LANG_RENAME);
+ menu[i].voice_id = LANG_RENAME;
menu[i].function = rename_file;
i++;
if (!(attr & ATTR_DIRECTORY))
{
menu[i].desc = str(LANG_DELETE);
+ menu[i].voice_id = LANG_DELETE;
menu[i].function = delete_file;
i++;
}
@@ -570,12 +586,14 @@
if ((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
{
menu[i].desc = str(LANG_VBRFIX);
+ menu[i].voice_id = LANG_VBRFIX;
menu[i].function = vbr_fix;
i++;
}
}
menu[i].desc = str(LANG_CREATE_DIR);
+ menu[i].voice_id = LANG_CREATE_DIR;
menu[i].function = create_dir;
i++;
diff --git a/apps/playlist.c b/apps/playlist.c
index 572eb26..53a18c6 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -91,6 +91,7 @@
#endif
#include "lang.h"
+#include "talk.h"
#define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control"
#define PLAYLIST_CONTROL_FILE_VERSION 2
@@ -337,6 +338,7 @@
{
/* use mp3 buffer for maximum load speed */
mpeg_stop();
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
buffer = mp3buf;
buflen = (mp3end - mp3buf);
@@ -1192,6 +1194,7 @@
};
/* use mp3 buffer for maximum load speed */
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
buflen = (mp3end - mp3buf);
buffer = mp3buf;
diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c
index 87862ab..6eafe0c 100644
--- a/apps/playlist_menu.c
+++ b/apps/playlist_menu.c
@@ -65,10 +65,10 @@
bool result;
struct menu_items items[] = {
- { str(LANG_CREATE_PLAYLIST), create_playlist },
- { str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
- { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
- { str(LANG_RECURSE_DIRECTORY), recurse_directory },
+ { STR(LANG_CREATE_PLAYLIST), create_playlist },
+ { STR(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
+ { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
+ { STR(LANG_RECURSE_DIRECTORY), recurse_directory },
};
m = menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index 58052af..8b9470c 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -685,12 +685,15 @@
bool current = (tracks[index].index == viewer.current_playing_track);
menu[i].desc = str(LANG_REMOVE);
+ menu[i].voice_id = LANG_REMOVE;
i++;
menu[i].desc = str(LANG_MOVE);
+ menu[i].voice_id = LANG_MOVE;
i++;
menu[i].desc = str(LANG_FILE_OPTIONS);
+ menu[i].voice_id = LANG_FILE_OPTIONS;
i++;
m = menu_init(menu, i, NULL);
@@ -757,10 +760,10 @@
bool result;
struct menu_items items[] = {
- { str(LANG_SHOW_ICONS), show_icons },
- { str(LANG_SHOW_INDICES), show_indices },
- { str(LANG_TRACK_DISPLAY), track_display },
- { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
+ { STR(LANG_SHOW_ICONS), show_icons },
+ { STR(LANG_SHOW_INDICES), show_indices },
+ { STR(LANG_TRACK_DISPLAY), track_display },
+ { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
diff --git a/apps/plugin.c b/apps/plugin.c
index 08c9801..cdb787a 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -38,6 +38,7 @@
#include "mp3_playback.h"
#include "backlight.h"
#include "ata.h"
+#include "talk.h"
#ifdef HAVE_LCD_BITMAP
#include "widgets.h"
@@ -325,6 +326,7 @@
return buf;
#else
mpeg_stop();
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
*buffer_size = mp3end - mp3buf;
return mp3buf;
#endif
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index a9937a3..86e11f9 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -595,6 +595,7 @@
if(presets[i].frequency)
{
menu[num_presets].desc = presets[i].name;
+ menu[num_presets].voice_id = -1;
/* We use the function pointer entry for the preset
entry index */
menu[num_presets++].function = (void *)i;
@@ -669,6 +670,7 @@
if(presets[i].frequency)
{
menu[num_presets].desc = presets[i].name;
+ menu[num_presets].voice_id = -1;
/* We use the function pointer entry for the preset
entry index */
menu[num_presets++].function = (void *)i;
@@ -715,10 +717,10 @@
bool radio_menu(void)
{
struct menu_items radio_menu_items[] = {
- { str(LANG_FM_SAVE_PRESET), radio_add_preset },
- { str(LANG_FM_DELETE_PRESET), radio_delete_preset },
- { str(LANG_SOUND_SETTINGS), sound_menu },
- { str(LANG_RECORDING_SETTINGS), fm_recording_settings }
+ { STR(LANG_FM_SAVE_PRESET), radio_add_preset },
+ { STR(LANG_FM_DELETE_PRESET), radio_delete_preset },
+ { STR(LANG_SOUND_SETTINGS), sound_menu },
+ { STR(LANG_RECORDING_SETTINGS), fm_recording_settings }
};
int m;
bool result;
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 7c060c4..75c78a7 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -368,16 +368,16 @@
bool result;
struct menu_items items[] = {
- { str(LANG_PM_RELEASE) , peak_meter_release },
- { str(LANG_PM_PEAK_HOLD), peak_meter_hold },
- { str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
- { str(LANG_PM_PERFORMANCE), peak_meter_performance },
+ { STR(LANG_PM_RELEASE) , peak_meter_release },
+ { STR(LANG_PM_PEAK_HOLD), peak_meter_hold },
+ { STR(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
+ { STR(LANG_PM_PERFORMANCE), peak_meter_performance },
#ifdef PM_DEBUG
- { "Refresh rate" , peak_meter_fps_menu },
+ { "Refresh rate" , -1 , peak_meter_fps_menu },
#endif
- { str(LANG_PM_SCALE) , peak_meter_scale },
- { str(LANG_PM_MIN) , peak_meter_min },
- { str(LANG_PM_MAX) , peak_meter_max },
+ { STR(LANG_PM_SCALE) , peak_meter_scale },
+ { STR(LANG_PM_MIN) , peak_meter_min },
+ { STR(LANG_PM_MAX) , peak_meter_max },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -791,8 +791,8 @@
bool result;
struct menu_items items[] = {
- { str(LANG_FFRW_STEP), ff_rewind_min_step },
- { str(LANG_FFRW_ACCEL), ff_rewind_accel },
+ { STR(LANG_FFRW_STEP), ff_rewind_min_step },
+ { STR(LANG_FFRW_ACCEL), ff_rewind_accel },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -808,13 +808,13 @@
bool result;
struct menu_items items[] = {
- { str(LANG_SHUFFLE), shuffle },
- { str(LANG_REPEAT), repeat_mode },
- { str(LANG_PLAY_SELECTED), play_selected },
- { str(LANG_RESUME), resume },
- { str(LANG_WIND_MENU), ff_rewind_settings_menu },
- { str(LANG_MP3BUFFER_MARGIN), buffer_margin },
- { str(LANG_FADE_ON_STOP), set_fade_on_stop },
+ { STR(LANG_SHUFFLE), shuffle },
+ { STR(LANG_REPEAT), repeat_mode },
+ { STR(LANG_PLAY_SELECTED), play_selected },
+ { STR(LANG_RESUME), resume },
+ { STR(LANG_WIND_MENU), ff_rewind_settings_menu },
+ { STR(LANG_MP3BUFFER_MARGIN), buffer_margin },
+ { STR(LANG_FADE_ON_STOP), set_fade_on_stop },
};
bool old_shuffle = global_settings.playlist_shuffle;
@@ -843,9 +843,9 @@
bool result;
struct menu_items items[] = {
- { str(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark},
- { str(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark},
- { str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB},
+ { STR(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark},
+ { STR(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark},
+ { STR(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB},
};
m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
@@ -910,10 +910,10 @@
bool result;
struct menu_items items[] = {
- { str(LANG_CASE_MENU), sort_case },
- { str(LANG_FILTER), dir_filter },
- { str(LANG_FOLLOW), browse_current },
- { str(LANG_SHOW_ICONS), show_icons },
+ { STR(LANG_CASE_MENU), sort_case },
+ { STR(LANG_FILTER), dir_filter },
+ { STR(LANG_FOLLOW), browse_current },
+ { STR(LANG_SHOW_ICONS), show_icons },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -929,15 +929,15 @@
bool result;
struct menu_items items[] = {
- { str(LANG_SCROLL_SPEED), scroll_speed },
- { str(LANG_SCROLL_DELAY), scroll_delay },
+ { STR(LANG_SCROLL_SPEED), scroll_speed },
+ { STR(LANG_SCROLL_DELAY), scroll_delay },
#ifdef HAVE_LCD_BITMAP
- { str(LANG_SCROLL_STEP), scroll_step },
+ { STR(LANG_SCROLL_STEP), scroll_step },
#endif
- { str(LANG_BIDIR_SCROLL), bidir_limit },
+ { STR(LANG_BIDIR_SCROLL), bidir_limit },
#ifdef HAVE_LCD_CHARCELLS
- { str(LANG_JUMP_SCROLL), jump_scroll },
- { str(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay },
+ { STR(LANG_JUMP_SCROLL), jump_scroll },
+ { STR(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay },
#endif
};
@@ -953,14 +953,14 @@
bool result;
struct menu_items items[] = {
- { str(LANG_BACKLIGHT), backlight_timer },
- { str(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging },
- { str(LANG_CAPTION_BACKLIGHT), caption_backlight },
- { str(LANG_CONTRAST), contrast },
+ { STR(LANG_BACKLIGHT), backlight_timer },
+ { STR(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging },
+ { STR(LANG_CAPTION_BACKLIGHT), caption_backlight },
+ { STR(LANG_CONTRAST), contrast },
#ifdef HAVE_LCD_BITMAP
- { str(LANG_INVERT), invert },
- { str(LANG_FLIP_DISPLAY), flip_display },
- { str(LANG_INVERT_CURSOR), invert_cursor },
+ { STR(LANG_INVERT), invert },
+ { STR(LANG_FLIP_DISPLAY), flip_display },
+ { STR(LANG_INVERT_CURSOR), invert_cursor },
#endif
};
@@ -977,10 +977,10 @@
bool result;
struct menu_items items[] = {
- { str(LANG_SCROLL_BAR), scroll_bar },
- { str(LANG_STATUS_BAR), status_bar },
- { str(LANG_VOLUME_DISPLAY), volume_type },
- { str(LANG_BATTERY_DISPLAY), battery_type },
+ { STR(LANG_SCROLL_BAR), scroll_bar },
+ { STR(LANG_STATUS_BAR), status_bar },
+ { STR(LANG_VOLUME_DISPLAY), volume_type },
+ { STR(LANG_BATTERY_DISPLAY), battery_type },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -998,14 +998,14 @@
struct menu_items items[] = {
#ifdef HAVE_LCD_BITMAP
- { str(LANG_CUSTOM_FONT), font_browse },
+ { STR(LANG_CUSTOM_FONT), font_browse },
#endif
- { str(LANG_WHILE_PLAYING), custom_wps_browse },
- { str(LANG_LCD_MENU), lcd_settings_menu },
- { str(LANG_SCROLL_MENU), scroll_settings_menu },
+ { STR(LANG_WHILE_PLAYING), custom_wps_browse },
+ { STR(LANG_LCD_MENU), lcd_settings_menu },
+ { STR(LANG_SCROLL_MENU), scroll_settings_menu },
#ifdef HAVE_LCD_BITMAP
- { str(LANG_BARS_MENU), bars_settings_menu },
- { str(LANG_PM_MENU), peak_meter_menu },
+ { STR(LANG_BARS_MENU), bars_settings_menu },
+ { STR(LANG_PM_MENU), peak_meter_menu },
#endif
};
@@ -1028,11 +1028,11 @@
struct menu_items items[] = {
#ifdef HAVE_CHARGE_CTRL
- { str(LANG_DISCHARGE), deep_discharge },
- { str(LANG_TRICKLE_CHARGE), trickle_charge },
+ { STR(LANG_DISCHARGE), deep_discharge },
+ { STR(LANG_TRICKLE_CHARGE), trickle_charge },
#endif
#ifndef SIMULATOR
- { str(LANG_BATTERY_CAPACITY), battery_capacity },
+ { STR(LANG_BATTERY_CAPACITY), battery_capacity },
#endif
};
@@ -1048,9 +1048,9 @@
bool result;
struct menu_items items[] = {
- { str(LANG_SPINDOWN), spindown },
+ { STR(LANG_SPINDOWN), spindown },
#ifdef HAVE_ATA_POWER_OFF
- { str(LANG_POWEROFF), poweroff },
+ { STR(LANG_POWEROFF), poweroff },
#endif
};
@@ -1067,8 +1067,8 @@
bool result;
struct menu_items items[] = {
- { str(LANG_TIME), timedate_set },
- { str(LANG_TIMEFORMAT), timeformat_set },
+ { STR(LANG_TIME), timedate_set },
+ { STR(LANG_TIMEFORMAT), timeformat_set },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1084,10 +1084,10 @@
bool result;
struct menu_items items[] = {
- { str(LANG_CUSTOM_CFG), custom_cfg_browse },
- { str(LANG_FIRMWARE), firmware_browse },
- { str(LANG_RESET), reset_settings },
- { str(LANG_SAVE_SETTINGS), settings_save_config },
+ { STR(LANG_CUSTOM_CFG), custom_cfg_browse },
+ { STR(LANG_FIRMWARE), firmware_browse },
+ { STR(LANG_RESET), reset_settings },
+ { STR(LANG_SAVE_SETTINGS), settings_save_config },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1102,8 +1102,8 @@
bool result;
struct menu_items items[] = {
- { str(LANG_MAX_FILES_IN_DIR), max_files_in_dir },
- { str(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist },
+ { STR(LANG_MAX_FILES_IN_DIR), max_files_in_dir },
+ { STR(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1119,22 +1119,22 @@
bool result;
struct menu_items items[] = {
- { str(LANG_BATTERY_MENU), battery_settings_menu },
- { str(LANG_DISK_MENU), disk_settings_menu },
+ { STR(LANG_BATTERY_MENU), battery_settings_menu },
+ { STR(LANG_DISK_MENU), disk_settings_menu },
#ifdef HAVE_RTC
- { str(LANG_TIME_MENU), time_settings_menu },
+ { STR(LANG_TIME_MENU), time_settings_menu },
#endif
- { str(LANG_POWEROFF_IDLE), poweroff_idle_timer },
- { str(LANG_SLEEP_TIMER), sleeptimer_screen },
+ { STR(LANG_POWEROFF_IDLE), poweroff_idle_timer },
+ { STR(LANG_SLEEP_TIMER), sleeptimer_screen },
#ifdef HAVE_ALARM_MOD
- { str(LANG_ALARM_MOD_ALARM_MENU), alarm_screen },
+ { STR(LANG_ALARM_MOD_ALARM_MENU), alarm_screen },
#endif
- { str(LANG_LIMITS_MENU), limits_settings_menu },
+ { STR(LANG_LIMITS_MENU), limits_settings_menu },
#ifdef HAVE_MAS3507D
- { str(LANG_LINE_IN), line_in },
+ { STR(LANG_LINE_IN), line_in },
#endif
- { str(LANG_CAR_ADAPTER_MODE), car_adapter_mode },
- { str(LANG_MANAGE_MENU), manage_settings_menu },
+ { STR(LANG_CAR_ADAPTER_MODE), car_adapter_mode },
+ { STR(LANG_MANAGE_MENU), manage_settings_menu },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1149,12 +1149,12 @@
bool result;
struct menu_items items[] = {
- { str(LANG_PLAYBACK), playback_settings_menu },
- { str(LANG_FILE), fileview_settings_menu },
- { str(LANG_DISPLAY), display_settings_menu },
- { str(LANG_SYSTEM), system_settings_menu },
- { str(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu },
- { str(LANG_LANGUAGE), language_browse },
+ { STR(LANG_PLAYBACK), playback_settings_menu },
+ { STR(LANG_FILE), fileview_settings_menu },
+ { STR(LANG_DISPLAY), display_settings_menu },
+ { STR(LANG_SYSTEM), system_settings_menu },
+ { STR(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu },
+ { STR(LANG_LANGUAGE), language_browse },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 256da0b..e0415cd 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -295,15 +295,15 @@
int m;
bool result;
struct menu_items items[] = {
- { str(LANG_VOLUME), volume },
- { str(LANG_BASS), bass },
- { str(LANG_TREBLE), treble },
- { str(LANG_BALANCE), balance },
- { str(LANG_CHANNEL_MENU), chanconf },
+ { STR(LANG_VOLUME), volume },
+ { STR(LANG_BASS), bass },
+ { STR(LANG_TREBLE), treble },
+ { STR(LANG_BALANCE), balance },
+ { STR(LANG_CHANNEL_MENU), chanconf },
#ifdef HAVE_MAS3587F
- { str(LANG_LOUDNESS), loudness },
- { str(LANG_BBOOST), bass_boost },
- { str(LANG_AUTOVOL), avc }
+ { STR(LANG_LOUDNESS), loudness },
+ { STR(LANG_BBOOST), bass_boost },
+ { STR(LANG_AUTOVOL), avc }
#endif
};
@@ -323,22 +323,30 @@
bool result;
menu[i].desc = str(LANG_RECORDING_QUALITY);
+ menu[i].voice_id = LANG_RECORDING_QUALITY;
menu[i++].function = recquality;
menu[i].desc = str(LANG_RECORDING_FREQUENCY);
+ menu[i].voice_id = LANG_RECORDING_FREQUENCY;
menu[i++].function = recfrequency;
if(!no_source) {
menu[i].desc = str(LANG_RECORDING_SOURCE);
+ menu[i].voice_id = LANG_RECORDING_SOURCE;
menu[i++].function = recsource;
}
menu[i].desc = str(LANG_RECORDING_CHANNELS);
+ menu[i].voice_id = LANG_RECORDING_CHANNELS;
menu[i++].function = recchannels;
menu[i].desc = str(LANG_RECORDING_EDITABLE);
+ menu[i].voice_id = LANG_RECORDING_EDITABLE;
menu[i++].function = receditable;
menu[i].desc = str(LANG_RECORD_TIMESPLIT);
+ menu[i].voice_id = LANG_RECORD_TIMESPLIT;
menu[i++].function = rectimesplit;
menu[i].desc = str(LANG_RECORD_PRERECORD_TIME);
+ menu[i].voice_id = LANG_RECORD_PRERECORD_TIME;
menu[i++].function = recprerecord;
menu[i].desc = str(LANG_RECORD_DIRECTORY);
+ menu[i].voice_id = LANG_RECORD_DIRECTORY;
menu[i++].function = recdirectory;
m=menu_init( menu, i, NULL );
diff --git a/firmware/export/talk.h b/firmware/export/talk.h
new file mode 100644
index 0000000..b2af46f
--- /dev/null
+++ b/firmware/export/talk.h
@@ -0,0 +1,34 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2004 Jörg Hohensohn
+ *
+ * This module collects the Talkbox and voice UI functions.
+ * (Talkbox reads directory names from mp3 clips called thumbnails,
+ * the voice UI lets menus and screens "talk" from a voicefont in memory.
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __TALK_H__
+#define __TALK_H__
+
+#include <stdbool.h>
+
+void talk_init(void);
+int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
+int talk_id(int id, bool block); /* play a voice ID from voicefont */
+int talk_file(char* filename, bool block); /* play a thumbnail from file */
+
+#endif /* __TALK_H__ */
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index ff545f0..0f676f1 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2134,6 +2134,7 @@
recording_filename[MAX_PATH - 1] = 0;
disable_xing_header = false;
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
}
@@ -2148,6 +2149,7 @@
prerecord_timeout = current_tick + HZ;
memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
reset_mp3_buffer();
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
is_prerecording = true;
@@ -2404,6 +2406,7 @@
#else
is_playing = true;
+ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
#endif /* #ifdef SIMULATOR */
diff --git a/firmware/talk.c b/firmware/talk.c
new file mode 100644
index 0000000..d02a4ef
--- /dev/null
+++ b/firmware/talk.c
@@ -0,0 +1,209 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2004 Jörg Hohensohn
+ *
+ * This module collects the Talkbox and voice UI functions.
+ * (Talkbox reads directory names from mp3 clips called thumbnails,
+ * the voice UI lets menus and screens "talk" from a voicefont in memory.
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stddef.h>
+#include "file.h"
+#include "buffer.h"
+#include "kernel.h"
+#include "mp3_playback.h"
+#include "mpeg.h"
+#include "talk.h"
+extern void bitswap(unsigned char *data, int length); /* no header for this */
+
+/***************** Constants *****************/
+
+#define VOICEFONT_FILENAME "/.rockbox/voicefont"
+
+
+/***************** Data types *****************/
+
+struct clip_entry /* one entry of the index table */
+{
+ int offset; /* offset from start of voicefont file */
+ int size; /* size of the clip */
+};
+
+struct voicefont /* file format of our "voicefont" */
+{
+ int version; /* version of the voicefont */
+ int headersize; /* size of the header, =offset to index */
+ int id_max; /* number of clips contained */
+ struct clip_entry index[]; /* followed by the index table */
+ /* and finally the bitswapped mp3 clips, not visible here */
+};
+
+
+/***************** Globals *****************/
+
+static unsigned char* p_thumbnail; /* buffer for thumbnail */
+static long size_for_thumbnail; /* leftover buffer size for it */
+static struct voicefont* p_voicefont; /* loaded voicefont */
+static bool has_voicefont; /* a voicefont file is present */
+static bool is_playing; /* we're currently playing */
+
+
+
+/***************** Private implementation *****************/
+
+static int load_voicefont(void)
+{
+ int fd;
+ int size;
+
+ p_voicefont = NULL; /* indicate no voicefont if we fail below */
+
+ fd = open(VOICEFONT_FILENAME, O_RDONLY);
+ if (fd < 0) /* failed to open */
+ {
+ p_voicefont = NULL; /* indicate no voicefont */
+ has_voicefont = false; /* don't try again */
+ return 0;
+ }
+
+ size = read(fd, mp3buf, mp3end - mp3buf);
+ if (size > 1000
+ && ((struct voicefont*)mp3buf)->headersize
+ == offsetof(struct voicefont, index))
+ {
+ p_voicefont = (struct voicefont*)mp3buf;
+
+ /* thumbnail buffer is the remaining space behind */
+ p_thumbnail = mp3buf + size;
+ p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */
+ size_for_thumbnail = mp3end - p_thumbnail;
+
+ /* max. DMA size, fixme */
+ if (size_for_thumbnail > 0xFFFF)
+ size_for_thumbnail = 0xFFFF;
+ }
+ else
+ {
+ has_voicefont = false; /* don't try again */
+ }
+ close(fd);
+
+ return size;
+}
+
+
+/* called in ISR context if mp3 data got consumed */
+void mp3_callback(unsigned char** start, int* size)
+{
+ (void)start; /* unused parameter, avoid warning */
+ *size = 0; /* end of data */
+ is_playing = false;
+ mp3_play_stop(); /* fixme: should be done by caller */
+}
+
+/***************** Public implementation *****************/
+
+void talk_init(void)
+{
+ has_voicefont = true; /* unless we fail later, assume we have one */
+ talk_buffer_steal();
+}
+
+
+/* somebody else claims the mp3 buffer, e.g. for regular play/record */
+int talk_buffer_steal(void)
+{
+ p_voicefont = NULL; /* indicate no voicefont (trashed) */
+ p_thumbnail = mp3buf; /* whole space for thumbnail */
+ size_for_thumbnail = mp3end - mp3buf;
+ /* max. DMA size, fixme */
+ if (size_for_thumbnail > 0xFFFF)
+ size_for_thumbnail = 0xFFFF;
+ return 0;
+}
+
+
+/* play a voice ID from voicefont */
+int talk_id(int id, bool block)
+{
+ int clipsize;
+
+ if (mpeg_status()) /* busy, buffer in use */
+ return -1;
+
+ if (p_voicefont == NULL && has_voicefont)
+ load_voicefont(); /* reload needed */
+
+ if (p_voicefont == NULL) /* still no voices? */
+ return -1;
+
+ if (id >= p_voicefont->id_max)
+ return -1;
+
+ clipsize = p_voicefont->index[id].size;
+ if (clipsize == 0) /* clip not included in voicefont */
+ return -1;
+
+ is_playing = true;
+ mp3_play_data(mp3buf + p_voicefont->index[id].offset,
+ clipsize, mp3_callback);
+ mp3_play_pause(true); /* kickoff audio */
+
+ while(block && is_playing)
+ sleep(1);
+
+ return 0;
+}
+
+
+/* play a thumbnail from file */
+int talk_file(char* filename, bool block)
+{
+ int fd;
+ int size;
+
+ if (mpeg_status()) /* busy, buffer in use */
+ return -1;
+
+ if (p_thumbnail == NULL || size_for_thumbnail <= 0)
+ return -1;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) /* failed to open */
+ {
+ return 0;
+ }
+
+ size = read(fd, p_thumbnail, size_for_thumbnail);
+ close(fd);
+
+ /* ToDo: find audio, skip ID headers and trailers */
+
+ if (size)
+ {
+ bitswap(p_thumbnail, size);
+ is_playing = true;
+ mp3_play_data(p_thumbnail, size, mp3_callback);
+ mp3_play_pause(true); /* kickoff audio */
+
+ while(block && is_playing)
+ sleep(1);
+ }
+
+ return size;
+}
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index 23a6728..4098c0b 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -225,3 +225,22 @@
{
(void)yesno;
}
+
+int talk_buffer_steal(void)
+{
+ return 0;
+}
+
+int talk_id(int id, bool block)
+{
+ (void)id;
+ (void)block;
+ return 0;
+}
+
+int talk_file(char* filename, bool block)
+{
+ (void)filename;
+ (void)block;
+ return 0;
+}