mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00
98_Text2Speech: Google fixed, svox-pico added
git-svn-id: https://svn.fhem.de/fhem/trunk@9758 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
f162920f0d
commit
2a201efbcc
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- bugfix 98_Text2Speech: Google fixed, svox-pico added
|
||||||
- bugfix 00_SIGNALduino: Updated Firmware (3.8.1-HF1)
|
- bugfix 00_SIGNALduino: Updated Firmware (3.8.1-HF1)
|
||||||
fixed send raw
|
fixed send raw
|
||||||
- updated: 74_AMAD: New Mijor Release 0.8.1
|
- updated: 74_AMAD: New Mijor Release 0.8.1
|
||||||
|
@ -73,7 +73,8 @@ my %ttsQuality = ("Google" => "",
|
|||||||
"VoiceRSS" => "f="
|
"VoiceRSS" => "f="
|
||||||
);
|
);
|
||||||
my %ttsMaxChar = ("Google" => 100,
|
my %ttsMaxChar = ("Google" => 100,
|
||||||
"VoiceRSS" => 300
|
"VoiceRSS" => 300,
|
||||||
|
"SVOX-pico" => 1000
|
||||||
);
|
);
|
||||||
my %language = ("Google" => {"Deutsch" => "de",
|
my %language = ("Google" => {"Deutsch" => "de",
|
||||||
"English-US" => "en-us",
|
"English-US" => "en-us",
|
||||||
@ -94,6 +95,16 @@ my %language = ("Google" => {"Deutsch" => "de",
|
|||||||
"Spain" => "es-es",
|
"Spain" => "es-es",
|
||||||
"Italian" => "it-it",
|
"Italian" => "it-it",
|
||||||
"Chinese" => "zh-cn"
|
"Chinese" => "zh-cn"
|
||||||
|
},
|
||||||
|
"SVOX-pico" => {"Deutsch" => "de-DE",
|
||||||
|
"English-US" => "en-US",
|
||||||
|
"Schwedisch" => "en-US", # gibts nicht
|
||||||
|
"Indian-Hindi" => "en-US", # gibts nicht
|
||||||
|
"Arabic" => "en-US", # gibts nicht
|
||||||
|
"France" => "fr-FR",
|
||||||
|
"Spain" => "es-ES",
|
||||||
|
"Italian" => "it-IT",
|
||||||
|
"Chinese" => "en-US" # gibts nicht
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -109,7 +120,7 @@ sub Text2Speech_Initialize($)
|
|||||||
$hash->{AttrFn} = "Text2Speech_Attr";
|
$hash->{AttrFn} = "Text2Speech_Attr";
|
||||||
$hash->{AttrList} = "disable:0,1".
|
$hash->{AttrList} = "disable:0,1".
|
||||||
" TTS_Delemiter".
|
" TTS_Delemiter".
|
||||||
" TTS_Ressource:ESpeak,". join(",", sort keys %ttsHost).
|
" TTS_Ressource:ESpeak,SVOX-pico,". join(",", sort keys %ttsHost).
|
||||||
" TTS_APIKey".
|
" TTS_APIKey".
|
||||||
" TTS_User".
|
" TTS_User".
|
||||||
" TTS_Quality:".
|
" TTS_Quality:".
|
||||||
@ -412,6 +423,7 @@ sub Text2Speech_Set($@)
|
|||||||
return undef if(AttrVal($hash->{NAME}, "disable", "0") eq "1");
|
return undef if(AttrVal($hash->{NAME}, "disable", "0") eq "1");
|
||||||
|
|
||||||
if($cmd eq "tts") {
|
if($cmd eq "tts") {
|
||||||
|
readingsSingleUpdate($hash, "playing", "1", 1);
|
||||||
if($hash->{MODE} eq "DIRECT") {
|
if($hash->{MODE} eq "DIRECT") {
|
||||||
Text2Speech_PrepareSpeech($hash, join(" ", @a));
|
Text2Speech_PrepareSpeech($hash, join(" ", @a));
|
||||||
$hash->{helper}{RUNNING_PID} = BlockingCall("Text2Speech_DoIt", $hash, "Text2Speech_Done", $TTS_TimeOut, "Text2Speech_AbortFn", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
|
$hash->{helper}{RUNNING_PID} = BlockingCall("Text2Speech_DoIt", $hash, "Text2Speech_Done", $TTS_TimeOut, "Text2Speech_AbortFn", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
|
||||||
@ -470,73 +482,68 @@ sub Text2Speech_PrepareSpeech($$) {
|
|||||||
$TTS_AddDelemiter = "";
|
$TTS_AddDelemiter = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if($TTS_Ressource ne "ESpeak") {
|
my @text;
|
||||||
my @text;
|
|
||||||
|
|
||||||
# ersetze Sonderzeichen die Google nicht auflösen kann
|
# ersetze Sonderzeichen die Google nicht auflösen kann
|
||||||
if($TTS_Ressource eq "Google") {
|
if($TTS_Ressource eq "Google") {
|
||||||
$t =~ s/ä/ae/g;
|
$t =~ s/ä/ae/g;
|
||||||
$t =~ s/ö/oe/g;
|
$t =~ s/ö/oe/g;
|
||||||
$t =~ s/ü/ue/g;
|
$t =~ s/ü/ue/g;
|
||||||
$t =~ s/Ä/Ae/g;
|
$t =~ s/Ä/Ae/g;
|
||||||
$t =~ s/Ö/Oe/g;
|
$t =~ s/Ö/Oe/g;
|
||||||
$t =~ s/Ü/Ue/g;
|
$t =~ s/Ü/Ue/g;
|
||||||
$t =~ s/ß/ss/g;
|
$t =~ s/ß/ss/g;
|
||||||
}
|
|
||||||
|
|
||||||
@text = $hash->{helper}{Text2Speech} if($hash->{helper}{Text2Speech}[0]); #vorhandene Queue, neuen Sprachbaustein hinten anfuegen
|
|
||||||
push(@text, $t);
|
|
||||||
|
|
||||||
# hole alle Filetemplates
|
|
||||||
my @FileTpl = split(" ", $TTS_FileTpl);
|
|
||||||
my @FileTplPc;
|
|
||||||
|
|
||||||
# bei Angabe direkter MP3-Files wird hier ein temporäres Template vergeben
|
|
||||||
for(my $i=0; $i<(@text); $i++) {
|
|
||||||
@FileTplPc = ($text[$i] =~ /:(\w+.+[mp3|ogg|wav]):/g);
|
|
||||||
for(my $j=0; $j<(@FileTplPc); $j++) {
|
|
||||||
my $time = time();
|
|
||||||
$time =~ s/\.//g;
|
|
||||||
my $tpl = "FileTpl_".$time."_#".$i; #eindeutige Templatedefinition schaffen
|
|
||||||
Log3 $hash, 4, "$me: Angabe einer direkten MP3-Datei gefunden: $FileTplPc[$i] => $tpl";
|
|
||||||
push(@FileTpl, $tpl.":".$FileTplPc[$j]); #zb: FileTpl_123645875_#0:/ring.mp3
|
|
||||||
$text[$i] =~ s/$FileTplPc[$j]/$tpl/g; # Ersetze die DateiDefinition gegen ein Template
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#iteriere durch die Sprachbausteine und splitte den Text bei den Filetemplates auf
|
|
||||||
for(my $i=0; $i<(@text); $i++) {
|
|
||||||
my $cutter = '#!#'; #eindeutigen Cutter als Delemiter bei den Filetemplates vergeben
|
|
||||||
@FileTplPc = ($text[$i] =~ /:([^:]+):/g);
|
|
||||||
for(my $j=0; $j<(@FileTplPc); $j++) {
|
|
||||||
$text[$i] =~ s/:$FileTplPc[$j]:/$cutter$FileTplPc[$j]$cutter/g;
|
|
||||||
}
|
|
||||||
@text = Text2Speech_SplitString(\@text, 0, $cutter, 1, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, $TTS_Delemiter, $TTS_ForceSplit, $TTS_AddDelemiter);
|
|
||||||
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, "(?<=[\\.!?])\\s*", 0, "");
|
|
||||||
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, ",", 0, "al");
|
|
||||||
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, ";", 0, "al");
|
|
||||||
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, "und", 0, "af");
|
|
||||||
|
|
||||||
Log3 $hash, 4, "$me: Auflistung der Textbausteine nach Aufbereitung:";
|
|
||||||
for(my $i=0; $i<(@text); $i++) {
|
|
||||||
# entferne führende und abschließende Leerzeichen aus jedem Textbaustein
|
|
||||||
$text[$i] =~ s/^\s+|\s+$//g;
|
|
||||||
for(my $j=0; $j<(@FileTpl); $j++) {
|
|
||||||
# ersetze die FileTemplates mit den echten MP3-Files
|
|
||||||
@FileTplPc = split(/:/, $FileTpl[$j]);
|
|
||||||
$text[$i] = $TTS_FileTemplateDir ."/". $FileTplPc[1] if($text[$i] eq $FileTplPc[0]);
|
|
||||||
}
|
|
||||||
Log3 $hash, 4, "$me: $i => ".$text[$i];
|
|
||||||
}
|
|
||||||
|
|
||||||
@{$hash->{helper}{Text2Speech}} = @text;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
push(@{$hash->{helper}{Text2Speech}}, $t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@text = $hash->{helper}{Text2Speech} if($hash->{helper}{Text2Speech}[0]); #vorhandene Queue, neuen Sprachbaustein hinten anfuegen
|
||||||
|
push(@text, $t);
|
||||||
|
|
||||||
|
# hole alle Filetemplates
|
||||||
|
my @FileTpl = split(" ", $TTS_FileTpl);
|
||||||
|
my @FileTplPc;
|
||||||
|
|
||||||
|
# bei Angabe direkter MP3-Files wird hier ein temporäres Template vergeben
|
||||||
|
for(my $i=0; $i<(@text); $i++) {
|
||||||
|
@FileTplPc = ($text[$i] =~ /:(\w+.+[mp3|ogg|wav]):/g);
|
||||||
|
for(my $j=0; $j<(@FileTplPc); $j++) {
|
||||||
|
my $time = time();
|
||||||
|
$time =~ s/\.//g;
|
||||||
|
my $tpl = "FileTpl_".$time."_#".$i; #eindeutige Templatedefinition schaffen
|
||||||
|
Log3 $hash, 4, "$me: Angabe einer direkten MP3-Datei gefunden: $FileTplPc[$i] => $tpl";
|
||||||
|
push(@FileTpl, $tpl.":".$FileTplPc[$j]); #zb: FileTpl_123645875_#0:/ring.mp3
|
||||||
|
$text[$i] =~ s/$FileTplPc[$j]/$tpl/g; # Ersetze die DateiDefinition gegen ein Template
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#iteriere durch die Sprachbausteine und splitte den Text bei den Filetemplates auf
|
||||||
|
for(my $i=0; $i<(@text); $i++) {
|
||||||
|
my $cutter = '#!#'; #eindeutigen Cutter als Delemiter bei den Filetemplates vergeben
|
||||||
|
@FileTplPc = ($text[$i] =~ /:([^:]+):/g);
|
||||||
|
for(my $j=0; $j<(@FileTplPc); $j++) {
|
||||||
|
$text[$i] =~ s/:$FileTplPc[$j]:/$cutter$FileTplPc[$j]$cutter/g;
|
||||||
|
}
|
||||||
|
@text = Text2Speech_SplitString(\@text, 0, $cutter, 1, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, $TTS_Delemiter, $TTS_ForceSplit, $TTS_AddDelemiter);
|
||||||
|
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, "(?<=[\\.!?])\\s*", 0, "");
|
||||||
|
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, ",", 0, "al");
|
||||||
|
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, ";", 0, "al");
|
||||||
|
@text = Text2Speech_SplitString(\@text, $ttsMaxChar{$TTS_Ressource}, "und", 0, "af");
|
||||||
|
|
||||||
|
Log3 $hash, 4, "$me: Auflistung der Textbausteine nach Aufbereitung:";
|
||||||
|
for(my $i=0; $i<(@text); $i++) {
|
||||||
|
# entferne führende und abschließende Leerzeichen aus jedem Textbaustein
|
||||||
|
$text[$i] =~ s/^\s+|\s+$//g;
|
||||||
|
for(my $j=0; $j<(@FileTpl); $j++) {
|
||||||
|
# ersetze die FileTemplates mit den echten MP3-Files
|
||||||
|
@FileTplPc = split(/:/, $FileTpl[$j]);
|
||||||
|
$text[$i] = $TTS_FileTemplateDir ."/". $FileTplPc[1] if($text[$i] eq $FileTplPc[0]);
|
||||||
|
}
|
||||||
|
Log3 $hash, 4, "$me: $i => ".$text[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
@{$hash->{helper}{Text2Speech}} = @text;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
@ -650,7 +657,7 @@ sub Text2Speech_CalcMP3Duration($$) {
|
|||||||
# param2: string: Dateiname
|
# param2: string: Dateiname
|
||||||
# param2: string: Text
|
# param2: string: Text
|
||||||
#
|
#
|
||||||
# Holt den Text aus dem Google Translator als MP3Datei
|
# Holt den Text mithilfe der entsprechenden TTS_Ressource
|
||||||
#####################################
|
#####################################
|
||||||
sub Text2Speech_Download($$$) {
|
sub Text2Speech_Download($$$) {
|
||||||
my ($hash, $file, $text) = @_;
|
my ($hash, $file, $text) = @_;
|
||||||
@ -661,50 +668,74 @@ sub Text2Speech_Download($$$) {
|
|||||||
my $TTS_Language = AttrVal($hash->{NAME}, "TTS_Language", "Deutsch");
|
my $TTS_Language = AttrVal($hash->{NAME}, "TTS_Language", "Deutsch");
|
||||||
my $TTS_Quality = AttrVal($hash->{NAME}, "TTS_Quality", "");
|
my $TTS_Quality = AttrVal($hash->{NAME}, "TTS_Quality", "");
|
||||||
my $TTS_Speed = AttrVal($hash->{NAME}, "TTS_Speed", "");
|
my $TTS_Speed = AttrVal($hash->{NAME}, "TTS_Speed", "");
|
||||||
|
my $cmd;
|
||||||
|
|
||||||
|
if($TTS_Ressource =~ m/(Google|VoiceRSS)/) {
|
||||||
|
my $HttpResponse;
|
||||||
|
my $HttpResponseErr;
|
||||||
|
my $fh;
|
||||||
|
|
||||||
my $HttpResponse;
|
my $url = "http://" . $ttsHost{$TTS_Ressource} . $ttsPath{$TTS_Ressource};
|
||||||
my $HttpResponseErr;
|
$url .= $ttsLang{$TTS_Ressource};
|
||||||
my $fh;
|
$url .= $language{$TTS_Ressource}{$TTS_Language};
|
||||||
|
$url .= "&" . $ttsAddon{$TTS_Ressource} if(length($ttsAddon{$TTS_Ressource})>0);
|
||||||
|
$url .= "&" . $ttsUser{$TTS_Ressource} . $TTS_User if(length($ttsUser{$TTS_Ressource})>0);
|
||||||
|
$url .= "&" . $ttsAPIKey{$TTS_Ressource} . $TTS_APIKey if(length($ttsAPIKey{$TTS_Ressource})>0);
|
||||||
|
$url .= "&" . $ttsQuality{$TTS_Ressource} . $TTS_Quality if(length($ttsQuality{$TTS_Ressource})>0);
|
||||||
|
$url .= "&" . $ttsSpeed{$TTS_Ressource} . $TTS_Speed if(length($ttsSpeed{$TTS_Ressource})>0);
|
||||||
|
$url .= "&" . $ttsQuery{$TTS_Ressource} . uri_escape($text);
|
||||||
|
|
||||||
my $url = "http://" . $ttsHost{$TTS_Ressource} . $ttsPath{$TTS_Ressource};
|
Log3 $hash->{NAME}, 4, "Text2Speech: Verwende ".$TTS_Ressource." OnlineResource zum Download";
|
||||||
$url .= $ttsLang{$TTS_Ressource};
|
Log3 $hash->{NAME}, 4, "Text2Speech: Hole URL: ". $url;
|
||||||
$url .= $language{$TTS_Ressource}{$TTS_Language};
|
#$HttpResponse = GetHttpFile($ttsHost, $ttsPath . $ttsLang . $language{$TTS_Ressource}{$TTS_Language} . "&" . $ttsQuery . uri_escape($text));
|
||||||
$url .= "&" . $ttsAddon{$TTS_Ressource} if(length($ttsAddon{$TTS_Ressource})>0);
|
my $param = {
|
||||||
$url .= "&" . $ttsUser{$TTS_Ressource} . $TTS_User if(length($ttsUser{$TTS_Ressource})>0);
|
url => $url,
|
||||||
$url .= "&" . $ttsAPIKey{$TTS_Ressource} . $TTS_APIKey if(length($ttsAPIKey{$TTS_Ressource})>0);
|
timeout => 5,
|
||||||
$url .= "&" . $ttsQuality{$TTS_Ressource} . $TTS_Quality if(length($ttsQuality{$TTS_Ressource})>0);
|
hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
|
||||||
$url .= "&" . $ttsSpeed{$TTS_Ressource} . $TTS_Speed if(length($ttsSpeed{$TTS_Ressource})>0);
|
method => "GET" # Lesen von Inhalten
|
||||||
$url .= "&" . $ttsQuery{$TTS_Ressource} . uri_escape($text);
|
#httpversion => "1.1",
|
||||||
|
#header => "User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22m" # Den Header gemäss abzufragender Daten ändern
|
||||||
|
#header => "agent: Mozilla/1.22\r\nUser-Agent: Mozilla/1.22"
|
||||||
|
};
|
||||||
|
($HttpResponseErr, $HttpResponse) = HttpUtils_BlockingGet($param);
|
||||||
|
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Verwende ".$TTS_Ressource." OnlineResource zum Download";
|
if(length($HttpResponseErr) > 0) {
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Hole URL: ". $url;
|
Log3 $hash->{NAME}, 3, "Text2Speech: Fehler beim abrufen der Daten von " .$TTS_Ressource. " Translator";
|
||||||
#$HttpResponse = GetHttpFile($ttsHost, $ttsPath . $ttsLang . $language{$TTS_Ressource}{$TTS_Language} . "&" . $ttsQuery . uri_escape($text));
|
Log3 $hash->{NAME}, 3, "Text2Speech: " . $HttpResponseErr;
|
||||||
my $param = {
|
}
|
||||||
url => $url,
|
|
||||||
timeout => 5,
|
|
||||||
hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
|
|
||||||
method => "GET" # Lesen von Inhalten
|
|
||||||
#httpversion => "1.1",
|
|
||||||
#header => "User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22m" # Den Header gemäss abzufragender Daten ändern
|
|
||||||
#header => "agent: Mozilla/1.22\r\nUser-Agent: Mozilla/1.22"
|
|
||||||
};
|
|
||||||
($HttpResponseErr, $HttpResponse) = HttpUtils_BlockingGet($param);
|
|
||||||
|
|
||||||
if(length($HttpResponseErr) > 0) {
|
$fh = new IO::File ">$file";
|
||||||
Log3 $hash->{NAME}, 3, "Text2Speech: Fehler beim abrufen der Daten von " .$TTS_Ressource. " Translator";
|
if(!defined($fh)) {
|
||||||
Log3 $hash->{NAME}, 3, "Text2Speech: " . $HttpResponseErr;
|
Log3 $hash->{NAME}, 2, "Text2Speech: mp3 Datei <$file> konnte nicht angelegt werden.";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fh->print($HttpResponse);
|
||||||
|
Log3 $hash->{NAME}, 4, "Text2Speech: Schreibe mp3 in die Datei $file mit ".length($HttpResponse)." Bytes";
|
||||||
|
close($fh);
|
||||||
|
} elsif ($TTS_Ressource eq "ESpeak") {
|
||||||
|
my $FileWav = $file . ".wav";
|
||||||
|
|
||||||
|
$cmd = "sudo espeak -vde+f3 -k5 -s150 \"" . $text . "\">\"" . $FileWav . "\"";
|
||||||
|
Log3 $hash, 4, "Text2Speech:" .$cmd;
|
||||||
|
system($cmd);
|
||||||
|
|
||||||
|
$cmd = "lame \"" . $FileWav . "\" \"" . $file . "\"";
|
||||||
|
Log3 $hash, 4, "Text2Speech:" .$cmd;
|
||||||
|
system($cmd);
|
||||||
|
unlink $FileWav;
|
||||||
|
} elsif ($TTS_Ressource eq "SVOX-pico") {
|
||||||
|
my $FileWav = $file . ".wav";
|
||||||
|
|
||||||
|
$cmd = "pico2wave --lang=" . $language{$TTS_Ressource}{$TTS_Language} . " --wave=\"" . $FileWav . "\" \"" . $text . "\"";
|
||||||
|
Log3 $hash, 4, "Text2Speech:" .$cmd;
|
||||||
|
system($cmd);
|
||||||
|
|
||||||
|
$cmd = "lame \"" . $FileWav . "\" \"" . $file . "\"";
|
||||||
|
Log3 $hash, 4, "Text2Speech:" .$cmd;
|
||||||
|
system($cmd);
|
||||||
|
unlink $FileWav;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fh = new IO::File ">$file";
|
|
||||||
if(!defined($fh)) {
|
|
||||||
Log3 $hash->{NAME}, 2, "Text2Speech: mp3 Datei <$file> konnte nicht angelegt werden.";
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fh->print($HttpResponse);
|
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Schreibe mp3 in die Datei $file mit ".length($HttpResponse)." Bytes";
|
|
||||||
close($fh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
@ -725,111 +756,98 @@ sub Text2Speech_DoIt($) {
|
|||||||
|
|
||||||
Log3 $hash->{NAME}, 4, "Verwende TTS Spracheinstellung: ".$TTS_Language;
|
Log3 $hash->{NAME}, 4, "Verwende TTS Spracheinstellung: ".$TTS_Language;
|
||||||
|
|
||||||
if($TTS_Ressource =~ m/(Google|VoiceRSS)/) {
|
my $filename;
|
||||||
|
my $file;
|
||||||
|
|
||||||
my $filename;
|
unless(-e $TTS_CacheFileDir or mkdir $TTS_CacheFileDir) {
|
||||||
my $file;
|
#Verzeichnis anlegen gescheitert
|
||||||
|
Log3 $hash->{NAME}, 2, "Text2Speech: Angegebenes Verzeichnis $TTS_CacheFileDir konnte erstmalig nicht angelegt werden.";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
unless(-e $TTS_CacheFileDir or mkdir $TTS_CacheFileDir) {
|
if(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0)) {
|
||||||
#Verzeichnis anlegen gescheitert
|
# benutze das Tool MP3Wrap um bereits einzelne vorhandene Sprachdateien
|
||||||
Log3 $hash->{NAME}, 2, "Text2Speech: Angegebenes Verzeichnis $TTS_CacheFileDir konnte erstmalig nicht angelegt werden.";
|
# zusammenzuführen. Ziel: sauberer Sprachfluss
|
||||||
return undef;
|
my @Mp3WrapFiles;
|
||||||
|
my @Mp3WrapText;
|
||||||
|
|
||||||
|
$TTS_SentenceAppendix = $myFileTemplateDir ."/". $TTS_SentenceAppendix if($TTS_SentenceAppendix);
|
||||||
|
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_SentenceAppendix));
|
||||||
|
|
||||||
|
#Abspielliste erstellen
|
||||||
|
foreach my $t (@{$hash->{helper}{Text2Speech}}) {
|
||||||
|
if(-e $TTS_CacheFileDir."/".$t) { $filename = $t;} else {$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $t) . ".mp3";} # falls eine bestimmte mp3-Datei gespielt werden soll
|
||||||
|
$file = $TTS_CacheFileDir."/".$filename;
|
||||||
|
if(-e $file) {
|
||||||
|
push(@Mp3WrapFiles, $file);
|
||||||
|
push(@Mp3WrapText, $t);
|
||||||
|
#Text2Speech_WriteStats($hash, 0, $file, $t);
|
||||||
|
} else {last;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push(@Mp3WrapFiles, $TTS_SentenceAppendix) if($TTS_SentenceAppendix);
|
||||||
|
|
||||||
if(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0)) {
|
if(scalar(@Mp3WrapFiles) >= 2) {
|
||||||
# benutze das Tool MP3Wrap um bereits einzelne vorhandene Sprachdateien
|
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". join(" ", @Mp3WrapText);
|
||||||
# zusammenzuführen. Ziel: sauberer Sprachfluss
|
|
||||||
my @Mp3WrapFiles;
|
|
||||||
my @Mp3WrapText;
|
|
||||||
|
|
||||||
$TTS_SentenceAppendix = $myFileTemplateDir ."/". $TTS_SentenceAppendix if($TTS_SentenceAppendix);
|
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapFiles));
|
||||||
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_SentenceAppendix));
|
my $Mp3WrapFile = $TTS_CacheFileDir ."/". $Mp3WrapPrefix . "_MP3WRAP.mp3";
|
||||||
|
|
||||||
#Abspielliste erstellen
|
if(! -e $Mp3WrapFile) {
|
||||||
foreach my $t (@{$hash->{helper}{Text2Speech}}) {
|
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapFiles);
|
||||||
if(-e $TTS_CacheFileDir."/".$t) { $filename = $t;} else {$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $t) . ".mp3";} # falls eine bestimmte mp3-Datei gespielt werden soll
|
$cmd .= " >/dev/null" if($verbose < 5);;
|
||||||
$file = $TTS_CacheFileDir."/".$filename;
|
|
||||||
if(-e $file) {
|
Log3 $hash->{NAME}, 4, "Text2Speech: " .$cmd;
|
||||||
push(@Mp3WrapFiles, $file);
|
system($cmd);
|
||||||
push(@Mp3WrapText, $t);
|
}
|
||||||
#Text2Speech_WriteStats($hash, 0, $file, $t);
|
if(-e $Mp3WrapFile) {
|
||||||
} else {last;}
|
$cmd = Text2Speech_BuildMplayerCmdString($hash, $Mp3WrapFile);
|
||||||
|
Log3 $hash->{NAME}, 4, "Text2Speech:" .$cmd;
|
||||||
|
system($cmd);
|
||||||
|
#Text2Speech_WriteStats($hash, 1, $Mp3WrapFile, join(" ", @Mp3WrapText));
|
||||||
|
} else {
|
||||||
|
Log3 $hash->{NAME}, 2, "Text2Speech: Mp3Wrap Datei konnte nicht angelegt werden.";
|
||||||
}
|
}
|
||||||
|
|
||||||
push(@Mp3WrapFiles, $TTS_SentenceAppendix) if($TTS_SentenceAppendix);
|
return $hash->{NAME} ."|".
|
||||||
|
($TTS_SentenceAppendix ? scalar(@Mp3WrapFiles)-1: scalar(@Mp3WrapFiles)) ."|".
|
||||||
if(scalar(@Mp3WrapFiles) >= 2) {
|
$Mp3WrapFile;
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". join(" ", @Mp3WrapText);
|
|
||||||
|
|
||||||
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapFiles));
|
|
||||||
my $Mp3WrapFile = $TTS_CacheFileDir ."/". $Mp3WrapPrefix . "_MP3WRAP.mp3";
|
|
||||||
|
|
||||||
if(! -e $Mp3WrapFile) {
|
|
||||||
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapFiles);
|
|
||||||
$cmd .= " >/dev/null" if($verbose < 5);;
|
|
||||||
|
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: " .$cmd;
|
|
||||||
system($cmd);
|
|
||||||
}
|
|
||||||
if(-e $Mp3WrapFile) {
|
|
||||||
$cmd = Text2Speech_BuildMplayerCmdString($hash, $Mp3WrapFile);
|
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech:" .$cmd;
|
|
||||||
system($cmd);
|
|
||||||
#Text2Speech_WriteStats($hash, 1, $Mp3WrapFile, join(" ", @Mp3WrapText));
|
|
||||||
} else {
|
|
||||||
Log3 $hash->{NAME}, 2, "Text2Speech: Mp3Wrap Datei konnte nicht angelegt werden.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hash->{NAME} ."|".
|
|
||||||
($TTS_SentenceAppendix ? scalar(@Mp3WrapFiles)-1: scalar(@Mp3WrapFiles)) ."|".
|
|
||||||
$Mp3WrapFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite jetzt den Text: ". $hash->{helper}{Text2Speech}[0];
|
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite jetzt den Text: ". $hash->{helper}{Text2Speech}[0];
|
||||||
|
|
||||||
if(-e $hash->{helper}{Text2Speech}[0]) {
|
if(-e $hash->{helper}{Text2Speech}[0]) {
|
||||||
# falls eine bestimmte mp3-Datei mit absolutem Pfad gespielt werden soll
|
# falls eine bestimmte mp3-Datei mit absolutem Pfad gespielt werden soll
|
||||||
$filename = $hash->{helper}{Text2Speech}[0];
|
$filename = $hash->{helper}{Text2Speech}[0];
|
||||||
$file = $filename;
|
$file = $filename;
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||||
} elsif(-e $TTS_CacheFileDir."/".$hash->{helper}{Text2Speech}[0]) {
|
} elsif(-e $TTS_CacheFileDir."/".$hash->{helper}{Text2Speech}[0]) {
|
||||||
# falls eine bestimmte mp3-Datei mit relativem Pfad gespielt werden soll
|
# falls eine bestimmte mp3-Datei mit relativem Pfad gespielt werden soll
|
||||||
$filename = $hash->{helper}{Text2Speech}[0];
|
$filename = $hash->{helper}{Text2Speech}[0];
|
||||||
$file = $TTS_CacheFileDir."/".$filename;
|
$file = $TTS_CacheFileDir."/".$filename;
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||||
} else {
|
} else {
|
||||||
$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $hash->{helper}{Text2Speech}[0]) . ".mp3";
|
$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $hash->{helper}{Text2Speech}[0]) . ".mp3";
|
||||||
$file = $TTS_CacheFileDir."/".$filename;
|
$file = $TTS_CacheFileDir."/".$filename;
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: Textbaustein ist keine direkte MP3 Datei, ermittle MD5 CacheNamen: $filename";
|
Log3 $hash->{NAME}, 4, "Text2Speech: Textbaustein ist keine direkte MP3 Datei, ermittle MD5 CacheNamen: $filename";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(! -e $file) { # Datei existiert noch nicht im Cache
|
if(! -e $file) { # Datei existiert noch nicht im Cache
|
||||||
Text2Speech_Download($hash, $file, $hash->{helper}{Text2Speech}[0]);
|
Text2Speech_Download($hash, $file, $hash->{helper}{Text2Speech}[0]);
|
||||||
} else {
|
} else {
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech: $file gefunden, kein Download";
|
Log3 $hash->{NAME}, 4, "Text2Speech: $file gefunden, kein Download";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(-e $file) { # Datei existiert jetzt
|
if(-e $file) { # Datei existiert jetzt
|
||||||
$cmd = Text2Speech_BuildMplayerCmdString($hash, $file);
|
$cmd = Text2Speech_BuildMplayerCmdString($hash, $file);
|
||||||
Log3 $hash->{NAME}, 4, "Text2Speech:" .$cmd;
|
Log3 $hash->{NAME}, 4, "Text2Speech:" .$cmd;
|
||||||
system($cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hash->{NAME}. "|".
|
|
||||||
"1" ."|".
|
|
||||||
$file;
|
|
||||||
|
|
||||||
} elsif ($TTS_Ressource eq "ESpeak") {
|
|
||||||
$cmd = "sudo espeak -vde+f3 -k5 -s150 \"" . $hash->{helper}{Text2Speech}[0] . "\"";
|
|
||||||
Log3 $hash, 4, "Text2Speech:" .$cmd;
|
|
||||||
system($cmd);
|
system($cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hash->{NAME}. "|".
|
return $hash->{NAME}. "|".
|
||||||
"1" ."|".
|
"1" ."|".
|
||||||
"";
|
$file;
|
||||||
}
|
}
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
@ -863,6 +881,8 @@ sub Text2Speech_Done($) {
|
|||||||
# erneutes aufrufen da ev. weiterer Text in der Warteschlange steht
|
# erneutes aufrufen da ev. weiterer Text in der Warteschlange steht
|
||||||
if(@{$hash->{helper}{Text2Speech}} > 0) {
|
if(@{$hash->{helper}{Text2Speech}} > 0) {
|
||||||
$hash->{helper}{RUNNING_PID} = BlockingCall("Text2Speech_DoIt", $hash, "Text2Speech_Done", $TTS_TimeOut, "Text2Speech_AbortFn", $hash);
|
$hash->{helper}{RUNNING_PID} = BlockingCall("Text2Speech_DoIt", $hash, "Text2Speech_Done", $TTS_TimeOut, "Text2Speech_AbortFn", $hash);
|
||||||
|
} else {
|
||||||
|
readingsSingleUpdate($hash, "playing", "0", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,8 +1032,19 @@ sub Text2Speech_WriteStats($$$$){
|
|||||||
because the quality is also fantastic. To use this engine you need an APIKey (see TTS_APIKey)
|
because the quality is also fantastic. To use this engine you need an APIKey (see TTS_APIKey)
|
||||||
</li>
|
</li>
|
||||||
<li>ESpeak<br>
|
<li>ESpeak<br>
|
||||||
Using the ESpeak Engine. Installation of the espeak sourcen is required.<br>
|
Using the ESpeak Engine. Installation Espeak and lame is required.<br>
|
||||||
<code>apt-get install espeak</code>
|
<code>apt-get install espeak lame</code>
|
||||||
|
</li>
|
||||||
|
<li>SVOX-pico<br>
|
||||||
|
Using the SVOX-Pico TTS-Engine (from the AOSP).<br>
|
||||||
|
Installation of the engine and <code>lame</code> is required:<br>
|
||||||
|
<code>sudo apt-get install libttspico-utils lame</code><br><br>
|
||||||
|
On ARM/Raspbian the package <code>libttspico-utils</code>,<br>
|
||||||
|
so you may have to compile it yourself or use the precompiled package from <a target="_blank" href"http://www.robotnet.de/2014/03/20/sprich-freund-und-tritt-ein-sprachausgabe-fur-den-rasberry-pi/">this guide</a>, in short:<br>
|
||||||
|
<code>sudo apt-get install libpopt-dev lame</code><br>
|
||||||
|
<code>cd /tmp</code><br>
|
||||||
|
<code>wget http://www.dr-bischoff.de/raspi/pico2wave.deb</code><br>
|
||||||
|
<code>sudo dpkg --install pico2wave.deb</code>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -1199,8 +1230,19 @@ sub Text2Speech_WriteStats($$$$){
|
|||||||
</li>
|
</li>
|
||||||
<li>ESpeak<br>
|
<li>ESpeak<br>
|
||||||
Nutzung der ESpeak Offline Sprachengine. Die Qualitä ist schlechter als die Google Engine.
|
Nutzung der ESpeak Offline Sprachengine. Die Qualitä ist schlechter als die Google Engine.
|
||||||
ESpeak ist vor der Nutzung zu installieren.<br>
|
ESpeak und lame sind vor der Nutzung zu installieren.<br>
|
||||||
<code>apt-get install espeak</code>
|
<code>apt-get install espeak lame</code>
|
||||||
|
</li>
|
||||||
|
<li>SVOX-pico<br>
|
||||||
|
Nutzung der SVOX-Pico TTS-Engine (aus dem AOSP).<br>
|
||||||
|
Die Sprachengine sowie <code>lame</code> müssen installiert sein:<br>
|
||||||
|
<code>sudo apt-get install libttspico-utils lame</code><br><br>
|
||||||
|
Für ARM/Raspbian sind die <code>libttspico-utils</code> leider nicht verfügbar,<br>
|
||||||
|
deswegen müsste man diese selbst kompilieren oder das vorkompilierte Paket aus <a target="_blank" href"http://www.robotnet.de/2014/03/20/sprich-freund-und-tritt-ein-sprachausgabe-fur-den-rasberry-pi/">dieser Anleitung</a> verwenden, in aller Kürze:<br>
|
||||||
|
<code>sudo apt-get install libpopt-dev lame</code><br>
|
||||||
|
<code>cd /tmp</code><br>
|
||||||
|
<code>wget http://www.dr-bischoff.de/raspi/pico2wave.deb</code><br>
|
||||||
|
<code>sudo dpkg --install pico2wave.deb</code>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -1263,7 +1305,8 @@ sub Text2Speech_WriteStats($$$$){
|
|||||||
<code>attr myTTS TTS_VolumeAdjust 400</code><br>
|
<code>attr myTTS TTS_VolumeAdjust 400</code><br>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
|
<li><a href="#readingFnAttributes">readingFnAttributes</a>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
<li><a href="#disable">disable</a><br>
|
<li><a href="#disable">disable</a><br>
|
||||||
If this attribute is activated, the soundoutput will be disabled.<br>
|
If this attribute is activated, the soundoutput will be disabled.<br>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user