From 746f01dd775feb9b53577a2338fd9182d879c0d3 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Sun, 3 Apr 2011 08:06:59 +0000 Subject: 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 --- rbutil/rbutilqt/base/ttsbase.h | 2 +- rbutil/rbutilqt/base/ttscarbon.cpp | 49 +++++++++++++++++++++----------------- rbutil/rbutilqt/configure.cpp | 33 +++++++++++++++---------- 3 files changed, 48 insertions(+), 36 deletions(-) (limited to 'rbutil') diff --git a/rbutil/rbutilqt/base/ttsbase.h b/rbutil/rbutilqt/base/ttsbase.h index f04016c85f..c6bbdcfb0b 100644 --- a/rbutil/rbutilqt/base/ttsbase.h +++ b/rbutil/rbutilqt/base/ttsbase.h @@ -36,7 +36,7 @@ class TTSBase : public EncTtsSettingInterface { Q_OBJECT public: - enum Capability { None = 0, RunInParallel = 1 }; + enum Capability { None = 0, RunInParallel = 1, CanSpeak = 2 }; Q_DECLARE_FLAGS(Capabilities, Capability) TTSBase(QObject *parent); diff --git a/rbutil/rbutilqt/base/ttscarbon.cpp b/rbutil/rbutilqt/base/ttscarbon.cpp index 63fb5315e3..ba744b5fcf 100644 --- a/rbutil/rbutilqt/base/ttscarbon.cpp +++ b/rbutil/rbutilqt/base/ttscarbon.cpp @@ -36,7 +36,7 @@ TTSCarbon::TTSCarbon(QObject* parent) : TTSBase(parent) TTSBase::Capabilities TTSCarbon::capabilities() { - return None; + return TTSBase::CanSpeak; } bool TTSCarbon::configOk() @@ -75,7 +75,7 @@ bool TTSCarbon::start(QString *errStr) if(voiceIndex == numVoices) { // voice not found. Add user notification here and proceed with // 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)); if(vdesc.script != -1) m_voiceScript = (CFStringBuiltInEncodings)vdesc.script; @@ -160,18 +160,21 @@ TTSStatus TTSCarbon::voice(QString text, QString wavfile, QString* errStr) TTSStatus status = NoError; OSErr error; - QString aifffile = wavfile + ".aiff"; - // FIXME: find out why we need to do this. - // Create a local copy of the temporary file filename. - // Not doing so causes weird issues (path contains trailing spaces) - unsigned int len = aifffile.size() + 1; - char* tmpfile = (char*)malloc(len * sizeof(char)); - strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len); - CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault, - tmpfile, kCFStringEncodingUTF8); - CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, - tmpfileref, kCFURLPOSIXPathStyle, false); - SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref); + char* tmpfile; + if(!wavfile.isEmpty()) { + QString aifffile = wavfile + ".aiff"; + // FIXME: find out why we need to do this. + // Create a local copy of the temporary file filename. + // Not doing so causes weird issues (path contains trailing spaces) + unsigned int len = aifffile.size() + 1; + tmpfile = (char*)malloc(len * sizeof(char)); + strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len); + CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault, + tmpfile, kCFStringEncodingUTF8); + CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + tmpfileref, kCFURLPOSIXPathStyle, false); + SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref); + } // speak it. // 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); CFRelease(cfstring); - // convert the temporary aiff file to wav - if(status == NoError - && convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) { - *errStr = tr("Could not convert intermediate file"); - status = FatalError; + if(!wavfile.isEmpty()) { + // convert the temporary aiff file to wav + if(status == NoError + && convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) { + *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; } diff --git a/rbutil/rbutilqt/configure.cpp b/rbutil/rbutilqt/configure.cpp index 8bfa20e6a0..9b6376e469 100644 --- a/rbutil/rbutilqt/configure.cpp +++ b/rbutil/rbutilqt/configure.cpp @@ -731,14 +731,16 @@ void Config::testTts() { QString errstr; 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()) { QMessageBox::warning(this,tr("TTS configuration invalid"), tr("TTS configuration invalid. \n Please configure TTS engine.")); return; } - ui.testTTS->setEnabled(false); if(!tts->start(&errstr)) { QMessageBox::warning(this,tr("Could not start TTS engine."), @@ -748,10 +750,13 @@ void Config::testTts() return; } - QTemporaryFile file(this); - file.open(); - QString filename = file.fileName(); - file.close(); + QString filename; + if(!(tts->capabilities() & TTSBase::CanSpeak)) { + QTemporaryFile file(this); + file.open(); + filename = file.fileName(); + file.close(); + } if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError) { @@ -763,16 +768,18 @@ void Config::testTts() return; } tts->stop(); + if(!(tts->capabilities() & TTSBase::CanSpeak)) { #if defined(Q_OS_LINUX) - QString exe = Utils::findExecutable("aplay"); - if(exe == "") exe = Utils::findExecutable("play"); - if(exe != "") - { - QProcess::execute(exe+" "+filename); - } + QString exe = Utils::findExecutable("aplay"); + if(exe == "") exe = Utils::findExecutable("play"); + if(exe != "") + { + QProcess::execute(exe+" "+filename); + } #else - QSound::play(filename); + QSound::play(filename); #endif + } ui.testTTS->setEnabled(true); delete tts; /* Config objects are never deleted (in fact, they are leaked..), so we can't rely on QObject, since that would -- cgit v1.2.3