[PATCH]: Festival driver autodetecting available voices



I've been working on getting gnome-speech Festival driver to expose all
available voices instead of two harcoded ones (that is very necessary
for non English users).

Attached is a patch doing this. There is some open issues about I would
like to ask.

After appliying it you should need to change your speaker names, because
they are exposed with its driver name. This is the only solution without
harcoding names, but would break in some way user configuration after an
update. What do you think about this?

About exposing the language, festival provides things like "English" for
lang and "Castillian" for dialect. I guess that it should expose this
language to the gnome-speech clients in the tipical locale way ("es_ES",
"en_US", ...). As other drivers are also harcoding voices and/or
languages shouldn't we add to gnome-speec some kind of general language
matching function and use it in the drivers for exposing voice language?

Thanks.

PS: For getting non-US voices working with festival you would need the
utf-8 --> iso8859 part from patch on bug
http://bugzilla.gnome.org/show_bug.cgi?id=141516
? fest.log
Index: festivalspeaker.c
===================================================================
RCS file: /cvs/gnome/gnome-speech/drivers/festival/festivalspeaker.c,v
retrieving revision 1.4
diff -u -r1.4 festivalspeaker.c
--- festivalspeaker.c	10 Jan 2005 18:15:57 -0000	1.4
+++ festivalspeaker.c	17 Feb 2005 17:07:51 -0000
@@ -196,11 +196,9 @@
 					festival_set_rate);
 
 	/* Set voice */
+
+	speaker->voice = g_strdup_printf ("(voice_%s)\n", info->name);
 		
-	if (!strcmp (info->name, "Kevin"))
-		speaker->voice = g_strdup ("(voice_ked_diphone)\n");
-	else if (!strcmp (info->name, "Kal"))
-		speaker->voice = g_strdup ("(voice_kal_diphone)\n");
 	return speaker;
 }
 
Index: festivalsynthesisdriver.c
===================================================================
RCS file: /cvs/gnome/gnome-speech/drivers/festival/festivalsynthesisdriver.c,v
retrieving revision 1.16
diff -u -r1.16 festivalsynthesisdriver.c
--- festivalsynthesisdriver.c	10 Jan 2005 18:15:57 -0000	1.16
+++ festivalsynthesisdriver.c	17 Feb 2005 17:07:52 -0000
@@ -46,8 +46,10 @@
 static gint 		text_id   = 0;
 static GObjectClass 	*parent_class;
 static gboolean 	festival_server_exists = FALSE;
+static gboolean 	festival_server_got_voices = FALSE;
 static GSList		*driver_list = NULL;
 static GSList		*markers_list = NULL;
+static GSList		*voices_list = NULL;
 
 typedef struct
 {
@@ -286,6 +288,7 @@
 			GIOCondition  condition,
 			gpointer      data)
 {
+	static int voices_waiting_for_description = 0;
 	gchar *ack = NULL;
 	FestivalSynthesisDriver *driver = data;
 
@@ -310,7 +313,58 @@
 #endif
 	    driver->is_querying = FALSE;
         }
-    
+	else if (ack && strncmp (ack, "(VOICES:", 8) == 0)
+	{
+	    char **voices;
+	    int i;
+#ifdef FESTIVAL_DEBUG_CONTROL
+    	    fprintf (stderr, "\nRECEIVE VOICE LIST");
+#endif
+	    voices = g_strsplit (ack, " ", 0);
+	    for (i = 1; voices[i] != NULL; i++)
+	    {
+		char *query_voice_des;
+		char *p;
+		p = strstr (voices[i], ")\n");
+		if (p != NULL)
+		    *p = 0; 
+		query_voice_des = g_strdup_printf ("(list 'VOICEDESC: "
+						   "(nth 0 (voice.description '%s)) "
+						   "(nth 1 (nth 0 (nth 1 (voice.description '%s)))) "
+						   "(nth 1 (nth 2 (nth 1 (voice.description '%s)))) "
+						   "(nth 1 (nth 1 (nth 1 (voice.description '%s)))))\n",
+						   voices[i], voices[i], voices[i], voices[i]);
+		festival_synthesis_driver_say_raw (driver, query_voice_des);
+		voices_waiting_for_description++;
+		g_free (query_voice_des);
+	    }
+	    g_strfreev (voices);
+	}
+	else if (ack && strncmp (ack, "(VOICEDESC:", 11) == 0)
+	{
+	    char **voice;
+	    voice = g_strsplit (ack, " ", 0);
+	    if (voice != NULL && voice[0] != NULL && 
+		voice[1] != NULL && strcmp (voice[1], "nil") && 
+		voice[2] != NULL && strcmp (voice[2], "nil") && 
+		voice[3] != NULL && strcmp (voice[3], "nil") && 
+		voice[4] != NULL && strcmp (voice[4], "nil"))
+	    {
+		GNOME_Speech_VoiceInfo *new_info;
+		new_info = GNOME_Speech_VoiceInfo__alloc ();
+		new_info->name = CORBA_string_dup (voice[1]);
+		new_info->language = CORBA_string_dup (voice[2]);
+		if (strncmp (voice[4], "female", 6) == 0)
+		    new_info->gender = GNOME_Speech_gender_female;
+		else
+		    new_info->gender = GNOME_Speech_gender_male;
+		voices_list = g_slist_append (voices_list, new_info);
+	    }
+	    voices_waiting_for_description--;
+	    if (voices_waiting_for_description == 0) 
+		festival_server_got_voices = TRUE;
+
+	}    
 	g_free (ack);
 
 	return TRUE;
@@ -432,8 +486,9 @@
 	d->channel_sock = g_io_channel_unix_new(d->sock);
         g_io_add_watch (d->channel_sock, G_IO_IN, festival_response_sock, d);
 
-	if (festival_server_exists)
+	if (festival_server_exists) {
     	    festival_synthesis_driver_say_raw (d, "(audio_mode 'async)\n");
+	}
 	
         g_timeout_add (50,festival_querying_queue, d);
 
@@ -562,32 +617,6 @@
 	return CORBA_string_dup (d->version);
 }
 
-
-
-static GSList *
-get_voice_list (void)
-{
-	GSList *l = NULL;
-	GNOME_Speech_VoiceInfo *info;	
-
-	if (festival_server_exists)
-	{
-	    info = GNOME_Speech_VoiceInfo__alloc ();
-	    info->language = CORBA_string_dup("en_US");
-	    info->name = CORBA_string_dup ("Kevin");
-	    info->gender = GNOME_Speech_gender_male;
-	    l = g_slist_prepend (l, info);
-	    info = GNOME_Speech_VoiceInfo__alloc ();
-	    info->language = CORBA_string_dup("en_US");
-	    info->name = CORBA_string_dup ("Kal");
-	    info->gender = GNOME_Speech_gender_male;
-	    l = g_slist_prepend (l, info);
-	    l = g_slist_reverse (l);
-	}
-	return l;
-}
-
-
 static void
 voice_list_free (GSList *l)
 {
@@ -605,33 +634,28 @@
 
 
 static GSList *
-prune_voice_list (GSList *l,
-		  const GNOME_Speech_VoiceInfo *info)
+get_voice_list_with_spec (GSList *l,
+			  const GNOME_Speech_VoiceInfo *info)
 {
-	GSList *cur, *next;
-	GNOME_Speech_VoiceInfo *i;
+	GSList *tmp, *new;
+	GNOME_Speech_VoiceInfo *i, *new_info;
 
-	cur = l;
-	while (cur) {
-		i = (GNOME_Speech_VoiceInfo *) cur->data;
-		next = cur->next;
-		if (strlen(info->name))
-			if (strcmp (i->name, info->name)) {
-				CORBA_free (i);
-				l = g_slist_remove_link (l, cur);
-				cur = next;
-				continue;
-			}
-		if (strlen(info->language))
-			if (strcmp (i->language, info->language)) {
-				CORBA_free (i);
-				l = g_slist_remove_link (l, cur);
-				cur = next;
-				continue;
-			}
-		cur = next;
+	new = NULL;
+	tmp = l;
+	while (tmp) {
+		i = (GNOME_Speech_VoiceInfo *) tmp->data;
+		if ((strlen(info->name) ? strcmp (i->name, info->name) : 1) && 
+		    (strlen(info->language) ? strcmp (i->language, info->language) : 1)) {
+			new_info = GNOME_Speech_VoiceInfo__alloc ();
+            		new_info->language = CORBA_string_dup(info->language);
+            		new_info->name = CORBA_string_dup (info->name);
+            		new_info->gender = info->gender;
+			new = g_slist_prepend (new, new_info);
+		}
+		tmp = tmp->next;
 	}
-	return l;
+	new = g_slist_reverse (new);
+	return new;
 }
 
 
@@ -671,8 +695,7 @@
 	GNOME_Speech_VoiceInfoList *rv;
 	GSList *l;
 
-	l = get_voice_list ();
-	l = prune_voice_list (l, voice_spec);
+	l = get_voice_list_with_spec (voices_list, voice_spec);
 	rv = voice_info_list_from_voice_list (l);
 	voice_list_free (l);
 	return rv;
@@ -685,11 +708,8 @@
 		       CORBA_Environment *ev)
 {
 	GNOME_Speech_VoiceInfoList *rv;
-	GSList *l;
 
-	l = get_voice_list ();
-	rv = voice_info_list_from_voice_list (l);
-	voice_list_free (l);
+	rv = voice_info_list_from_voice_list (voices_list);
 	return rv;
 }
 
@@ -705,8 +725,7 @@
 	GNOME_Speech_VoiceInfo *info;
 	GSList *l;
 	
-	l = get_voice_list ();
-	l = prune_voice_list (l, voice_spec);
+	l = get_voice_list_with_spec (voices_list, voice_spec);
 	
 	if (l)
 		info = l->data;
@@ -714,6 +733,7 @@
 		info = NULL;
 
 	s = festival_speaker_new (G_OBJECT(d), info);
+	/* FIXME: shound't we free l here? */
 	return CORBA_Object_duplicate(bonobo_object_corba_objref (BONOBO_OBJECT(s)), ev);
 }
 
@@ -736,6 +756,10 @@
 		festival_stop (d);
 		return FALSE;
 	}
+
+        festival_synthesis_driver_say_raw (d, "(cons 'VOICES: (voice.list))\n");
+	while (festival_server_got_voices == FALSE)
+	    g_main_context_iteration (NULL, FALSE);
 
 	d->initialized = TRUE;
 	return TRUE;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]