You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
467 lines
21 KiB
467 lines
21 KiB
15 years ago
|
/***************************************************** vim:set ts=4 sw=4 sts=4:
|
||
|
This file is the template for the processing plug ins.
|
||
|
-------------------
|
||
|
Copyright : (C) 2002-2003 by José Pablo Ezequiel "Pupeno" Fernández
|
||
|
Copyright : (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
|
||
|
-------------------
|
||
|
Original author: José Pablo Ezequiel "Pupeno" Fernández <pupeno@kde.org>
|
||
|
Current Maintainer: Gary Cramblitt <garycramblitt@comcast.net>
|
||
|
******************************************************************************/
|
||
|
|
||
|
/***************************************************************************
|
||
|
* *
|
||
|
* 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. *
|
||
|
* *
|
||
|
***************************************************************************/
|
||
|
|
||
|
#ifndef _PLUGINPROC_H_
|
||
|
#define _PLUGINPROC_H_
|
||
|
|
||
|
#include <qobject.h>
|
||
|
#include <qstring.h>
|
||
|
#include <kdemacros.h>
|
||
|
#include "kdeexportfix.h"
|
||
|
#include <kconfig.h>
|
||
|
|
||
|
/**
|
||
|
* @interface PlugInProc
|
||
|
*
|
||
|
* pluginproc - the KDE Text-to-Speech Deamon Plugin API.
|
||
|
*
|
||
|
* @version 1.0 Draft 1
|
||
|
*
|
||
|
* This class defines the interface that plugins to KTTSD must implement.
|
||
|
*
|
||
|
* @warning The pluginproc interface is still being developed and is likely
|
||
|
* to change in the future.
|
||
|
*
|
||
|
* A KTTSD Plugin interfaces between KTTSD and a speech engine. It provides the methods
|
||
|
* used by KTTSD to synthesize and/or audibilize text into speech.
|
||
|
*
|
||
|
* @section Goals
|
||
|
*
|
||
|
* The ideal plugin has the following features (listed most important to least important):
|
||
|
* - It can synthesize text into an audio file without sending the audio to
|
||
|
* the audio device. If the plugin can do this, the @ref supportsSynth function
|
||
|
* should return True.
|
||
|
* - When @ref stopText is called, is able to immediately stop an in-progress
|
||
|
* synthesis or saying operation.
|
||
|
* - It can operate asynchronously, i.e., returns immediately from a
|
||
|
* @ref sayText or @ref synthText call and emits signals @ref sayFinished or
|
||
|
* @ref synthFinished when completed. If the plugin can do this, the @ref supportsAsync
|
||
|
* function should return True.
|
||
|
*
|
||
|
* As a plugin author, your goal is to provide all 3 of these features. However,
|
||
|
* the speech engine you are working with might not be able to support all three
|
||
|
* features.
|
||
|
*
|
||
|
* If a plugin cannot do all 3 of the features above, the next best combinations
|
||
|
* are (from best to worst):
|
||
|
*
|
||
|
* - @ref supportsSynth returns True, @ref supportsAsync returns False, and
|
||
|
* @stopText is able to immediately stop synthesis.
|
||
|
* - @ref supportsSynth returns True, @ref supportsAsync returns False, and
|
||
|
* @stopText returns immediately without stopping synthesis.
|
||
|
* - @ref supportsAsync returns True, @ref supportsSynth returns False, and
|
||
|
* @ref stopText is able to immediately stop saying.
|
||
|
* - Both @ref supportsSynth and @ref supportsAsync both return False, and
|
||
|
* @ref stopText is able to immediately stop saying.
|
||
|
* - @ref supportsAsync returns True, @ref supportsSynth returns False, and
|
||
|
* @ref stopText returns immediately without stopping saying.
|
||
|
* - Both @ref supportsSynth and @ref supportsAsync both return False, and
|
||
|
* @ref stopText returns immediately without stopping saying.
|
||
|
*
|
||
|
* Notice that aynchronous support is not essential because KTTSD is able to
|
||
|
* provide aynchronous support by running the plugin in a separate thread.
|
||
|
* The ability to immediately stop audio output (or support separate synthesis
|
||
|
* only) is more important.
|
||
|
*
|
||
|
* @section Minimum Implementations
|
||
|
*
|
||
|
* All plugins should implement @ref init in order to initialize the speech engine,
|
||
|
* set language codes, etc.
|
||
|
*
|
||
|
* If @ref supportsSynth return False, a plugin must implement @ref sayText .
|
||
|
*
|
||
|
* If @ref supportsSynth returns True, a plugin must implement the following methods:
|
||
|
* - @ref synthText
|
||
|
* - @ref getFilename
|
||
|
* - @ref ackFinished
|
||
|
* The plugin need not implement @ref sayText .
|
||
|
*
|
||
|
* If @ref supportsAsync returns True, the plugin must implement @ref getState .
|
||
|
*
|
||
|
* If @ref supportsAsync returns True, and @ref supportsSynth returns True,
|
||
|
* a plugin must emit @ref synthFinished signal when synthesis is completed.
|
||
|
*
|
||
|
* If @ref supportsAsync returns True, and @ref supportsSynth returns False,
|
||
|
* a plugin must emit @ref sayFinished signal when saying is completed.
|
||
|
*
|
||
|
* If @ref supportsAsync returns False, do not emit signals @ref sayFinished
|
||
|
* or @ref synthFinished .
|
||
|
*
|
||
|
* @section Implementation Guidelines
|
||
|
*
|
||
|
* In no case, will a plugin need to perform more than one @ref sayText or
|
||
|
* @ref synthText at a time. In other words, in asynchronous mode, KTTSD will
|
||
|
* not call @ref sayText or @ref synthText again until @ref @getState returns
|
||
|
* psFinished.
|
||
|
*
|
||
|
* If @ref supportsAsync returns False, KTTSD will run the plugin in a separate
|
||
|
* QThread. As a consequence, the plugin must not make use of the KDE Library,
|
||
|
* when @ref sayText or @ref synthText is called,
|
||
|
* with the exception of KProcess and family (KProcIO, KShellProcess).
|
||
|
* This restriction comes about because the KDE Libraries make use of the
|
||
|
* main Qt event loop, which unfortunately, runs only in the main thread.
|
||
|
* This restriction will likely be lifted in Qt 4 and later.
|
||
|
*
|
||
|
* Since the KDE library is not available from the @ref sayText and @ref synthText methods,
|
||
|
* it is best if the plugin reads configuration settings in the @ref init method.
|
||
|
* The KConfig object is passed as an argument to @ref init .
|
||
|
*
|
||
|
* If the synthesis engine requires a long initialization time (more than a second),
|
||
|
* it is best if the plugin loads the speech engine from the @ref init method.
|
||
|
* Otherwise, it will be more memory efficient to wait until @ref sayText or
|
||
|
* @ref synthText is called, because it is possible that the plugin will be created
|
||
|
* and initialized, but never used.
|
||
|
*
|
||
|
* All plugins, whether @ref supportsAsync returns True or not, should try to
|
||
|
* implement @ref stopText . If a plugin returns False from @ref supportsAsync,
|
||
|
* @ref stopText will be called from the main thread, while @ref sayText and/or
|
||
|
* @ref synthText will be called from a separate thread. Hence, it will be
|
||
|
* possible for @ref stopText to be called while @ref sayText or @ref synthText is
|
||
|
* running. Keep this in mind when implementing the code.
|
||
|
*
|
||
|
* If the plugin returns True from @ref supportsAsync, you will of course
|
||
|
* need to deal with similar issues. If you have to use QThreads
|
||
|
* to implement asynchronous support, do not be concerned about emitting
|
||
|
* the @ref sayFinished or @ref synthFinished signals from your threads, since
|
||
|
* KTTSD will convert the received signals into postEvents and
|
||
|
* return immediately.
|
||
|
*
|
||
|
* If it is not possible for @ref stopText to stop an in-progress operation, it
|
||
|
* must not wait for the operation to complete, since this would block KTTSD.
|
||
|
* Instead, simply return immediately. Usually, KTTSD will perform other operations
|
||
|
* while waiting for the plugin to complete its operation. (See threadedplugin.cpp.)
|
||
|
*
|
||
|
* If the @ref stopText implementation returns before the operation has actually
|
||
|
* completed, it must emit the @ref stopped() signal when it is actually completed.
|
||
|
*
|
||
|
* If a plugin returns True from @ref supportsAsync, and @ref stopText is called,
|
||
|
* when the plugin has stopped or completed the operation, it must return psIdle
|
||
|
* on the next call to @ref getState ; not psFinished. The following state diagram
|
||
|
* might be helpful to understand this:
|
||
|
*
|
||
|
@verbatim
|
||
|
psIdle <<----------------------------------------------------------
|
||
|
/ \ ^
|
||
|
psSaying psSynthing --- stopText called and operation completed -->> ^
|
||
|
\ / ^
|
||
|
psFinished --- ackFinished called ------------------------------->> ^
|
||
|
@endverbatim
|
||
|
*
|
||
|
* If your plugin can't immediately stop an in-progress operation, the easiest
|
||
|
* way to handle this is to set a flag when stopText is called, and then in your
|
||
|
* getState() implementation, if the operation has completed, change the
|
||
|
* psFinished state to psIdle, if the flag is set. See the flite plugin for
|
||
|
* example code.
|
||
|
*
|
||
|
* If a plugin returns True from @ref supportsSynth, KTTSD will pass a suggested
|
||
|
* filename in the @ref synthText call. The plugin should synthesize the text
|
||
|
* into an audio file with the suggested name. If the synthesis engine does not
|
||
|
* permit this, i.e., it will pick a filename of its own, that is OK. In either
|
||
|
* case, the actual filename produced should be returned in @ref getFilename .
|
||
|
* In no case may the plugin re-use this filename once @ref getFilename has been
|
||
|
* called. If for some reason the synthesis engine cannot support this, the
|
||
|
* plugin should copy the file to the suggested filename. The file must not be
|
||
|
* locked when @ref getFilename is called. The file will be deleted when
|
||
|
* KTTSD is finished using it.
|
||
|
*
|
||
|
* The preferred audio file format is wave, since this is the only format
|
||
|
* guaranteed to be supported by KDE (aRts). Other formats may or may not be
|
||
|
* supported on a user's machine.
|
||
|
*
|
||
|
* The plugin destructor should take care of terminating the speech engine.
|
||
|
*
|
||
|
* @section Error-handling Error Handling
|
||
|
*
|
||
|
* Plugins may emit the @ref error signal when an error occurs.
|
||
|
*
|
||
|
* When an error occurs, plugins should attempt to recover as best they can and
|
||
|
* continue accepting @ref sayText or @ref synthText calls. For example,
|
||
|
* if a speech engine emits an error in response to certain characters embedded
|
||
|
* in synthesizing text, the plugin should discard the text and
|
||
|
* emit signal @ref error with True as the first argument and the speech
|
||
|
* engine's error message as the second argument. The plugin should then
|
||
|
* treat the operation as a completed operation, i.e., return psFinished when
|
||
|
* @ref getState is called.
|
||
|
*
|
||
|
* If the speech engine crashes, the plugin should emit signal @ref error with
|
||
|
* True as the first argument and then attempt to restart the speech engine.
|
||
|
* The plugin will need to implement some protection against an infinite
|
||
|
* restart loop and emit the @ref error signal with False as the first argument
|
||
|
* if this occurs.
|
||
|
*
|
||
|
* If a plugin emits the @ref error signal with False as the first argument,
|
||
|
* KTTSD will no longer call the plugin.
|
||
|
*
|
||
|
* @section PlugInConf
|
||
|
*
|
||
|
* The plugin should implement a configuration dialog where the user can specify
|
||
|
* options specific to the speech engine. This dialog is displayed in the KDE
|
||
|
* Control Center and also in the KTTS Manager (kttsmgr). See pluginconf.h.
|
||
|
*
|
||
|
* If the user changes any of the settings while the plugin is created,
|
||
|
* the plugin will be destroyed and re-created.
|
||
|
*/
|
||
|
|
||
|
class QTextCodec;
|
||
|
|
||
|
enum pluginState
|
||
|
{
|
||
|
psIdle = 0, /**< Plugin is not doing anything. */
|
||
|
psSaying = 1, /**< Plugin is synthesizing and audibilizing. */
|
||
|
psSynthing = 2, /**< Plugin is synthesizing. */
|
||
|
psFinished = 3 /**< Plugin has finished synthesizing. Audio file is ready. */
|
||
|
};
|
||
|
|
||
|
class KDE_EXPORT PlugInProc : virtual public QObject{
|
||
|
Q_OBJECT
|
||
|
|
||
|
public:
|
||
|
enum CharacterCodec {
|
||
|
Local = 0,
|
||
|
Latin1 = 1,
|
||
|
Unicode = 2,
|
||
|
UseCodec = 3
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*/
|
||
|
PlugInProc( QObject *parent = 0, const char *name = 0);
|
||
|
|
||
|
/**
|
||
|
* Destructor.
|
||
|
* Plugin must terminate the speech engine.
|
||
|
*/
|
||
|
virtual ~PlugInProc();
|
||
|
|
||
|
/**
|
||
|
* Initialize the speech engine.
|
||
|
* @param config Settings object.
|
||
|
* @param configGroup Settings Group.
|
||
|
*
|
||
|
* Sample code for reading configuration:
|
||
|
*
|
||
|
@verbatim
|
||
|
config->setGroup(configGroup);
|
||
|
m_fliteExePath = config->readEntry("FliteExePath", "flite");
|
||
|
kdDebug() << "FliteProc::init: path to flite: " << m_fliteExePath << endl;
|
||
|
config->setGroup(configGroup);
|
||
|
@endverbatim
|
||
|
*/
|
||
|
virtual bool init(KConfig *config, const QString &configGroup);
|
||
|
|
||
|
/**
|
||
|
* Say a text. Synthesize and audibilize it.
|
||
|
* @param text The text to be spoken.
|
||
|
*
|
||
|
* If the plugin supports asynchronous operation, it should return immediately
|
||
|
* and emit sayFinished signal when synthesis and audibilizing is finished.
|
||
|
* It must also implement the @ref getState method, which must return
|
||
|
* psFinished, when saying is completed.
|
||
|
*/
|
||
|
virtual void sayText(const QString &text);
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
* and emit @ref synthFinished signal when synthesis is completed.
|
||
|
* It must also implement the @ref getState method, which must return
|
||
|
* psFinished, when synthesis is completed.
|
||
|
*/
|
||
|
virtual void synthText(const QString &text, const QString &suggestedFilename);
|
||
|
|
||
|
/**
|
||
|
* Get the generated audio filename from call to @ref synthText.
|
||
|
* @return Name of the audio file the plugin generated.
|
||
|
* Null if no such file.
|
||
|
*
|
||
|
* The plugin must not re-use or delete the filename. The file may not
|
||
|
* be locked when this method is called. The file will be deleted when
|
||
|
* KTTSD is finished using it.
|
||
|
*/
|
||
|
virtual QString getFilename();
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
virtual void stopText();
|
||
|
|
||
|
/**
|
||
|
* Return the current state of the plugin.
|
||
|
* This function only makes sense in asynchronous mode.
|
||
|
* @return The pluginState of the plugin.
|
||
|
*
|
||
|
* @see pluginState
|
||
|
*/
|
||
|
virtual pluginState getState();
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
virtual void ackFinished();
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
virtual bool supportsAsync();
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*
|
||
|
* If the plugin returns True, it must also implement the following methods:
|
||
|
* - @ref synthText
|
||
|
* - @ref getFilename
|
||
|
* - @ref ackFinished
|
||
|
*
|
||
|
* If the plugin returns True, it need not implement @ref sayText .
|
||
|
*/
|
||
|
virtual bool supportsSynth();
|
||
|
|
||
|
/**
|
||
|
* Returns the name of an XSLT stylesheet that will convert a valid SSML file
|
||
|
* into a format that can be processed by the synth. For example,
|
||
|
* The Festival plugin returns a stylesheet that will convert SSML into
|
||
|
* SABLE. Any tags the synth cannot handle should be stripped (leaving
|
||
|
* their text contents though). The default stylesheet strips all
|
||
|
* tags and converts the file to plain text.
|
||
|
* @return Name of the XSLT file.
|
||
|
*/
|
||
|
virtual QString getSsmlXsltFilename();
|
||
|
|
||
|
/**
|
||
|
* Given the name of a codec, returns the QTextCodec for the name.
|
||
|
* Handles the following "special" codec names:
|
||
|
* Local The user's current Locale codec.
|
||
|
* Latin1 Latin1 (ISO 8859-1)
|
||
|
* Unicode UTF-16
|
||
|
* @param codecName Name of desired codec.
|
||
|
* @return The codec object. Calling program must not delete this object
|
||
|
* as it is a reference to an existing QTextCodec object.
|
||
|
*
|
||
|
* Caution: Do not pass translated codec names to this routine.
|
||
|
*/
|
||
|
static QTextCodec* codecNameToCodec(const QString &codecName);
|
||
|
|
||
|
/**
|
||
|
* Builds a list of codec names, suitable for display in a QComboBox.
|
||
|
* The list includes the 3 special codec names (translated) at the top:
|
||
|
* Local The user's current Locale codec.
|
||
|
* Latin1 Latin1 (ISO 8859-1)
|
||
|
* Unicode UTF-16
|
||
|
*/
|
||
|
static QStringList buildCodecList();
|
||
|
|
||
|
/**
|
||
|
* Given the name of a codec, returns index into the codec list.
|
||
|
* Handles the following "special" codec names:
|
||
|
* Local The user's current Locale codec.
|
||
|
* Latin1 Latin1 (ISO 8859-1)
|
||
|
* Unicode UTF-16
|
||
|
* @param codecName Name of the codec.
|
||
|
* @param codecList List of codec names. The first 3 entries may be translated names.
|
||
|
* @return QTextCodec object. Caller must not delete this object.
|
||
|
*
|
||
|
* Caution: Do not pass translated codec names to this routine in codecName parameter.
|
||
|
*/
|
||
|
static int codecNameToListIndex(const QString &codecName, const QStringList &codecList);
|
||
|
|
||
|
/**
|
||
|
* Given index into codec list, returns the codec object.
|
||
|
* @param codecNum Index of the codec.
|
||
|
* @param codecList List of codec names. The first 3 entries may be translated names.
|
||
|
* @return QTextCodec object. Caller must not delete this object.
|
||
|
*/
|
||
|
static QTextCodec* codecIndexToCodec(int codecNum, const QStringList &codecList);
|
||
|
|
||
|
/**
|
||
|
* Given index into codec list, returns the codec Name.
|
||
|
* Handles the following "special" codec names:
|
||
|
* Local The user's current Locale codec.
|
||
|
* Latin1 Latin1 (ISO 8859-1)
|
||
|
* Unicode UTF-16
|
||
|
* @param codecNum Index of the codec.
|
||
|
* @param codecList List of codec names. The first 3 entries may be translated names.
|
||
|
* @return Untranslated name of the codec.
|
||
|
*/
|
||
|
static QString codecIndexToCodecName(int codecNum, const QStringList &codecList);
|
||
|
|
||
|
signals:
|
||
|
/**
|
||
|
* Emitted when synthText() finishes and plugin supports asynchronous mode.
|
||
|
*/
|
||
|
void synthFinished();
|
||
|
/**
|
||
|
* Emitted when sayText() finishes and plugin supports asynchronous mode.
|
||
|
*/
|
||
|
void sayFinished();
|
||
|
/**
|
||
|
* Emitted when stopText() has been called and plugin stops asynchronously.
|
||
|
*/
|
||
|
void stopped();
|
||
|
/**
|
||
|
* Emitted if an error occurs.
|
||
|
* @param keepGoing True if the plugin can continue processing.
|
||
|
* False if the plugin cannot continue, for example,
|
||
|
* the speech engine could not be started.
|
||
|
* @param msg Error message.
|
||
|
*
|
||
|
* When an error occurs, plugins should attempt to recover as best they can
|
||
|
* and continue accepting @ref sayText or @ref synthText calls. For example,
|
||
|
* if the speech engine emits an error while synthesizing text, the plugin
|
||
|
* should return True along with error message.
|
||
|
*
|
||
|
* @see Error-handling
|
||
|
*
|
||
|
*/
|
||
|
void error(bool keepGoing, const QString &msg);
|
||
|
};
|
||
|
|
||
|
#endif // _PLUGINPROC_H_
|