1
0
Fork 0
forked from len0rd/rockbox

Add capability to speak directly from the TTS engine.

The OS X TTS engine (and likely others) allows outputting its speech directly
to the sound system. This avoids the extra step of creating a temporary file to
play for TTS preview. Currently implemented as TTS capability reported.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29672 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dominik Riebeling 2011-04-03 08:06:59 +00:00
parent 76c112ce6e
commit 746f01dd77
3 changed files with 48 additions and 36 deletions

View file

@ -36,7 +36,7 @@ class TTSBase : public EncTtsSettingInterface
{ {
Q_OBJECT Q_OBJECT
public: public:
enum Capability { None = 0, RunInParallel = 1 }; enum Capability { None = 0, RunInParallel = 1, CanSpeak = 2 };
Q_DECLARE_FLAGS(Capabilities, Capability) Q_DECLARE_FLAGS(Capabilities, Capability)
TTSBase(QObject *parent); TTSBase(QObject *parent);

View file

@ -36,7 +36,7 @@ TTSCarbon::TTSCarbon(QObject* parent) : TTSBase(parent)
TTSBase::Capabilities TTSCarbon::capabilities() TTSBase::Capabilities TTSCarbon::capabilities()
{ {
return None; return TTSBase::CanSpeak;
} }
bool TTSCarbon::configOk() bool TTSCarbon::configOk()
@ -75,7 +75,7 @@ bool TTSCarbon::start(QString *errStr)
if(voiceIndex == numVoices) { if(voiceIndex == numVoices) {
// voice not found. Add user notification here and proceed with // voice not found. Add user notification here and proceed with
// system default voice. // system default voice.
qDebug() << "selected voice not found, using system default!"; qDebug() << "[TTSCarbon] Selected voice not found, using system default!";
GetVoiceDescription(&vspec, &vdesc, sizeof(vdesc)); GetVoiceDescription(&vspec, &vdesc, sizeof(vdesc));
if(vdesc.script != -1) if(vdesc.script != -1)
m_voiceScript = (CFStringBuiltInEncodings)vdesc.script; m_voiceScript = (CFStringBuiltInEncodings)vdesc.script;
@ -160,18 +160,21 @@ TTSStatus TTSCarbon::voice(QString text, QString wavfile, QString* errStr)
TTSStatus status = NoError; TTSStatus status = NoError;
OSErr error; OSErr error;
QString aifffile = wavfile + ".aiff"; char* tmpfile;
// FIXME: find out why we need to do this. if(!wavfile.isEmpty()) {
// Create a local copy of the temporary file filename. QString aifffile = wavfile + ".aiff";
// Not doing so causes weird issues (path contains trailing spaces) // FIXME: find out why we need to do this.
unsigned int len = aifffile.size() + 1; // Create a local copy of the temporary file filename.
char* tmpfile = (char*)malloc(len * sizeof(char)); // Not doing so causes weird issues (path contains trailing spaces)
strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len); unsigned int len = aifffile.size() + 1;
CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault, tmpfile = (char*)malloc(len * sizeof(char));
tmpfile, kCFStringEncodingUTF8); strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len);
CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault,
tmpfileref, kCFURLPOSIXPathStyle, false); tmpfile, kCFStringEncodingUTF8);
SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref); CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
tmpfileref, kCFURLPOSIXPathStyle, false);
SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref);
}
// speak it. // speak it.
// Convert the string to the encoding requested by the voice. Do this // Convert the string to the encoding requested by the voice. Do this
@ -206,15 +209,17 @@ TTSStatus TTSCarbon::voice(QString text, QString wavfile, QString* errStr)
free(textbuf); free(textbuf);
CFRelease(cfstring); CFRelease(cfstring);
// convert the temporary aiff file to wav if(!wavfile.isEmpty()) {
if(status == NoError // convert the temporary aiff file to wav
&& convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) { if(status == NoError
*errStr = tr("Could not convert intermediate file"); && convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) {
status = FatalError; *errStr = tr("Could not convert intermediate file");
status = FatalError;
}
// remove temporary aiff file
unlink(tmpfile);
free(tmpfile);
} }
// remove temporary aiff file
unlink(tmpfile);
free(tmpfile);
return status; return status;
} }

View file

@ -731,14 +731,16 @@ void Config::testTts()
{ {
QString errstr; QString errstr;
int index = ui.comboTts->currentIndex(); int index = ui.comboTts->currentIndex();
TTSBase* tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString()); TTSBase* tts;
ui.testTTS->setEnabled(false);
tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString());
if(!tts->configOk()) if(!tts->configOk())
{ {
QMessageBox::warning(this,tr("TTS configuration invalid"), QMessageBox::warning(this,tr("TTS configuration invalid"),
tr("TTS configuration invalid. \n Please configure TTS engine.")); tr("TTS configuration invalid. \n Please configure TTS engine."));
return; return;
} }
ui.testTTS->setEnabled(false);
if(!tts->start(&errstr)) if(!tts->start(&errstr))
{ {
QMessageBox::warning(this,tr("Could not start TTS engine."), QMessageBox::warning(this,tr("Could not start TTS engine."),
@ -748,10 +750,13 @@ void Config::testTts()
return; return;
} }
QTemporaryFile file(this); QString filename;
file.open(); if(!(tts->capabilities() & TTSBase::CanSpeak)) {
QString filename = file.fileName(); QTemporaryFile file(this);
file.close(); file.open();
filename = file.fileName();
file.close();
}
if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError) if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError)
{ {
@ -763,16 +768,18 @@ void Config::testTts()
return; return;
} }
tts->stop(); tts->stop();
if(!(tts->capabilities() & TTSBase::CanSpeak)) {
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
QString exe = Utils::findExecutable("aplay"); QString exe = Utils::findExecutable("aplay");
if(exe == "") exe = Utils::findExecutable("play"); if(exe == "") exe = Utils::findExecutable("play");
if(exe != "") if(exe != "")
{ {
QProcess::execute(exe+" "+filename); QProcess::execute(exe+" "+filename);
} }
#else #else
QSound::play(filename); QSound::play(filename);
#endif #endif
}
ui.testTTS->setEnabled(true); ui.testTTS->setEnabled(true);
delete tts; /* Config objects are never deleted (in fact, they are delete tts; /* Config objects are never deleted (in fact, they are
leaked..), so we can't rely on QObject, since that would leaked..), so we can't rely on QObject, since that would