/**************************************************************************** Main speaking functions for the FreeTTS Plug in ------------------- Copyright : (C) 2004 Paul Giannaros ------------------- Original author: Paul Giannaros Current Maintainer: Paul Giannaros ******************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "freettsproc.h" /** Constructor */ FreeTTSProc::FreeTTSProc( TQObject* parent, const char* name, const TQStringList& /*args*/) : PlugInProc( parent, name ) { kdDebug() << "Running: FreeTTSProc::FreeTTSProc" << endl; m_state = psIdle; m_waitingStop = false; m_freettsProc = 0; } /** Desctructor */ FreeTTSProc::~FreeTTSProc() { kdDebug() << "Running: FreeTTSProc::~FreeTTSProc" << endl; if (m_freettsProc) { stopText(); delete m_freettsProc; } } /** Initializate the speech */ bool FreeTTSProc::init(KConfig *config, const TQString &configGroup) { kdDebug() << "Running: FreeTTSProc::init()" << endl; kdDebug() << "Initializing plug in: FreeTTS" << endl; config->setGroup(configGroup); m_freettsJarPath = config->readEntry("FreeTTSJarPath", "freetts.jar"); kdDebug() << "FreeTTSProc::init: path to freetts.jar: " << m_freettsJarPath << endl; return true; } /** * Say a text. Synthesize and audibilize it. * @param text The text to be spoken. * * If the plugin supports asynchronous operation, it should return immediately. */ void FreeTTSProc::sayText(const TQString &text) { synth(text, TQString(), m_freettsJarPath); } /** * Synthesize text into an audio file, but do not send to the audio device. * @param text The text to be synthesized. * @param suggestedFilename Full pathname of file to create. The plugin * may ignore this parameter and choose its own * filename. KTTSD will query the generated * filename using getFilename(). * * If the plugin supports asynchronous operation, it should return immediately. */ void FreeTTSProc::synthText(const TQString& text, const TQString& suggestedFilename) { kdDebug() << "Running: FreeTTSProc::synthText" << endl; synth(text, suggestedFilename, m_freettsJarPath); } // A little helper function because KDE 3.2 kdDebug() does not support TQValueList. TQStringList argsToTQStringList(const TQValueList list) { TQStringList newList; TQValueList::ConstIterator it = list.begin(); for ( ; it != list.end(); ++it ) newList.append(*it); return newList; } void FreeTTSProc::synth( const TQString &text, const TQString &synthFilename, const TQString& freettsJarPath) { kdDebug() << "Running: FreeTTSProc::synth" << endl; if (m_freettsProc) { if (m_freettsProc->isRunning()) m_freettsProc->kill(); delete m_freettsProc; m_freettsProc = 0; } m_freettsProc = new KProcess; connect(m_freettsProc, TQT_SIGNAL(processExited(KProcess*)), this, TQT_SLOT(slotProcessExited(KProcess*))); connect(m_freettsProc, TQT_SIGNAL(receivedStdout(KProcess*, char*, int)), this, TQT_SLOT(slotReceivedStdout(KProcess*, char*, int))); connect(m_freettsProc, TQT_SIGNAL(receivedStderr(KProcess*, char*, int)), this, TQT_SLOT(slotReceivedStderr(KProcess*, char*, int))); connect(m_freettsProc, TQT_SIGNAL(wroteStdin(KProcess*)), this, TQT_SLOT(slotWroteStdin(KProcess* ))); if (synthFilename.isNull()) m_state = psSaying; else m_state = psSynthing; TQString saidText = text; saidText += "\n"; /// As freetts.jar doesn't seem to like being called from an absolute path, /// we need to strip off the path to freetts.jar and pass it to /// KProcess::setWorkingDirectory() /// We could just strip off 11 characters from the end of the path to freetts.jar, but thats /// not exactly very portable... TQString filename = TQFileInfo(freettsJarPath).baseName().append(TQString(".").append(TQFileInfo(freettsJarPath).extension())); TQString freettsJarDir = freettsJarPath.left((freettsJarPath.length() - filename.length()) - 1); m_freettsProc->setWorkingDirectory(freettsJarDir); kdDebug() << "FreeTTSProc::synthText: moved to directory '" << freettsJarDir << "'" << endl; kdDebug() << "FreeTTSProc::synthText: Running file: '" << filename << "'" << endl; *m_freettsProc << "java" << "-jar" << filename; /// Dump audio into synthFilename if (!synthFilename.isNull()) *m_freettsProc << "-dumpAudio" << synthFilename; m_synthFilename = synthFilename; kdDebug() << "FreeTTSProc::synth: Synthing text: '" << saidText << "' using FreeTTS plug in" << endl; if (!m_freettsProc->start(KProcess::NotifyOnExit, KProcess::All)) { kdDebug() << "FreeTTSProc::synth: Error starting FreeTTS process. Is freetts.jar in the PATH?" << endl; m_state = psIdle; kdDebug() << "KProcess args: " << argsToTQStringList(m_freettsProc->args()) << endl; return; } kdDebug()<< "FreeTTSProc:synth: FreeTTS initialized" << endl; m_freettsProc->writeStdin(saidText.latin1(), saidText.length()); } /** * Returning the filename of the synth'd text * @returns The filename of the last synth'd text */ TQString FreeTTSProc::getFilename() { kdDebug() << "FreeTTSProc::getFilename: returning " << m_synthFilename << endl; return m_synthFilename; } /** * Stop current operation (saying or synthesizing text). * Important: This function may be called from a thread different from the * one that called sayText or synthText. * If the plugin cannot stop an in-progress @ref sayText or * @ref synthText operation, it must not block waiting for it to complete. * Instead, return immediately. * * If a plugin returns before the operation has actually been stopped, * the plugin must emit the @ref stopped signal when the operation has * actually stopped. * * The plugin should change to the psIdle state after stopping the * operation. */ void FreeTTSProc::stopText() { kdDebug() << "FreeTTSProc::stopText:: Running" << endl; if (m_freettsProc) { if (m_freettsProc->isRunning()) { kdDebug() << "FreeTTSProc::stopText: killing FreeTTS." << endl; m_waitingStop = true; m_freettsProc->kill(); } else m_state = psIdle; } else m_state = psIdle; kdDebug() << "FreeTTSProc::stopText: FreeTTS stopped." << endl; } void FreeTTSProc::slotProcessExited(KProcess*) { kdDebug() << "FreeTTSProc:slotProcessExited: FreeTTS process has exited." << endl; pluginState prevState = m_state; if (m_waitingStop) { m_waitingStop = false; m_state = psIdle; emit stopped(); } else { m_state = psFinished; if (prevState == psSaying) emit sayFinished(); else if (prevState == psSynthing) emit synthFinished(); } } void FreeTTSProc::slotReceivedStdout(KProcess*, char* buffer, int buflen) { TQString buf = TQString::tqfromLatin1(buffer, buflen); kdDebug() << "FreeTTSProc::slotReceivedStdout: Received output from FreeTTS: " << buf << endl; } void FreeTTSProc::slotReceivedStderr(KProcess*, char* buffer, int buflen) { TQString buf = TQString::tqfromLatin1(buffer, buflen); kdDebug() << "FreeTTSProc::slotReceivedStderr: Received error from FreeTTS: " << buf << endl; } void FreeTTSProc::slotWroteStdin(KProcess*) { kdDebug() << "FreeTTSProc::slotWroteStdin: closing Stdin" << endl; m_freettsProc->closeStdin(); } /** * Return the current state of the plugin. * This function only makes sense in asynchronous mode. * @return The pluginState of the plugin. * * @see pluginState */ pluginState FreeTTSProc::getState() { return m_state; } /** * Acknowledges a finished state and resets the plugin state to psIdle. * * If the plugin is not in state psFinished, nothing happens. * The plugin may use this call to do any post-processing cleanup, * for example, blanking the stored filename (but do not delete the file). * Calling program should call getFilename prior to ackFinished. */ void FreeTTSProc::ackFinished() { if (m_state == psFinished) { m_state = psIdle; m_synthFilename = TQString(); } } /** * Returns True if the plugin supports asynchronous processing, * i.e., returns immediately from sayText or synthText. * @return True if this plugin supports asynchronous processing. * * If the plugin returns True, it must also implement @ref getState . * It must also emit @ref sayFinished or @ref synthFinished signals when * saying or synthesis is completed. */ bool FreeTTSProc::supportsAsync() { // return true; return true; } /** * Returns True if the plugIn supports synthText method, * i.e., is able to synthesize text to a sound file without * audibilizing the text. * @return True if this plugin supports synthText method. */ bool FreeTTSProc::supportsSynth() { // return true; return true; } #include "freettsproc.moc"