[
  {
    "path": ".gitignore",
    "content": "*.pyc\nbuild/\ndist/\npyttsx.egg-info/\n_build/\n"
  },
  {
    "path": "LICENSE",
    "content": "pyttsx Copyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."
  },
  {
    "path": "MANIFEST.in",
    "content": "recursive-include docs *"
  },
  {
    "path": "README.rst",
    "content": "======\npyttsx\n======\n\nCross-platform Python wrapper for text-to-speech synthesis\n\nHelp Wanted\n===========\n\nAs you can probably tell, I have not had time or in some cases the resources (e.g., specific versions of OSes) to maintain pyttsx very well for some time now. If you are using pyttsx in your day to day work and would like to take over as maintainer of the project, please let me know.\n\nQuickstart\n==========\n\n::\n\n   import pyttsx\n   engine = pyttsx.init()\n   engine.say('Greetings!')\n   engine.say('How are you today?')\n   engine.runAndWait()\n\nSee http://pyttsx.readthedocs.org/ for documentation of the full API.\n\nIncluded drivers\n================\n\n* nsss - NSSpeechSynthesizer on Mac OS X 10.5 and higher\n* sapi5 - SAPI5 on Windows XP, Windows Vista, and (untested) Windows 7\n* espeak - eSpeak on any distro / platform that can host the shared library (e.g., Ubuntu / Fedora Linux)\n\nContributing drivers\n====================\n\nEmail the author if you have wrapped or are interested in wrapping another text-to-speech engine for use with pyttsx.\n\nProject links\n=============\n\n* Python Package Index for downloads (http://pypi.python.org/pyttsx)\n* GitHub site for source, bugs, and q&a (https://github.com/parente/pyttsx)\n* ReadTheDocs for docs (http://pyttsx.readthedocs.org)\n\nSee Also\n========\n\nhttps://github.com/parente/espeakbox - espeak in a 16.5 MB Docker container with a simple REST API\n\nLicense\n=======\n\nCopyright (c) 2009, 2013 Peter Parente\nAll rights reserved.\n\nhttp://creativecommons.org/licenses/BSD/\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nPAPER         =\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n\n.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest\n\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html      to make standalone HTML files\"\n\t@echo \"  dirhtml   to make HTML files named index.html in directories\"\n\t@echo \"  pickle    to make pickle files\"\n\t@echo \"  json      to make JSON files\"\n\t@echo \"  htmlhelp  to make HTML files and a HTML help project\"\n\t@echo \"  qthelp    to make HTML files and a qthelp project\"\n\t@echo \"  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  changes   to make an overview of all changed/added/deprecated items\"\n\t@echo \"  linkcheck to check all external links for integrity\"\n\t@echo \"  doctest   to run all doctests embedded in the documentation (if enabled)\"\n\nclean:\n\t-rm -rf _build/*\n\nhtml:\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in _build/html.\"\n\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in _build/dirhtml.\"\n\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in _build/htmlhelp.\"\n\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in _build/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator _build/qthelp/pyttsx.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile _build/qthelp/pyttsx.qhc\"\n\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in _build/latex.\"\n\t@echo \"Run \\`make all-pdf' or \\`make all-ps' in that directory to\" \\\n\t      \"run these through (pdf)latex.\"\n\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes\n\t@echo\n\t@echo \"The overview file is in _build/changes.\"\n\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in _build/linkcheck/output.txt.\"\n\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in _build/doctest/output.txt.\"\n"
  },
  {
    "path": "docs/changelog.rst",
    "content": "Changelog\r\n---------\r\n\r\nVersion 1.2\r\n~~~~~~~~~~~\r\n\r\n* Added pip install instructions to doc.\r\n* Fixed voice selection to use VoiceLocaleIdentifier on OS X instead of deprecated VoiceLanguage\r\n\r\nVersion 1.1\r\n~~~~~~~~~~~\r\n\r\n* Fixed compatibility with pip\r\n* Fixed espeak crash when running on Natty (https://github.com/parente/pyttsx/issues/3)\r\n\r\nVersion 1.0\r\n~~~~~~~~~~~\r\n\r\nFirst release"
  },
  {
    "path": "docs/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# pyttsx documentation build configuration file, created by\n# sphinx-quickstart on Sun Nov  1 09:40:19 2009.\n#\n# This file is execfile()d with the current directory set to its containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport sys, os\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#sys.path.append(os.path.abspath('.'))\n\n# -- General configuration -----------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be extensions\n# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = []\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The encoding of source files.\n#source_encoding = 'utf-8'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'pyttsx'\ncopyright = u'2009, 2013 Peter Parente'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = '1.2'\n# The full version, including alpha/beta/rc tags.\nrelease = '1.2'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of documents that shouldn't be included in the build.\n#unused_docs = []\n\n# List of directories, relative to source directory, that shouldn't be searched\n# for source files.\nexclude_trees = ['_build']\n\n# The reST default role (used for this markup: `text`) to use for all documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n\n# -- Options for HTML output ---------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  Major themes that come with\n# Sphinx are currently 'default' and 'sphinxdoc'.\nhtml_theme = 'default'\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#html_theme_options = {}\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\n#html_logo = None\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\n#html_favicon = None\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_use_modindex = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\nhtml_show_sourcelink = False\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# If nonempty, this is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = ''\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'pyttsxdoc'\n\n\n# -- Options for LaTeX output --------------------------------------------------\n\n# The paper size ('letter' or 'a4').\n#latex_paper_size = 'letter'\n\n# The font size ('10pt', '11pt' or '12pt').\n#latex_font_size = '10pt'\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, documentclass [howto/manual]).\nlatex_documents = [\n  ('index', 'pyttsx.tex', u'pyttsx Documentation',\n   u'Peter Parente', 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# Additional stuff for the LaTeX preamble.\n#latex_preamble = ''\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_use_modindex = True\n"
  },
  {
    "path": "docs/drivers.rst",
    "content": "Implementing drivers\n--------------------\n\nYou can implement new drivers for the :mod:`pyttsx.Engine` by:\n\n#. Creating a Python module with the name of your new driver.\n#. Implementing the required driver factory function and class in your module.\n#. Using methods on a :class:`pyttsx.driver.DriverProxy` instance provided by the :class:`pyttsx.Engine` to control the event queue and notify applications about events.\n\nThe Driver interface\n~~~~~~~~~~~~~~~~~~~~\n\nAll drivers must implement the following factory function and driver interface.\n\n.. module:: pyttsx.drivers\n   :synopsis: The package containing the available driver implementations\n\n.. function:: buildDriver(proxy : pyttsx.driver.DriverProxy) -> pyttsx.drivers.DriverDelegate\n\n   Instantiates delegate subclass declared in this module.\n   \n   :param proxy: Proxy instance provided by a :class:`pyttsx.Engine` instance.\n\n.. class:: DriverDelegate\n   \n   .. note:: The :class:`DriverDelegate` class is not actually declared in :mod:`pyttsx.drivers` and cannot server as a base class. It is only here for the purpose of documenting the interface all drivers must implement.\n\n   .. method:: __init__(proxy : pyttsx.drivers.DriverProxy, *args, **kwargs) -> None\n\n      Constructor. Must store the proxy reference.\n      \n      :param proxy: Proxy instance provided by the :func:`buildDriver` function.\n\n   .. method:: destroy() ->\n   \n      Optional. Invoked by the :class:`pyttsx.driver.DriverProxy` when it is being destroyed so this delegate can clean up any synthesizer resources. If not implemented, the proxy proceeds safely.\n\n   .. method:: endLoop() -> None\n   \n      Immediately ends a running driver event loop.\n   \n   .. method:: getProperty(name : string) -> object\n   \n      Immediately gets the named property value. At least those properties listed in the :meth:`pyttsx.Engine.getProperty` documentation must be supported.\n      \n      :param name: Name of the property to query.\n      :return: Value of the property at the time of this invocation.\n   \n   .. method:: say(text : unicode, name : string) -> None\n   \n      Immediately speaks an utterance. The speech must be output according to the current property values applied at the time of this invocation. Before this method returns, it must invoke :meth:`pyttsx.driver.DriverProxy.setBusy` with value :const:`True` to stall further processing of the command queue until the output completes or is interrupted.\n      \n      This method must trigger one and only one `started-utterance` notification when output begins, one `started-word` notification at the start of each word in the utterance, and a `finished-utterance` notification when output completes.\n      \n      :param text: Text to speak.\n      :param name: Name to associate with the utterance. Included in notifications about this utterance.\n   \n   .. method:: setProperty(name : string, value : object) -> None\n   \n      Immediately sets the named property value. At least those properties listed in the :meth:`pyttsx.Engine.setProperty` documentation must be supported. After setting the property, the driver must invoke :meth:`pyttsx.driver.DriverProxy.setBusy` with value :const:`False` to pump the command queue.\n      \n      :param name: Name of the property to change.\n      :param value: Value to set.\n   \n   .. method:: startLoop()\n   \n      Immediately starts an event loop. The loop is responsible for sending notifications about utterances and pumping the command queue by using methods on the :class:`pyttsx.driver.DriverProxy` object given to the factory function that created this object.\n   \n   .. method:: stop()\n   \n      Immediately stops the current utterance output. This method must trigger a `finished-utterance` notification if called during on-going output. It must trigger no notification if there is no ongoing output. \n      \n      After stopping the output and sending any required notification, the driver must invoke :meth:`pyttsx.driver.DriverProxy.setBusy` with value :const:`False` to pump the command queue.\n\nThe DriverProxy interface\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. module:: pyttsx.driver\n   :synopsis: The module containing the driver proxy implementation\n\nThe :func:`pyttsx.drivers.buildDriver` factory receives an instance of a :class:`DriverProxy` class and provides it to the :class:`pyttsx.drivers.DriverDelegate` it constructs. The driver delegate can invoke the following public methods on the proxy instance. All other public methods found in the code are reserved for use by an :class:`pyttsx.Engine` instance.\n\n.. class:: DriverProxy\n   \n   .. method:: isBusy() -> bool\n   \n      Gets if the proxy is busy and cannot process the next command in the queue or not.\n   \n      :return: True means busy, False means idle.\n\n   .. method:: notify(topic : string, **kwargs) -> None\n   \n      Fires a notification.\n      \n      :param topic: The name of the notification.\n      :kwargs: Name/value pairs associated with the topic.\n   \n   .. method:: setBusy(busy : bool) -> None\n   \n      Sets the proxy to busy so it cannot continue to pump the command queue or idle so it can process the next command.\n      \n      :param busy: True to set busy, false to set idle"
  },
  {
    "path": "docs/engine.rst",
    "content": ".. module:: pyttsx\n   :synopsis: The root pyttsx package defining the engine factory function\n\nUsing pyttsx\n------------\n\nAn application invokes the :func:`pyttsx.init` factory function to get a reference to a :class:`pyttsx.Engine` instance. During construction, the engine initializes a :class:`pyttsx.driver.DriverProxy` object responsible for loading a speech engine driver implementation from the :mod:`pyttsx.drivers` module. After construction, an application uses the engine object to register and unregister event callbacks; produce and stop speech; get and set speech engine properties; and start and stop event loops.\n\nThe Engine factory\n~~~~~~~~~~~~~~~~~~\n\n.. function:: init([driverName : string, debug : bool]) -> pyttsx.Engine\n\n   Gets a reference to an engine instance that will use the given driver. If the requested driver is already in use by another engine instance, that engine is returned. Otherwise, a new engine is created.\n\n   :param driverName: Name of the :mod:`pyttsx.drivers` module to load and use. Defaults to the best available driver for the platform, currently:\n\n      * `sapi5` - SAPI5 on Windows\n      * `nsss` - NSSpeechSynthesizer on Mac OS X\n      * `espeak` - eSpeak on every other platform\n\n   :param debug: Enable debug output or not.\n   :raises ImportError: When the requested driver is not found\n   :raises RuntimeError: When the driver fails to initialize\n\nThe Engine interface\n~~~~~~~~~~~~~~~~~~~~\n\n.. module:: pyttsx.engine\n   :synopsis: The module containing the engine implementation\n\n.. class:: Engine\n\n   Provides application access to text-to-speech synthesis.\n\n   .. method:: connect(topic : string, cb : callable) -> dict\n\n      Registers a callback for notifications on the given topic.\n\n      :param topic: Name of the event to subscribe to.\n      :param cb: Function to invoke when the event fires.\n      :return: A token that the caller can use to unsubscribe the callback later.\n\n      The following are the valid topics and their callback signatures.\n\n      .. describe:: started-utterance\n\n         Fired when the engine begins speaking an utterance. The associated callback must have the folowing signature.\n\n         .. function:: onStartUtterance(name : string) -> None\n\n            :param name: Name associated with the utterance.\n\n      .. describe:: started-word\n\n         Fired when the engine begins speaking a word. The associated callback must have the folowing signature.\n\n         .. function:: onStartWord(name : string, location : integer, length : integer)\n\n            :param name: Name associated with the utterance.\n\n      .. describe:: finished-utterance\n\n         Fired when the engine finishes speaking an utterance. The associated callback must have the folowing signature.\n\n         .. function:: onFinishUtterance(name : string, completed : bool) -> None\n\n            :param name: Name associated with the utterance.\n            :param completed: True if the utterance was output in its entirety or not.\n\n      .. describe:: error\n\n         Fired when the engine encounters an error. The associated callback must have the folowing signature.\n\n         .. function:: onError(name : string, exception : Exception) -> None\n\n            :param name: Name associated with the utterance that caused the error.\n            :param exception: Exception that was raised.\n\n   .. method:: disconnect(token : dict)\n\n      Unregisters a notification callback.\n\n      :param token: Token returned by :meth:`connect` associated with the callback to be disconnected.\n\n   .. method:: endLoop() -> None\n\n      Ends a running event loop. If :meth:`startLoop` was called with `useDriverLoop` set to True, this method stops processing of engine commands and immediately exits the event loop. If it was called with False, this method stops processing of engine commands, but it is up to the caller to end the external event loop it started.\n\n      :raises RuntimeError: When the loop is not running\n\n   .. method:: getProperty(name : string) -> object\n\n      Gets the current value of an engine property.\n\n      :param name: Name of the property to query.\n      :return: Value of the property at the time of this invocation.\n\n      The following property names are valid for all drivers.\n\n      .. describe:: rate\n\n         Integer speech rate in words per minute. Defaults to 200 word per minute.\n\n      .. describe:: voice\n\n         String identifier of the active voice.\n\n      .. describe:: voices\n\n         List of :class:`pyttsx.voice.Voice` descriptor objects.\n\n      .. describe:: volume\n\n         Floating point volume in the range of 0.0 to 1.0 inclusive. Defaults to 1.0.\n\n   .. method:: isBusy() -> bool\n\n      Gets if the engine is currently busy speaking an utterance or not.\n\n      :return: True if speaking, false if not.\n\n   .. method:: runAndWait() -> None\n\n      Blocks while processing all currently queued commands. Invokes callbacks for engine notifications appropriately. Returns when all commands queued before this call are emptied from the queue.\n\n   .. method:: say(text : unicode, name : string) -> None\n\n      Queues a command to speak an utterance. The speech is output according to the properties set before this command in the queue.\n\n      :param text: Text to speak.\n      :param name: Name to associate with the utterance. Included in notifications about this utterance.\n\n   .. method:: setProperty(name, value) -> None\n\n      Queues a command to set an engine property. The new property value affects all utterances queued after this command.\n\n      :param name: Name of the property to change.\n      :param value: Value to set.\n\n      The following property names are valid for all drivers.\n\n      .. describe:: rate\n\n         Integer speech rate in words per minute.\n\n      .. describe:: voice\n\n         String identifier of the active voice.\n\n      .. describe:: volume\n\n         Floating point volume in the range of 0.0 to 1.0 inclusive.\n\n   .. method:: startLoop([useDriverLoop : bool]) -> None\n\n      Starts running an event loop during which queued commands are processed and notifications are fired.\n\n      :param useDriverLoop: True to use the loop provided by the selected driver. False to indicate the caller will enter its own loop after invoking this method. The caller's loop must pump events for the driver in use so that pyttsx notifications are delivered properly (e.g., SAPI5 requires a COM message pump). Defaults to True.\n\n   .. method:: stop() -> None\n\n      Stops the current utterance and clears the command queue.\n\nThe Voice metadata\n~~~~~~~~~~~~~~~~~~\n\n.. module:: pyttsx.voice\n   :synopsis: The module containing the voice structure implementation\n\n.. class:: Voice\n\n   Contains information about a speech synthesizer voice.\n\n   .. attribute:: age\n\n      Integer age of the voice in years. Defaults to :const:`None` if unknown.\n\n   .. attribute:: gender\n\n      String gender of the voice: `male`, `female`, or `neutral`. Defaults to :const:`None` if unknown.\n\n   .. attribute:: id\n\n      String identifier of the voice. Used to set the active voice via :meth:`pyttsx.engine.Engine.setPropertyValue`. This attribute is always defined.\n\n   .. attribute:: languages\n\n      List of string languages supported by this voice. Defaults to an empty list of unknown.\n\n   .. attribute:: name\n\n      Human readable name of the voice. Defaults to :const:`None` if unknown.\n\nExamples\n~~~~~~~~\n\nSpeaking text\n#############\n\n.. sourcecode:: python\n\n   import pyttsx\n   engine = pyttsx.init()\n   engine.say('Sally sells seashells by the seashore.')\n   engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nListening for events\n####################\n\n.. sourcecode:: python\n\n   import pyttsx\n   def onStart(name):\n      print 'starting', name\n   def onWord(name, location, length):\n      print 'word', name, location, length\n   def onEnd(name, completed):\n      print 'finishing', name, completed\n   engine = pyttsx.init()\n   engine.connect('started-utterance', onStart)\n   engine.connect('started-word', onWord)\n   engine.connect('finished-utterance', onEnd)\n   engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nInterrupting an utterance\n#########################\n\n.. sourcecode:: python\n\n   import pyttsx\n   def onWord(name, location, length):\n      print 'word', name, location, length\n      if location > 10:\n         engine.stop()\n   engine = pyttsx.init()\n   engine.connect('started-word', onWord)\n   engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nChanging voices\n###############\n\n.. sourcecode:: python\n\n   engine = pyttsx.init()\n   voices = engine.getProperty('voices')\n   for voice in voices:\n      engine.setProperty('voice', voice.id)\n      engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nChanging speech rate\n####################\n\n.. sourcecode:: python\n\n   engine = pyttsx.init()\n   rate = engine.getProperty('rate')\n   engine.setProperty('rate', rate+50)\n   engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nChanging volume\n###############\n\n.. sourcecode:: python\n\n   engine = pyttsx.init()\n   volume = engine.getProperty('volume')\n   engine.setProperty('volume', volume-0.25)\n   engine.say('The quick brown fox jumped over the lazy dog.')\n   engine.runAndWait()\n\nRunning a driver event loop\n###########################\n\n.. sourcecode:: python\n\n   engine = pyttsx.init()\n   def onStart(name):\n      print 'starting', name\n   def onWord(name, location, length):\n      print 'word', name, location, length\n   def onEnd(name, completed):\n      print 'finishing', name, completed\n      if name == 'fox':\n         engine.say('What a lazy dog!', 'dog')\n      elif name == 'dog':\n         engine.endLoop()\n   engine = pyttsx.init()\n   engine.connect('started-utterance', onStart)\n   engine.connect('started-word', onWord)\n   engine.connect('finished-utterance', onEnd)\n   engine.say('The quick brown fox jumped over the lazy dog.', 'fox')\n   engine.startLoop()\n\nUsing an external event loop\n############################\n\n.. sourcecode:: python\n\n   engine = pyttsx.init()\n   engine.say('The quick brown fox jumped over the lazy dog.', 'fox')\n   engine.startLoop(False)\n   # engine.iterate() must be called inside externalLoop()\n   externalLoop()\n   engine.endLoop()"
  },
  {
    "path": "docs/index.rst",
    "content": "==================================\r\npyttsx - Text-to-speech x-platform\r\n==================================\r\n\r\nThis documentation describes the pyttsx Python package v |release| and was rendered on |today|.\r\n\r\n.. rubric:: Table of Contents\r\n\r\n.. toctree::\r\n   :maxdepth: 2\r\n\r\n   install\r\n   engine\r\n   drivers\r\n   changelog\r\n\r\n.. rubric:: Project Links\r\n\r\n* `Project home page at GitHub`__\r\n* `Package listing in PyPI`__\r\n* `Documentation at ReadTheDocs`__\r\n\r\n__ https://github.com/parente/pyttsx\r\n__ http://pypi.python.org/pypi/pyttsx\r\n__ https://pyttsx.readthedocs.org/"
  },
  {
    "path": "docs/install.rst",
    "content": "Installing pyttsx\n-----------------\n\nTested versions\n~~~~~~~~~~~~~~~\n\nVersion |version| of pyttsx includes drivers for the following text-to-speech synthesizers. Only operating systems on which a driver is tested and known to work are listed. The drivers may work on other systems.\n\n* SAPI5 on Windows XP, Windows Vista, and Windows 7\n* NSSpeechSynthesizer on Mac OS X 10.5 (Leopard), 10.6 (Snow Leopard), 10.7 (Lion), and 10.8 (Mountain Lion).\n* `espeak`_ on 32-bit Ubuntu Desktop Edition 8.10 (Intrepid), 9.04 (Jaunty), 9.10 (Karmic), and 12.04 (Precise).\n\nThe :func:`pyttsx.init` documentation explains how to select a specific synthesizer by name as well as the default for each platform.\n\nUsing pip to install system-wide\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you have pip installed, you can use it to install pyttsx in the system site-packages folder.\n\nOn Windows\n##########\n\nFirst install the `pywin32-extensions <http://sourceforge.net/projects/pywin32/files/pywin32/>`_ package using its Windows installer. Then use pip to install pyttsx.\n\n.. code-block:: bash\n\n   $ pip install pyttsx\n\nOn OSX or Linux\n###############\n\n.. code-block:: bash\n\n   $ sudo pip install pyttsx\n\nUsing pip to install in a virtualenv\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you have virtualenv_ installed with pip_, you can use pip to install a copy of pyttsx in the virtual environment folder.\n\nOn Windows\n##########\n\nYou'll need to install the `pywin32-extensions <http://sourceforge.net/projects/pywin32/files/pywin32/>`_ package system-wide using its Windows installer. Then you'll need to give your virtualenv access to the system site-packages in order to install pyttsx.\n\n.. code-block:: bash\n\n   $ virtualenv --system-site-packages myproj\n   New python executable in myproj/bin/python\n   Installing setuptools............done.\n   Installing pip...............done.\n   $ myproj\\Scripts\\activate\n   (myproj)$ pip install pyttsx\n\nOn OSX\n######\n\nUnless you wish to compile your own version of pyobjc (a lengthy process), you will need to give your virtualenv access to the system site-packages folder.\n\n.. code-block:: bash\n\n   $ virtualenv --system-site-packages myproj\n   New python executable in myproj/bin/python\n   Installing setuptools............done.\n   Installing pip...............done.\n   $ . myproj/bin/activate\n   (myproj)$ pip install pyttsx\n   ...\n   Successfully installed pyttsx\n   Cleaning up...\n\nOn Linux\n########\n\npyttsx requires no Python dependencies on Linux. You can cut-off the pyttsx virtualenv from the system site-packages.\n\ncode-block:: bash\n\n   $ virtualenv --no-site-packages myproj\n   New python executable in myproj/bin/python\n   Installing setuptools............done.\n   Installing pip...............done.\n   $ . myproj/bin/activate\n   (myproj)$ pip install pyttsx\n   ...\n   Successfully installed pyttsx\n   Cleaning up...\n\n\n.. _espeak: http://espeak.sourceforge.net/\n.. _virtualenv: https://pypi.python.org/pypi/virtualenv/1.10.1\n.. _pip: https://pypi.python.org/pypi/pip"
  },
  {
    "path": "pyttsx/__init__.py",
    "content": "'''\npyttsx package.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nfrom __future__ import absolute_import\nfrom .engine import Engine\nimport weakref\n\n_activeEngines = weakref.WeakValueDictionary()\n\ndef init(driverName=None, debug=False):\n    '''\n    Constructs a new TTS engine instance or reuses the existing instance for\n    the driver name.\n\n    @param driverName: Name of the platform specific driver to use. If\n        None, selects the default driver for the operating system.\n    @type: str\n    @param debug: Debugging output enabled or not\n    @type debug: bool\n    @return: Engine instance\n    @rtype: L{engine.Engine}\n    '''\n    try:\n        eng = _activeEngines[driverName]\n    except KeyError:\n        eng = Engine(driverName, debug)\n        _activeEngines[driverName] = eng\n    return eng\n"
  },
  {
    "path": "pyttsx/driver.py",
    "content": "'''\nProxy for drivers.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport sys\nimport traceback\nimport weakref\nimport importlib\n\nclass DriverProxy(object):\n    '''\n    Proxy to a driver implementation.\n\n    @ivar _module: Module containing the driver implementation\n    @type _module: module\n    @ivar _engine: Reference to the engine that owns the driver\n    @type _engine: L{engine.Engine}\n    @ivar _queue: Queue of commands outstanding for the driver\n    @type _queue: list\n    @ivar _busy: True when the driver is busy processing a command, False when\n        not\n    @type _busy: bool\n    @ivar _name: Name associated with the current utterance\n    @type _name: str\n    @ivar _debug: Debugging output enabled or not\n    @type _debug: bool\n    @ivar _iterator: Driver iterator to invoke when in an external run loop\n    @type _iterator: iterator\n    '''\n    def __init__(self, engine, driverName, debug):\n        '''\n        Constructor.\n\n        @param engine: Reference to the engine that owns the driver\n        @type engine: L{engine.Engine}\n        @param driverName: Name of the driver module to use under drivers/ or\n            None to select the default for the platform\n        @type driverName: str\n        @param debug: Debugging output enabled or not\n        @type debug: bool\n        '''\n        if driverName is None:\n            # pick default driver for common platforms\n            if sys.platform == 'darwin':\n                driverName = 'nsss'\n            elif sys.platform == 'win32':\n                driverName = 'sapi5'\n            else:\n                driverName = 'espeak'\n        # import driver module\n        name = 'pyttsx.drivers.%s' % driverName\n        self._module = importlib.import_module(name)\n        # build driver instance\n        self._driver = self._module.buildDriver(weakref.proxy(self))\n        # initialize refs\n        self._engine = engine\n        self._queue = []\n        self._busy = True\n        self._name = None\n        self._iterator = None\n        self._debug = debug\n\n    def __del__(self):\n        try:\n            self._driver.destroy()\n        except (AttributeError, TypeError):\n            pass\n\n    def _push(self, mtd, args, name=None):\n        '''\n        Adds a command to the queue.\n\n        @param mtd: Method to invoke to process the command\n        @type mtd: method\n        @param args: Arguments to apply when invoking the method\n        @type args: tuple\n        @param name: Name associated with the command\n        @type name: str\n        '''\n        self._queue.append((mtd, args, name))\n        self._pump()\n\n    def _pump(self):\n        '''\n        Attempts to process the next command in the queue if one exists and the\n        driver is not currently busy.\n        '''\n        while (not self._busy) and len(self._queue):\n            cmd = self._queue.pop(0)\n            self._name = cmd[2]\n            try:\n                cmd[0](*cmd[1])\n            except Exception as e:\n                self.notify('error', exception=e)\n                if self._debug: traceback.print_exc()\n\n    def notify(self, topic, **kwargs):\n        '''\n        Sends a notification to the engine from the driver.\n\n        @param topic: Notification topic\n        @type topic: str\n        @param kwargs: Arbitrary keyword arguments\n        @type kwargs: dict\n        '''\n        kwargs['name'] = self._name\n        self._engine._notify(topic, **kwargs)\n\n    def setBusy(self, busy):\n        '''\n        Called by the driver to indicate it is busy.\n\n        @param busy: True when busy, false when idle\n        @type busy: bool\n        '''\n        self._busy = busy\n        if not self._busy:\n            self._pump()\n\n    def isBusy(self):\n        '''\n        @return: True if the driver is busy, false if not\n        @rtype: bool\n        '''\n        return self._busy\n\n    def say(self, text, name):\n        '''\n        Called by the engine to push a say command onto the queue.\n\n        @param text: Text to speak\n        @type text: unicode\n        @param name: Name to associate with the utterance\n        @type name: str\n        '''\n        self._push(self._driver.say, (text,), name)\n\n    def stop(self):\n        '''\n        Called by the engine to stop the current utterance and clear the queue\n        of commands.\n        '''\n        # clear queue up to first end loop command\n        while(True):\n            try:\n                mtd, args, name = self._queue[0]\n            except IndexError:\n                break\n            if(mtd == self._engine.endLoop): break\n            self._queue.pop(0)\n        self._driver.stop()\n\n    def getProperty(self, name):\n        '''\n        Called by the engine to get a driver property value.\n\n        @param name: Name of the property\n        @type name: str\n        @return: Property value\n        @rtype: object\n        '''\n        return self._driver.getProperty(name)\n\n    def setProperty(self, name, value):\n        '''\n        Called by the engine to set a driver property value.\n\n        @param name: Name of the property\n        @type name: str\n        @param value: Property value\n        @type value: object\n        '''\n        self._push(self._driver.setProperty, (name, value))\n\n    def runAndWait(self):\n        '''\n        Called by the engine to start an event loop, process all commands in\n        the queue at the start of the loop, and then exit the loop.\n        '''\n        self._push(self._engine.endLoop, tuple())\n        self._driver.startLoop()\n\n    def startLoop(self, useDriverLoop):\n        '''\n        Called by the engine to start an event loop.\n        '''\n        if useDriverLoop:\n            self._driver.startLoop()\n        else:\n            self._iterator = self._driver.iterate()\n\n    def endLoop(self, useDriverLoop):\n        '''\n        Called by the engine to stop an event loop.\n        '''\n        self._queue = []\n        self._driver.stop()\n        if useDriverLoop:\n            self._driver.endLoop()\n        else:\n            self._iterator = None\n        self.setBusy(True)\n\n    def iterate(self):\n        '''\n        Called by the engine to iterate driver commands and notifications from\n        within an external event loop.\n        '''\n        try:\n            next(self._iterator)\n        except StopIteration:\n            pass\n"
  },
  {
    "path": "pyttsx/drivers/__init__.py",
    "content": "'''\nSpeech driver implementations.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''"
  },
  {
    "path": "pyttsx/drivers/_espeak.py",
    "content": "'''espeak.py a thin ctypes wrapper for the espeak dll\n\nGary Bishop\nJuly 2007\nModified October 2007 for the version 2 interface to espeak and more pythonic interfaces\n\nFree for any use.\n'''\n\nfrom __future__ import print_function\nimport ctypes\nfrom ctypes import cdll, c_int, c_char_p, c_wchar_p, POINTER, c_short, c_uint, c_long, c_void_p\nfrom ctypes import CFUNCTYPE, byref, Structure, Union, c_wchar, c_ubyte, c_ulong\nimport time\n\ndef cfunc(name, dll, result, *args):\n    '''build and apply a ctypes prototype complete with parameter flags'''\n    atypes = []\n    aflags = []\n    for arg in args:\n        atypes.append(arg[1])\n        aflags.append((arg[2], arg[0]) + arg[3:])\n    return CFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))\n\ndll = cdll.LoadLibrary('libespeak.so.1')\n\n# constants and such from speak_lib.h\n\nEVENT_LIST_TERMINATED = 0\nEVENT_WORD = 1\nEVENT_SENTENCE = 2\nEVENT_MARK = 3\nEVENT_PLAY = 4\nEVENT_END = 5\nEVENT_MSG_TERMINATED = 6\n\nclass numberORname(Union):\n    _fields_ = [\n        ('number', c_int),\n        ('name', c_char_p)\n        ]\n    \nclass EVENT(Structure):\n    _fields_ = [\n        ('type', c_int),\n        ('unique_identifier', c_uint),\n        ('text_position', c_int),\n        ('length', c_int),\n        ('audio_position', c_int),\n        ('sample', c_int),\n        ('user_data', c_void_p),\n        ('id', numberORname)\n        ]\n    \nAUDIO_OUTPUT_PLAYBACK = 0\nAUDIO_OUTPUT_RETRIEVAL = 1\nAUDIO_OUTPUT_SYNCHRONOUS = 2\nAUDIO_OUTPUT_SYNCH_PLAYBACK = 3\n\nEE_OK = 0\nEE_INTERNAL_ERROR = -1\nEE_BUFFER_FULL = 1\nEE_NOT_FOUND = 2\n\nInitialize = cfunc('espeak_Initialize', dll, c_int,\n                   ('output', c_int, 1, AUDIO_OUTPUT_PLAYBACK),\n                   ('bufflength', c_int, 1, 100),\n                   ('path', c_char_p, 1, None),\n                   ('option', c_int, 1, 0))\nInitialize.__doc__ = '''Must be called before any synthesis functions are called.\n  output: the audio data can either be played by eSpeak or passed back by the SynthCallback function. \n  buflength:  The length in mS of sound buffers passed to the SynthCallback function.\n  path: The directory which contains the espeak-data directory, or NULL for the default location.\n  options: bit 0: 1=allow espeakEVENT_PHONEME events.\n\n  Returns: sample rate in Hz, or -1 (EE_INTERNAL_ERROR).'''\n\nt_espeak_callback = CFUNCTYPE(c_int, POINTER(c_short), c_int, POINTER(EVENT))\n\ncSetSynthCallback = cfunc('espeak_SetSynthCallback', dll, None,\n                        ('SynthCallback', t_espeak_callback, 1))\nSynthCallback = None\ndef SetSynthCallback(cb):\n    global SynthCallback\n    SynthCallback = t_espeak_callback(cb)\n    cSetSynthCallback(SynthCallback)\n\nSetSynthCallback.__doc__ = '''Must be called before any synthesis functions are called.\n   This specifies a function in the calling program which is called when a buffer of\n   speech sound data has been produced. \n\n\n   The callback function is of the form:\n\nint SynthCallback(short *wav, int numsamples, espeak_EVENT *events);\n\n   wav:  is the speech sound data which has been produced.\n      NULL indicates that the synthesis has been completed.\n\n   numsamples: is the number of entries in wav.  This number may vary, may be less than\n      the value implied by the buflength parameter given in espeak_Initialize, and may\n      sometimes be zero (which does NOT indicate end of synthesis).\n\n   events: an array of espeak_EVENT items which indicate word and sentence events, and\n      also the occurance if <mark> and <audio> elements within the text.\n\n\n   Callback returns: 0=continue synthesis,  1=abort synthesis.'''\n\nt_UriCallback = CFUNCTYPE(c_int, c_int, c_char_p, c_char_p)\n\ncSetUriCallback = cfunc('espeak_SetUriCallback', dll, None,\n                       ('UriCallback', t_UriCallback, 1))\nUriCallback = None\ndef SetUriCallback(cb):\n    global UriCallback\n    UriCallback = t_UriCallback(UriCallback)\n    cSetUriCallback(UriCallback)\n\nSetUriCallback.__doc__ = '''This function must be called before synthesis functions are used, in order to deal with\n   <audio> tags.  It specifies a callback function which is called when an <audio> element is\n   encountered and allows the calling program to indicate whether the sound file which\n   is specified in the <audio> element is available and is to be played.\n\n   The callback function is of the form:\n\nint UriCallback(int type, const char *uri, const char *base);\n\n   type:  type of callback event.  Currently only 1= <audio> element\n\n   uri:   the \"src\" attribute from the <audio> element\n\n   base:  the \"xml:base\" attribute (if any) from the <speak> element\n\n   Return: 1=don't play the sound, but speak the text alternative.\n           0=place a PLAY event in the event list at the point where the <audio> element\n             occurs.  The calling program can then play the sound at that point.'''\n\n\n# a few manifest constants\nCHARS_AUTO =  0\nCHARS_UTF8 =  1\nCHARS_8BIT =  2\nCHARS_WCHAR = 3\n\nSSML          = 0x10\nPHONEMES      = 0x100\nENDPAUSE      = 0x1000\nKEEP_NAMEDATA = 0x2000\n\nPOS_CHARACTER = 1\nPOS_WORD      = 2\nPOS_SENTENCE  = 3\n\ndef Synth(text, position=0, position_type=POS_CHARACTER, end_position=0, flags=0):\n    flags |= CHARS_WCHAR\n    text = str(text)\n    return cSynth(text, len(text)*10, position, position_type, end_position, flags, None, None)\n\ncSynth = cfunc('espeak_Synth', dll, c_int,\n              ('text', c_wchar_p, 1),\n              ('size', c_long, 1),\n              ('position', c_uint, 1, 0),\n              ('position_type', c_int, 1, POS_CHARACTER),\n              ('end_position', c_uint, 1, 0),\n              ('flags', c_uint, 1, CHARS_AUTO),\n              ('unique_identifier', POINTER(c_uint), 1, None),\n              ('user_data', c_void_p, 1, None))\nSynth.__doc__ = '''Synthesize speech for the specified text.  The speech sound data is passed to the calling\n   program in buffers by means of the callback function specified by espeak_SetSynthCallback(). The command is asynchronous: it is internally buffered and returns as soon as possible. If espeak_Initialize was previously called with AUDIO_OUTPUT_PLAYBACK as argument, the sound data are played by eSpeak.\n\n   text: The text to be spoken, terminated by a zero character. It may be either 8-bit characters,\n      wide characters (wchar_t), or UTF8 encoding.  Which of these is determined by the \"flags\"\n      parameter.\n\n   size: Equal to (or greatrer than) the size of the text data, in bytes.  This is used in order\n      to allocate internal storage space for the text.  This value is not used for\n      AUDIO_OUTPUT_SYNCHRONOUS mode.\n\n   position:  The position in the text where speaking starts. Zero indicates speak from the\n      start of the text.\n\n   position_type:  Determines whether \"position\" is a number of characters, words, or sentences.\n      Values: \n\n   end_position:  If set, this gives a character position at which speaking will stop.  A value\n      of zero indicates no end position.\n\n   flags:  These may be OR'd together:\n      Type of character codes, one of:\n         espeak.CHARS_UTF8     UTF8 encoding\n         espeak.CHARS_8BIT     The 8 bit ISO-8859 character set for the particular language.\n         espeak.CHARS_AUTO     8 bit or UTF8  (this is the default)\n         espeak.CHARS_WCHAR    Wide characters (wchar_t)\n\n      espeak.SSML   Elements within < > are treated as SSML elements, or if not recognised are ignored.\n\n      espeak.PHONEMES  Text within [[ ]] is treated as phonemes codes (in espeak's Hirschenbaum encoding).\n\n      espeak.ENDPAUSE  If set then a sentence pause is added at the end of the text.  If not set then\n         this pause is suppressed.\n\n   unique_identifier: message identifier; helpful for identifying later \n     data supplied to the callback.\n\n   user_data: pointer which will be passed to the callback function.\n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\ndef Synth_Mark(text, index_mark, end_position=0, flags=CHARS_AUTO):\n    cSynth_Mark(text, len(text)+1, index_mark, end_position, flags)\n\ncSynth_Mark = cfunc('espeak_Synth_Mark', dll, c_int,\n                   ('text', c_char_p, 1),\n                   ('size', c_ulong, 1),\n                   ('index_mark', c_char_p, 1),\n                   ('end_position', c_uint, 1, 0),\n                   ('flags', c_uint, 1, CHARS_AUTO),\n                   ('unique_identifier', POINTER(c_uint), 1, None),\n                   ('user_data', c_void_p, 1, None))\nSynth_Mark.__doc__ = '''Synthesize speech for the specified text.  Similar to espeak_Synth() but the start position is\n   specified by the name of a <mark> element in the text.\n\n   index_mark:  The \"name\" attribute of a <mark> element within the text which specified the\n      point at which synthesis starts.  UTF8 string.\n\n   For the other parameters, see espeak_Synth()\n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\nKey = cfunc('espeak_Key', dll, c_int,\n            ('key_name', c_char_p, 1))\nKey.__doc__ = '''Speak the name of a keyboard key.\n   Currently this just speaks the \"key_name\" as given \n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\nChar = cfunc('espeak_Char', dll, c_int,\n             ('character', c_wchar, 1))\nChar.__doc__ = '''Speak the name of the given character \n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\n# Speech Parameters\nSILENCE=0  #internal use\nRATE=1\nVOLUME=2\nPITCH=3\nRANGE=4\nPUNCTUATION=5\nCAPITALS=6\nEMPHASIS=7   # internal use\nLINELENGTH=8 # internal use\n\nPUNCT_NONE=0\nPUNCT_ALL=1\nPUNCT_SOME=2\n\nSetParameter = cfunc('espeak_SetParameter', dll, c_int,\n                     ('parameter', c_int, 1),\n                     ('value', c_int, 1),\n                     ('relative', c_int, 1, 0))\nSetParameter.__doc__ = '''Sets the value of the specified parameter.\n   relative=0   Sets the absolute value of the parameter.\n   relative=1   Sets a relative value of the parameter.\n\n   parameter:\n      espeak.RATE:    speaking speed in word per minute.\n\n      espeak.VOLUME:  volume in range 0-100    0=silence\n\n      espeak.PITCH:   base pitch, range 0-100.  50=normal\n\n      espeak.RANGE:   pitch range, range 0-100. 0-monotone, 50=normal\n\n      espeak.PUNCTUATION:  which punctuation characters to announce:\n         value in espeak_PUNCT_TYPE (none, all, some), \n\t see espeak_GetParameter() to specify which characters are announced.\n\n      espeak.CAPITALS: announce capital letters by:\n         0=none,\n         1=sound icon,\n         2=spelling,\n         3 or higher, by raising pitch.  This values gives the amount in Hz by which the pitch\n            of a word raised to indicate it has a capital letter.\n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\nGetParameter = cfunc('espeak_GetParameter', dll, c_int,\n                     ('parameter', c_int, 1))\nGetParameter.__doc__ = '''current=0  Returns the default value of the specified parameter.\n   current=1  Returns the current value of the specified parameter, as set by SetParameter()'''\n\nSetPunctuationList = cfunc('espeak_SetPunctuationList', dll, c_int,\n                           ('punctlist', c_wchar, 1))\nSetPunctuationList.__doc__ = '''Specified a list of punctuation characters whose names are to be spoken when the value of the Punctuation parameter is set to \"some\".\n\n   punctlist:  A list of character codes, terminated by a zero character.\n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n                           \nSetPhonemeTrace = cfunc('espeak_SetPhonemeTrace', dll, None,\n                        ('value', c_int, 1),\n                        ('stream', c_void_p, 1))\nSetPhonemeTrace.__doc__ = '''Controls the output of phoneme symbols for the text\n   value=0  No phoneme output (default)\n   value=1  Output the translated phoneme symbols for the text\n   value=2  as (1), but also output a trace of how the translation was done (matching rules and list entries)\n\n   stream   output stream for the phoneme symbols (and trace).  If stream=NULL then it uses stdout.'''\n\nCompileDictionary = cfunc('espeak_CompileDictionary', dll, None,\n                          ('path', c_char_p, 1),\n                          ('log', c_void_p, 1))\nCompileDictionary.__doc__ = '''Compile pronunciation dictionary for a language which corresponds to the currently\n   selected voice.  The required voice should be selected before calling this function.\n\n   path:  The directory which contains the language's '_rules' and '_list' files.\n          'path' should end with a path separator character ('/').\n   log:   Stream for error reports and statistics information. If log=NULL then stderr will be used.'''\n\nclass VOICE(Structure):\n    _fields_ = [\n        ('name', c_char_p),\n        ('languages', c_char_p),\n        ('identifier', c_char_p),\n        ('gender', c_ubyte),\n        ('age', c_ubyte),\n        ('variant', c_ubyte),\n        ('xx1', c_ubyte),\n        ('score', c_int),\n        ('spare', c_void_p),\n        ]\n    def __repr__(self):\n        '''Print the fields'''\n        res = []\n        for field in self._fields_:\n            res.append('%s=%s' % (field[0], repr(getattr(self, field[0]))))\n        return self.__class__.__name__ + '(' + ','.join(res) + ')'\n        \n\ncListVoices = cfunc('espeak_ListVoices', dll, POINTER(POINTER(VOICE)),\n                    ('voice_spec', POINTER(VOICE), 1))\ncListVoices.__doc__ = '''Reads the voice files from espeak-data/voices and creates an array of espeak_VOICE pointers.\n   The list is terminated by a NULL pointer\n\n   If voice_spec is NULL then all voices are listed.\n   If voice spec is given, then only the voices which are compatible with the voice_spec\n   are listed, and they are listed in preference order.'''\n\ndef ListVoices(voice_spec=None):\n    '''Reads the voice files from espeak-data/voices and returns a list of VOICE objects.\n\n   If voice_spec is None then all voices are listed.\n   If voice spec is given, then only the voices which are compatible with the voice_spec\n   are listed, and they are listed in preference order.'''\n    ppv = cListVoices(voice_spec)\n    res = []\n    i = 0\n    while ppv[i]:\n        res.append(ppv[i][0])\n        i += 1\n    return res\n\nSetVoiceByName = cfunc('espeak_SetVoiceByName', dll, c_int,\n                       ('name', c_char_p, 1))\nSetVoiceByName.__doc__ = '''Searches for a voice with a matching \"name\" field.  Language is not considered.\n   \"name\" is a UTF8 string.\n\n   Return: EE_OK: operation achieved \n           EE_BUFFER_FULL: the command can not be buffered; \n             you may try after a while to call the function again.\n\t   EE_INTERNAL_ERROR.'''\n\nSetVoiceByProperties = cfunc('espeak_SetVoiceByProperties', dll, c_int,\n                             ('voice_spec', POINTER(VOICE), 1))\nSetVoiceByProperties.__doc__ = '''An espeak_VOICE structure is used to pass criteria to select a voice.  Any of the following\n   fields may be set:\n\n   name     NULL, or a voice name\n\n   languages  NULL, or a single language string (with optional dialect), eg. \"en-uk\", or \"en\"\n\n   gender   0=not specified, 1=male, 2=female\n\n   age      0=not specified, or an age in years\n\n   variant  After a list of candidates is produced, scored and sorted, \"variant\" is used to index\n            that list and choose a voice.\n            variant=0 takes the top voice (i.e. best match). variant=1 takes the next voice, etc'''\n\nGetCurrentVoice = cfunc('espeak_GetCurrentVoice', dll, POINTER(VOICE),\n                        )\nGetCurrentVoice.__doc__ = '''Returns the espeak_VOICE data for the currently selected voice.\n   This is not affected by temporary voice changes caused by SSML elements such as <voice> and <s>'''\n\nCancel = cfunc('espeak_Cancel', dll, c_int)\nCancel.__doc__ = '''Stop immediately synthesis and audio output of the current text. When this\n   function returns, the audio output is fully stopped and the synthesizer is ready to\n   synthesize a new message.\n\n   Return: EE_OK: operation achieved \n\t   EE_INTERNAL_ERROR.'''\n\nIsPlaying = cfunc('espeak_IsPlaying', dll, c_int)\nIsPlaying.__doc__ = '''Returns 1 if audio is played, 0 otherwise.'''\n\nSynchronize = cfunc('espeak_Synchronize', dll, c_int)\nSynchronize.__doc__ = '''This function returns when all data have been spoken.\n   Return: EE_OK: operation achieved \n\t   EE_INTERNAL_ERROR.'''\n\nTerminate = cfunc('espeak_Terminate', dll, c_int)\nTerminate.__doc__ = '''last function to be called.\n   Return: EE_OK: operation achieved \n\t   EE_INTERNAL_ERROR.'''\n\nInfo = cfunc('espeak_Info', dll, c_char_p,\n             ('ptr', c_void_p, 1, 0))\nInfo.__doc__ = '''Returns the version number string.\n   The parameter is for future use, and should be set to NULL'''\n\nif __name__ == '__main__':\n    def synth_cb(wav, numsample, events):\n        print (numsample, end=' ')\n        i = 0\n        while True:\n            if events[i].type == EVENT_LIST_TERMINATED:\n                break\n            print (events[i].type, end=' ')\n            i += 1\n        print()\n        return 0\n\n    samplerate = Initialize(output=AUDIO_OUTPUT_PLAYBACK)\n    SetSynthCallback(synth_cb)\n    s = 'This is a test, only a test. '\n    uid = c_uint(0)\n    #print ('pitch=',GetParameter(PITCH))\n    #SetParameter(PITCH, 50, 0)\n    print (Synth(s))\n    while IsPlaying():\n        time.sleep(0.1)\n"
  },
  {
    "path": "pyttsx/drivers/dummy.py",
    "content": "'''\nDummy driver that produces no output but gives all expected callbacks. Useful\nfor testing and as a model for real drivers.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nfrom ..voice import Voice\nimport time\n\ndef buildDriver(proxy):\n    '''\n    Builds a new instance of a driver and returns it for use by the driver\n    proxy.\n\n    @param proxy: Proxy creating the driver\n    @type proxy: L{driver.DriverProxy}\n    '''\n    return DummyDriver(proxy)\n\nclass DummyDriver(object):\n    '''\n    Dummy speech engine implementation. Documents the interface, notifications,\n    properties, and sequencing responsibilities of a driver implementation.\n\n    @ivar _proxy: Driver proxy that manages this instance\n    @type _proxy: L{driver.DriverProxy}\n    @ivar _config: Dummy configuration\n    @type _config: dict\n    @ivar _looping: True when in the dummy event loop, False when not\n    @ivar _looping: bool\n    '''\n    def __init__(self, proxy):\n        '''\n        Constructs the driver.\n\n        @param proxy: Proxy creating the driver\n        @type proxy: L{driver.DriverProxy}\n        '''\n        self._proxy = proxy\n        self._looping = False\n        # hold config values as if we had a real tts implementation that\n        # supported them\n        voices = [\n            Voice('dummy.voice1', 'John Doe', ['en-US', 'en-GB'], 'male', 'adult'),\n            Voice('dummy.voice2', 'Jane Doe', ['en-US', 'en-GB'], 'female', 'adult'),\n            Voice('dummy.voice3', 'Jimmy Doe', ['en-US', 'en-GB'], 'male', 10)\n        ]\n        self._config = {\n            'rate' : 200,\n            'volume' : 1.0,\n            'voice' : voices[0],\n            'voices' : voices\n        }\n\n    def destroy(self):\n        '''\n        Optional method that will be called when the driver proxy is being\n        destroyed. Can cleanup any resources to make sure the engine terminates\n        properly.\n        '''\n        pass\n\n    def startLoop(self):\n        '''\n        Starts a blocking run loop in which driver callbacks are properly\n        invoked.\n\n        @precondition: There was no previous successful call to L{startLoop}\n            without an intervening call to L{stopLoop}.\n        '''\n        first = True\n        self._looping = True\n        while self._looping:\n            if first:\n                self._proxy.setBusy(False)\n                first = False\n            time.sleep(0.5)\n\n    def endLoop(self):\n        '''\n        Stops a previously started run loop.\n\n        @precondition: A previous call to L{startLoop} suceeded and there was\n            no intervening call to L{endLoop}.\n        '''\n        self._looping = False\n\n    def iterate(self):\n        '''\n        Iterates from within an external run loop.\n        '''\n        self._proxy.setBusy(False)\n        yield\n\n    def say(self, text):\n        '''\n        Speaks the given text. Generates the following notifications during\n        output:\n\n        started-utterance: When speech output has started\n        started-word: When a word is about to be spoken. Includes the character\n            \"location\" of the start of the word in the original utterance text\n            and the \"length\" of the word in characters.\n        finished-utterance: When speech output has finished. Includes a flag\n            indicating if the entire utterance was \"completed\" or not.\n\n        The proxy automatically adds any \"name\" associated with the utterance\n        to the notifications on behalf of the driver.\n\n        When starting to output an utterance, the driver must inform its proxy\n        that it is busy by invoking L{driver.DriverProxy.setBusy} with a flag\n        of True. When the utterance completes or is interrupted, the driver\n        inform the proxy that it is no longer busy by invoking\n        L{driver.DriverProxy.setBusy} with a flag of False.\n\n        @param text: Unicode text to speak\n        @type text: unicode\n        '''\n        self._proxy.setBusy(True)\n        self._proxy.notify('started-utterance')\n        i = 0\n        for word in text.split(' '):\n            self._proxy.notify('started-word', location=i, length=len(word))\n            try:\n                i = text.index(' ', i+1)+1\n            except Exception:\n                pass\n        self._proxy.notify('finished-utterance', completed=True)\n        self._proxy.setBusy(False)\n\n    def stop(self):\n        '''\n        Stops any current output. If an utterance was being spoken, the driver\n        is still responsible for sending the closing finished-utterance\n        notification documented above and resetting the busy state of the\n        proxy.\n        '''\n        pass\n\n    def getProperty(self, name):\n        '''\n        Gets a property value of the speech engine. The suppoted properties\n        and their values are:\n\n        voices: List of L{voice.Voice} objects supported by the driver\n        voice: String ID of the current voice\n        rate: Integer speech rate in words per minute\n        volume: Floating point volume of speech in the range [0.0, 1.0]\n\n        @param name: Property name\n        @type name: str\n        @raise KeyError: When the property name is unknown\n        '''\n        try:\n            return self._config[name]\n        except KeyError:\n            raise KeyError('unknown property %s' % name)\n\n    def setProperty(self, name, value):\n        '''\n        Sets one of the supported property values of the speech engine listed\n        above. If a value is invalid, attempts to clip it / coerce so it is\n        valid before giving up and firing an exception.\n\n        @param name: Property name\n        @type name: str\n        @param value: Property value\n        @type value: object\n        @raise KeyError: When the property name is unknown\n        @raise ValueError: When the value cannot be coerced to fit the property\n        '''\n        if name == 'voice':\n            v = [v for v in self._config['voices'] if v.id == value]\n            self._config['voice'] = v[0]\n        elif name == 'rate':\n            self._config['rate'] = value\n        elif name == 'volume':\n            self._config['volume'] = value\n        else:\n            raise KeyError('unknown property %s' % name)\n"
  },
  {
    "path": "pyttsx/drivers/espeak.py",
    "content": "'''\nespeak driver.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nfrom __future__ import absolute_import\nimport ctypes\nfrom . import _espeak\nfrom ..voice import Voice\nimport time\n\ndef buildDriver(proxy):\n    return EspeakDriver(proxy)\n\nclass EspeakDriver(object):\n    _moduleInitialized = False\n    _defaultVoice = ''\n    def __init__(self, proxy):\n        if not EspeakDriver._moduleInitialized:\n            # espeak cannot initialize more than once per process and has\n            # issues when terminating from python (assert error on close)\n            # so just keep it alive and init once\n            rate = _espeak.Initialize(_espeak.AUDIO_OUTPUT_PLAYBACK, 1000)\n            if rate == -1:\n                raise RuntimeError('could not initialize espeak')\n            EspeakDriver._defaultVoice = self.getProperty('voice')\n            EspeakDriver._moduleInitialized = True\n        _espeak.SetSynthCallback(self._onSynth)\n        # make sure all props reset\n        self.setProperty('voice', EspeakDriver._defaultVoice)\n        self.setProperty('rate', 200)\n        self.setProperty('volume', 1.0)\n        self._proxy = proxy\n        self._looping = True\n        self._stopping = False\n\n    def destroy(self):\n        _espeak.SetSynthCallback(None)\n\n    def say(self, text):\n        self._proxy.setBusy(True)\n        self._proxy.notify('started-utterance')\n        _espeak.Synth(text, flags=_espeak.ENDPAUSE)\n\n    def stop(self):\n        if _espeak.IsPlaying():\n            self._stopping = True\n\n    def getProperty(self, name):\n        if name == 'voices':\n            voices = []\n            for v in _espeak.ListVoices(None):\n                kwargs = {}\n                kwargs['id'] = v.name\n                kwargs['name'] = v.name\n                if v.languages:\n                    kwargs['languages'] = [v.languages]\n                genders = [None, 'male', 'female']\n                kwargs['gender'] = genders[v.gender]\n                kwargs['age'] = v.age or None\n                voices.append(Voice(**kwargs))\n            return voices\n        elif name == 'voice':\n            return _espeak.GetCurrentVoice().contents.name\n        elif name == 'rate':\n            return _espeak.GetParameter(_espeak.RATE)\n        elif name == 'volume':\n            return _espeak.GetParameter(_espeak.VOLUME)/100.0\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def setProperty(self, name, value):\n        if name == 'voice':\n            if value is None: return\n            try:\n                _espeak.SetVoiceByName(value)\n            except ctypes.ArgumentError as e:\n                raise ValueError(str(e))\n        elif name == 'rate':\n            try:\n                _espeak.SetParameter(_espeak.RATE, value, 0)\n            except ctypes.ArgumentError as e:\n                raise ValueError(str(e))\n        elif name == 'volume':\n            try:\n                _espeak.SetParameter(_espeak.VOLUME, int(round(value*100, 2)), 0)\n            except TypeError as e:\n                raise ValueError(str(e))\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def startLoop(self):\n        first = True\n        self._looping = True\n        while self._looping:\n            if first:\n                # kick the queue\n                self._proxy.setBusy(False)\n                first = False\n            if self._stopping:\n                # have to do the cancel on the main thread, not inside the\n                # callback else deadlock\n                _espeak.Cancel()\n                self._stopping = False\n                self._proxy.notify('finished-utterance', completed=False)\n                self._proxy.setBusy(False)\n            time.sleep(0.01)\n\n    def endLoop(self):\n        self._looping = False\n\n    def iterate(self):\n        self._proxy.setBusy(False)\n        while 1:\n            if self._stopping:\n                # have to do the cancel on the main thread, not inside the\n                # callback else deadlock\n                _espeak.Cancel()\n                self._stopping = False\n                self._proxy.notify('finished-utterance', completed=False)\n                self._proxy.setBusy(False)\n            yield\n\n    def _onSynth(self, wav, numsamples, events):\n        i = 0\n        while True:\n            event = events[i]\n            if event.type == _espeak.EVENT_LIST_TERMINATED:\n                break\n            if event.type == _espeak.EVENT_WORD:\n                self._proxy.notify('started-word',\n                    location=event.text_position-1,\n                    length=event.length)\n            elif event.type == _espeak.EVENT_MSG_TERMINATED:\n                self._proxy.notify('finished-utterance', completed=True)\n                self._proxy.setBusy(False)\n            i += 1\n        return 0\n"
  },
  {
    "path": "pyttsx/drivers/nsss.py",
    "content": "'''\nNSSpeechSynthesizer driver.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nfrom Foundation import *\nfrom AppKit import NSSpeechSynthesizer\nfrom PyObjCTools import AppHelper\nfrom ..voice import Voice\n\ndef buildDriver(proxy):\n    return NSSpeechDriver.alloc().initWithProxy(proxy)\n\nclass NSSpeechDriver(NSObject):\n    def initWithProxy(self, proxy):\n        self = super(NSSpeechDriver, self).init()\n        if self:\n            self._proxy = proxy\n            self._tts = NSSpeechSynthesizer.alloc().initWithVoice_(None)\n            self._tts.setDelegate_(self)\n            # default rate\n            self._tts.setRate_(200)\n            self._completed = True\n        return self\n\n    def destroy(self):\n        self._tts.setDelegate_(None)\n        del self._tts\n\n    def onPumpFirst_(self, timer):\n        self._proxy.setBusy(False)\n\n    def startLoop(self):\n        NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(\n            0.0, self, 'onPumpFirst:', None, False)\n        AppHelper.runConsoleEventLoop()\n\n    def endLoop(self):\n        AppHelper.stopEventLoop()\n\n    def iterate(self):\n        self._proxy.setBusy(False)\n        yield\n\n    def say(self, text):\n        self._proxy.setBusy(True)\n        self._completed = True\n        self._proxy.notify('started-utterance')\n        self._tts.startSpeakingString_(str(text))\n\n    def stop(self):\n        if self._proxy.isBusy():\n            self._completed = False\n        self._tts.stopSpeaking()\n\n    def _toVoice(self, attr):\n        try:\n            lang = attr['VoiceLocaleIdentifier']\n        except KeyError:\n            lang = attr['VoiceLanguage']\n        return Voice(attr['VoiceIdentifier'], attr['VoiceName'],\n                     [lang], attr['VoiceGender'],\n                     attr['VoiceAge'])\n\n    def getProperty(self, name):\n        if name == 'voices':\n            return [self._toVoice(NSSpeechSynthesizer.attributesForVoice_(v))\n                     for v in list(NSSpeechSynthesizer.availableVoices())]\n        elif name == 'voice':\n            return self._tts.voice()\n        elif name == 'rate':\n            return self._tts.rate()\n        elif name == 'volume':\n            return self._tts.volume()\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def setProperty(self, name, value):\n        if name == 'voice':\n            # vol/rate gets reset, so store and restore it\n            vol = self._tts.volume()\n            rate = self._tts.rate()\n            self._tts.setVoice_(value)\n            self._tts.setRate_(rate)\n            self._tts.setVolume_(vol)\n        elif name == 'rate':\n            self._tts.setRate_(value)\n        elif name == 'volume':\n            self._tts.setVolume_(value)\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def speechSynthesizer_didFinishSpeaking_(self, tts, success):\n        if not self._completed:\n            success = False\n        else:\n            success = True\n        self._proxy.notify('finished-utterance', completed=success)\n        self._proxy.setBusy(False)\n\n    def speechSynthesizer_willSpeakWord_ofString_(self, tts, rng, text):\n        self._proxy.notify('started-word', location=rng.location,\n            length=rng.length)\n"
  },
  {
    "path": "pyttsx/drivers/sapi5.py",
    "content": "'''\nSAPI 5+ driver.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\n#import comtypes.client\nimport win32com.client\nimport pythoncom\nimport time\nimport math\nimport weakref\nfrom ..voice import Voice\n\n# common voices\nMSSAM = 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Speech\\\\Voices\\\\Tokens\\\\MSSam'\nMSMARY = 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Speech\\\\Voices\\\\Tokens\\\\MSMary'\nMSMIKE = 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Speech\\\\Voices\\\\Tokens\\\\MSMike'\n\n# coeffs for wpm conversion\nE_REG = {MSSAM : (137.89, 1.11),\n         MSMARY : (156.63, 1.11),\n         MSMIKE : (154.37, 1.11)}\n\ndef buildDriver(proxy):\n    return SAPI5Driver(proxy)\n\nclass SAPI5Driver(object):\n    def __init__(self, proxy):\n        self._tts = win32com.client.Dispatch('SAPI.SPVoice')\n        #self._tts = comtypes.client.CreateObject('SAPI.SPVoice')\n        # all events\n        self._tts.EventInterests = 33790\n        self._advise = win32com.client.WithEvents(self._tts,\n            SAPI5DriverEventSink)\n        self._advise.setDriver(weakref.proxy(self))\n        #self._debug = comtypes.client.ShowEvents(self._tts)\n        #self._advise = comtypes.client.GetEvents(self._tts, self)\n        self._proxy = proxy\n        self._looping = False\n        self._speaking = False\n        self._stopping = False\n        # initial rate\n        self._rateWpm = 200\n        self.setProperty('voice', self.getProperty('voice'))\n\n    def destroy(self):\n        self._tts.EventInterests = 0\n\n    def say(self, text):\n        self._proxy.setBusy(True)\n        self._proxy.notify('started-utterance')\n        self._speaking = True\n        self._tts.Speak(str(text), 19)\n\n    def stop(self):\n        if not self._speaking:\n            return\n        self._proxy.setBusy(True)\n        self._stopping = True\n        self._tts.Speak('', 3)\n\n    def _toVoice(self, attr):\n        return Voice(attr.Id, attr.GetDescription())\n\n    def _tokenFromId(self, id):\n        tokens = self._tts.GetVoices()\n        for token in tokens:\n            if token.Id == id: return token\n        raise ValueError('unknown voice id %s', id)\n\n    def getProperty(self, name):\n        if name == 'voices':\n            return [self._toVoice(attr) for attr in self._tts.GetVoices()]\n        elif name == 'voice':\n            return self._tts.Voice.Id\n        elif name == 'rate':\n            return self._rateWpm\n        elif name == 'volume':\n            return self._tts.Volume/100.0\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def setProperty(self, name, value):\n        if name == 'voice':\n            token = self._tokenFromId(value)\n            self._tts.Voice = token\n            a, b = E_REG.get(value, E_REG[MSMARY])\n            self._tts.Rate = int(math.log(self._rateWpm/a, b))\n        elif name == 'rate':\n            id = self._tts.Voice.Id\n            a, b = E_REG.get(id, E_REG[MSMARY])\n            try:\n                self._tts.Rate = int(math.log(value/a, b))\n            except TypeError as e:\n                raise ValueError(str(e))\n            self._rateWpm = value\n        elif name == 'volume':\n            try:\n                self._tts.Volume = int(round(value*100, 2))\n            except TypeError as e:\n                raise ValueError(str(e))\n        else:\n            raise KeyError('unknown property %s' % name)\n\n    def startLoop(self):\n        first = True\n        self._looping = True\n        while self._looping:\n            if first:\n                self._proxy.setBusy(False)\n                first = False\n            pythoncom.PumpWaitingMessages()\n            time.sleep(0.05)\n\n    def endLoop(self):\n        self._looping = False\n\n    def iterate(self):\n        self._proxy.setBusy(False)\n        while 1:\n            pythoncom.PumpWaitingMessages()\n            yield\n\nclass SAPI5DriverEventSink(object):\n    def __init__(self):\n        self._driver = None\n\n    def setDriver(self, driver):\n        self._driver = driver\n\n    def OnWord(self, stream, pos, char, length):\n        self._driver._proxy.notify('started-word', location=char, length=length)\n\n    def OnEndStream(self, stream, pos):\n        d = self._driver\n        if d._speaking:\n            d._proxy.notify('finished-utterance', completed=not d._stopping)\n        d._speaking = False\n        d._stopping = False\n        d._proxy.setBusy(False)\n"
  },
  {
    "path": "pyttsx/engine.py",
    "content": "'''\nSpeech engine front-end.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nfrom __future__ import absolute_import\nfrom . import driver\nimport traceback\nimport weakref\n\nclass Engine(object):\n    '''\n    @ivar proxy: Proxy to a driver implementation\n    @type proxy: L{DriverProxy}\n    @ivar _connects: Array of subscriptions\n    @type _connects: list\n    @ivar _inLoop: Running an event loop or not\n    @type _inLoop: bool\n    @ivar _driverLoop: Using a driver event loop or not\n    @type _driverLoop: bool\n    @ivar _debug: Print exceptions or not\n    @type _debug: bool\n    '''\n    def __init__(self, driverName=None, debug=False):\n        '''\n        Constructs a new TTS engine instance.\n\n        @param driverName: Name of the platform specific driver to use. If\n            None, selects the default driver for the operating system.\n        @type: str\n        @param debug: Debugging output enabled or not\n        @type debug: bool\n        '''\n        self.proxy = driver.DriverProxy(weakref.proxy(self), driverName, debug)\n        # initialize other vars\n        self._connects = {}\n        self._inLoop = False\n        self._driverLoop = True\n        self._debug = debug\n\n    def _notify(self, topic, **kwargs):\n        '''\n        Invokes callbacks for an event topic.\n\n        @param topic: String event name\n        @type topic: str\n        @param kwargs: Values associated with the event\n        @type kwargs: dict\n        '''\n        for cb in self._connects.get(topic, []):\n            try:\n                cb(**kwargs)\n            except Exception as e:\n                if self._debug: traceback.print_exc()\n\n    def connect(self, topic, cb):\n        '''\n        Registers a callback for an event topic. Valid topics and their\n        associated values:\n\n        started-utterance: name=<str>\n        started-word: name=<str>, location=<int>, length=<int>\n        finished-utterance: name=<str>, completed=<bool>\n        error: name=<str>, exception=<exception>\n\n        @param topic: Event topic name\n        @type topic: str\n        @param cb: Callback function\n        @type cb: callable\n        @return: Token to use to unregister\n        @rtype: dict\n        '''\n        arr = self._connects.setdefault(topic, [])\n        arr.append(cb)\n        return {'topic' : topic, 'cb' : cb}\n\n    def disconnect(self, token):\n        '''\n        Unregisters a callback for an event topic.\n\n        @param token: Token of the callback to unregister\n        @type token: dict\n        '''\n        topic = token['topic']\n        try:\n            arr = self._connects[topic]\n        except KeyError:\n            return\n        arr.remove(token['cb'])\n        if len(arr) == 0:\n            del self._connects[topic]\n\n    def say(self, text, name=None):\n        '''\n        Adds an utterance to speak to the event queue.\n\n        @param text: Text to sepak\n        @type text: unicode\n        @param name: Name to associate with this utterance. Included in\n            notifications about this utterance.\n        @type name: str\n        '''\n        self.proxy.say(text, name)\n\n    def stop(self):\n        '''\n        Stops the current utterance and clears the event queue.\n        '''\n        self.proxy.stop()\n\n    def isBusy(self):\n        '''\n        @return: True if an utterance is currently being spoken, false if not\n        @rtype: bool\n        '''\n        return self.proxy.isBusy()\n\n    def getProperty(self, name):\n        '''\n        Gets the current value of a property. Valid names and values include:\n\n        voices: List of L{voice.Voice} objects supported by the driver\n        voice: String ID of the current voice\n        rate: Integer speech rate in words per minute\n        volume: Floating point volume of speech in the range [0.0, 1.0]\n\n        Numeric values outside the valid range supported by the driver are\n        clipped.\n\n        @param name: Name of the property to fetch\n        @type name: str\n        @return: Value associated with the property\n        @rtype: object\n        @raise KeyError: When the property name is unknown\n        '''\n        return self.proxy.getProperty(name)\n\n    def setProperty(self, name, value):\n        '''\n        Adds a property value to set to the event queue. Valid names and values\n        include:\n\n        voice: String ID of the voice\n        rate: Integer speech rate in words per minute\n        volume: Floating point volume of speech in the range [0.0, 1.0]\n\n        Numeric values outside the valid range supported by the driver are\n        clipped.\n\n        @param name: Name of the property to fetch\n        @type name: str\n        @param: Value to set for the property\n        @rtype: object\n        @raise KeyError: When the property name is unknown\n        '''\n        self.proxy.setProperty(name, value)\n\n    def runAndWait(self):\n        '''\n        Runs an event loop until all commands queued up until this method call\n        complete. Blocks during the event loop and returns when the queue is\n        cleared.\n\n        @raise RuntimeError: When the loop is already running\n        '''\n        if self._inLoop:\n            raise RuntimeError('run loop already started')\n        self._inLoop = True\n        self._driverLoop = True\n        self.proxy.runAndWait()\n\n    def startLoop(self, useDriverLoop=True):\n        '''\n        Starts an event loop to process queued commands and callbacks.\n\n        @param useDriverLoop: If True, uses the run loop provided by the driver\n            (the default). If False, assumes the caller will enter its own\n            run loop which will pump any events for the TTS engine properly.\n        @type useDriverLoop: bool\n        @raise RuntimeError: When the loop is already running\n        '''\n        if self._inLoop:\n            raise RuntimeError('run loop already started')\n        self._inLoop = True\n        self._driverLoop = useDriverLoop\n        self.proxy.startLoop(self._driverLoop)\n\n    def endLoop(self):\n        '''\n        Stops a running event loop.\n\n        @raise RuntimeError: When the loop is not running\n        '''\n        if not self._inLoop:\n            raise RuntimeError('run loop not started')\n        self.proxy.endLoop(self._driverLoop)\n        self._inLoop = False\n\n    def iterate(self):\n        '''\n        Must be called regularly when using an external event loop.\n        '''\n        if not self._inLoop:\n            raise RuntimeError('run loop not started')\n        elif self._driverLoop:\n            raise RuntimeError('iterate not valid in driver run loop')\n        self.proxy.iterate()\n"
  },
  {
    "path": "pyttsx/voice.py",
    "content": "'''\nVoice metadata definition.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nclass Voice(object):\n    def __init__(self, id, name=None, languages=[], gender=None, age=None):\n        self.id = id\n        self.name = name\n        self.languages = languages\n        self.gender = gender\n        self.age = age\n\n    def __str__(self):\n        return '''<Voice id=%(id)s\n          name=%(name)s\n          languages=%(languages)s\n          gender=%(gender)s\n          age=%(age)s>''' % self.__dict__"
  },
  {
    "path": "setup.py",
    "content": "'''\r\npyttsx setup script.\r\n\r\nCopyright (c) 2009, 2013 Peter Parente\r\n\r\nPermission to use, copy, modify, and distribute this software for any\r\npurpose with or without fee is hereby granted, provided that the above\r\ncopyright notice and this permission notice appear in all copies.\r\n\r\nTHE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r\n'''\r\nimport platform\r\nfrom setuptools import setup\r\n\r\ninstall_requires = []\r\nif platform.system() == 'Windows':\r\n    install_requires = [\r\n        'win32com'\r\n    ]\r\nelif platform.system() == 'Darwin':\r\n    install_requires = [\r\n        'pyobjc>=2.4'\r\n    ]\r\n\r\nsetup(name='pyttsx',\r\n      version='1.2',\r\n      description='pyttsx - cross platform text-to-speech',\r\n      long_description='pyttsx is a Python package supporting common text-to-speech engines on Mac OS X, Windows, and Linux.',\r\n      author='Peter Parente',\r\n      author_email='parente@cs.unc.edu',\r\n      url='https://github.com/parente/pyttsx',\r\n      download_url='http://pypi.python.org/pypi/pyttsx',\r\n      license='BSD License',\r\n      packages=['pyttsx', 'pyttsx.drivers'],\r\n      install_requires=install_requires\r\n)"
  },
  {
    "path": "tests/manual/run.py",
    "content": "import os\nimport sys\nsys.path.insert(0, os.path.join('..', '..'))\nimport pyttsx\nimport time\n\ncount = 0\n\ndef started(name):\n    print 'started', name\n\ndef word(location, length, name):\n    print 'word', location, length, name\n\ndef finished(completed, name):\n    print 'finished', completed, name\n    engine.endLoop()\n\nengine = pyttsx.Engine()\nengine.connect('started-utterance', started)\nengine.connect('finished-utterance', finished)\nengine.connect('started-word', word)\nprint engine.getProperty('rate')\nprint engine.getProperty('volume')\nprint engine.getProperty('voice')\nprint [v.id for v in engine.getProperty('voices')]\n#engine.stop()\nengine.say('Hello out there. This is a test.', 'utter1')\nengine.say('Hello out there again.', 'utter2')\n#engine.setProperty('voice', vs[2].id)\n#engine.say('This is another one.', 'utter2')\n#engine.runAndWait()\nengine.startLoop()\n#engine.startLoop()\ntime.sleep(2)"
  },
  {
    "path": "tests/unit/test_all.py",
    "content": "'''\nRuns all unit tests.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport unittest\nimport test_say\nimport test_prop\nimport test_lifecycle\n\ndef suite():\n    suite = unittest.TestSuite([\n        test_lifecycle.suite(),\n        test_prop.suite(),\n        test_say.suite()\n    ])\n    return suite\n\nif __name__ == '__main__':\n    unittest.TextTestRunner(verbosity=2).run(suite())"
  },
  {
    "path": "tests/unit/test_lifecycle.py",
    "content": "'''\nTests lifecycle.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport unittest\nimport test_setup\nimport pyttsx\n\nclass TestLifecycle(unittest.TestCase):\n    def setUp(self):\n        self.engine = pyttsx.init()\n\n    def tearDown(self):\n        del self.engine\n\n    def testSeparateDrivers(self):\n        self.engine2 = pyttsx.init('dummy')\n        self.assert_(self.engine != self.engine2)\n        del self.engine2\n\n    def testReuseDriver(self):\n        self.engine2 = pyttsx.init()\n        self.assert_(self.engine == self.engine2)\n        del self.engine2\n\ndef suite():\n    suite = unittest.TestLoader().loadTestsFromTestCase(TestLifecycle)\n    #suite = unittest.TestLoader().loadTestsFromName('testBadVoice', TestProperties)\n    return suite\n\nif __name__ == '__main__':\n    unittest.TextTestRunner(verbosity=2).run(suite())"
  },
  {
    "path": "tests/unit/test_prop.py",
    "content": "'''\nTests properties.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport unittest\nimport test_setup\nimport pyttsx\n\nclass TestProperties(unittest.TestCase):\n    def setUp(self):\n        self.engine = pyttsx.init(debug=False)\n\n    def tearDown(self):\n        del self.engine\n\n    def testDefaults(self):\n        voices = self.engine.getProperty('voices')\n        drate = 200\n        dvolume = 1.0\n\n        rate = self.engine.getProperty('rate')\n        self.assert_(drate == rate)\n        volume = self.engine.getProperty('volume')\n        self.assert_(dvolume == volume)\n        voice = self.engine.getProperty('voice')\n        self.assert_(voice in [v.id for v in voices])\n\n    def testSetRate(self):\n        for rate in xrange(100, 400, 10):\n            self.engine.setProperty('rate', rate)\n            self.engine.runAndWait()\n            grate = self.engine.getProperty('rate')\n            self.assert_(rate == grate)\n\n    def testSetVoice(self):\n        voices = self.engine.getProperty('voices')\n        for voice in voices:\n            self.engine.setProperty('voice', voice.id)\n            self.engine.runAndWait()\n            gvoice = self.engine.getProperty('voice')\n            self.assert_(voice.id == gvoice)\n\n    def testSetVolume(self):\n        for volume in xrange(0, 100, 1):\n            volume /= 100.0\n            self.engine.setProperty('volume', volume)\n            self.engine.runAndWait()\n            gvolume = self.engine.getProperty('volume')\n            self.assertAlmostEqual(volume, gvolume, 4)\n\n    def testSetMultiple(self):\n        voices = self.engine.getProperty('voices')\n        self.engine.setProperty('volume', 0.5)\n        self.engine.setProperty('rate', 300)\n        self.engine.setProperty('voice', voices[0].id)\n        self.engine.runAndWait()\n        gvoice = self.engine.getProperty('voice')\n        self.assert_(gvoice == voices[0].id)\n        gvolume = self.engine.getProperty('volume')\n        self.assertAlmostEqual(gvolume, 0.5, 4)\n        grate = self.engine.getProperty('rate')\n        self.assert_(grate == 300)\n\n    def testBadVolume(self):\n        errors = []\n        def errback(exception, name):\n            errors.append(exception)\n        tok = self.engine.connect('error', errback)\n        self.engine.setProperty('volume', 'foobar')\n        self.engine.setProperty('volume', None)\n        self.engine.setProperty('volume', object())\n        self.engine.runAndWait()\n        self.engine.disconnect(tok)\n        for error in errors:\n            self.assert_(isinstance(error, ValueError))\n\n    def testBadRate(self):\n        errors = []\n        def errback(exception, name):\n            errors.append(exception)\n        tok = self.engine.connect('error', errback)\n        self.engine.setProperty('rate', 'foobar')\n        self.engine.setProperty('rate', None)\n        self.engine.setProperty('rate', object())\n        self.engine.runAndWait()\n        self.engine.disconnect(tok)\n        for error in errors:\n            self.assert_(isinstance(error, ValueError))\n\n    def testBadVoice(self):\n        errors = []\n        def errback(exception, name):\n            errors.append(exception)\n        tok = self.engine.connect('error', errback)\n        self.engine.setProperty('voice', 'foobar')\n        self.engine.setProperty('voice', 100)\n        self.engine.setProperty('voice', 1.0)\n        self.engine.setProperty('voice', None)\n        self.engine.setProperty('voice', object())\n        self.engine.runAndWait()\n        self.engine.disconnect(tok)\n        for error in errors:\n            self.assert_(isinstance(error, ValueError))\n\ndef suite():\n    suite = unittest.TestLoader().loadTestsFromTestCase(TestProperties)\n    #suite = unittest.TestLoader().loadTestsFromName('testBadVoice', TestProperties)\n    return suite\n\nif __name__ == '__main__':\n    unittest.TextTestRunner(verbosity=2).run(suite())"
  },
  {
    "path": "tests/unit/test_say.py",
    "content": "'''\nTests say.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport unittest\nimport test_setup\nimport pyttsx\nimport itertools\n\nclass TestSay(unittest.TestCase):\n    utters = ['This is the first utterance',\n              'The second is an utterance as well']\n    names = ['utter1', 'utter2']\n\n    def setUp(self):\n        self.correct = []\n        for utter, name in zip(self.utters, self.names):\n            events = [{'type' : 'started-utterance'}]\n            last = 0\n            for word in utter.split(' '):\n                event = {'type' : 'started-word'}\n                event['length'] = len(word)\n                event['location'] = last\n                events.append(event)\n                last += len(word) + 1\n            events.append({'type' : 'finished-utterance', 'completed' : True})\n            for event in events:\n                event['name'] = name\n            self.correct.append(events)\n\n        self.events = []\n        self.engine = pyttsx.init(debug=False)\n        self.engine.connect('started-utterance', self._onUtterStart)\n        self.engine.connect('started-word', self._onUtterWord)\n        self.engine.connect('finished-utterance', self._onUtterEnd)\n        self.engine.connect('error', self._onUtterError)\n\n    def tearDown(self):\n        del self.engine\n\n    def _onUtterStart(self, **kwargs):\n        event = {'type' : 'started-utterance'}\n        event.update(kwargs)\n        self.events.append(event)\n\n    def _onUtterWord(self, **kwargs):\n        event = {'type' : 'started-word'}\n        event.update(kwargs)\n        self.events.append(event)\n\n    def _onUtterEnd(self, **kwargs):\n        event = {'type' : 'finished-utterance'}\n        event.update(kwargs)\n        self.events.append(event)\n\n    def _onUtterError(self, **kwargs):\n        event = {'type' : 'error'}\n        event.update(kwargs)\n        self.events.append(event)\n\n    def testSay(self):\n        self.engine.say(self.utters[0], self.names[0])\n        self.engine.runAndWait()\n\n        # number of events check\n        self.assert_(len(self.events) == len(self.correct[0]))\n        # event data check\n        for cevent, tevent in zip(self.correct[0], self.events):\n            self.assert_(cevent == tevent)\n\n    def testMultipleSay(self):\n        self.engine.say(self.utters[0], self.names[0])\n        self.engine.say(self.utters[1], self.names[1])\n        self.engine.runAndWait()\n        # number of events check\n        self.assert_(len(self.events) == len(self.correct[0]) + len(self.correct[1]))\n        # event data check\n        correct = itertools.chain(*self.correct)\n        for cevent, tevent in zip(correct, self.events):\n            self.assert_(cevent == tevent)\n\n    def testSayTypes(self):\n        self.engine.say(1.0)\n        self.engine.say(None)\n        self.engine.say(object())\n        self.engine.runAndWait()\n        # event data check\n        errors = filter(lambda e: e['type'] == 'error', self.events)\n        self.assert_(len(errors) == 0)\n\n    def testStop(self):\n        tok = None\n        def _onWord(**kwargs):\n            self.engine.stop()\n            self.engine.disconnect(tok)\n        tok = self.engine.connect('started-word', _onWord)\n        self.engine.say(self.utters[0], self.names[0])\n        self.engine.runAndWait()\n        # make sure it stopped short\n        self.assert_(len(self.events) < len(self.correct[0]))\n        end = self.events[-1]\n        self.assert_(not end['completed'])\n\n    def testStopBeforeSay(self):\n        self.engine.stop()\n        self.testSay()\n\n    def testMultipleStopBeforeSay(self):\n        self.engine.stop()\n        self.engine.stop()\n        self.testSay()\n\n    def testStartEndLoop(self):\n        def _onEnd(**kwargs):\n            self.engine.endLoop()\n        self.engine.connect('finished-utterance', _onEnd)\n        self.engine.say(self.utters[0], self.names[0])\n        self.engine.startLoop()\n        # number of events check\n        self.assert_(len(self.events) == len(self.correct[0]))\n        # event data check\n        for cevent, tevent in zip(self.correct[0], self.events):\n            self.assert_(cevent == tevent)\n\n    def testExternalLoop(self):\n        def _onEnd(**kwargs):\n            self.engine.endLoop()\n\n        # kill the engine built by setUp\n        del self.engine\n        self.engine = pyttsx.init('dummy')\n        self.engine.connect('started-utterance', self._onUtterStart)\n        self.engine.connect('started-word', self._onUtterWord)\n        self.engine.connect('finished-utterance', self._onUtterEnd)\n        self.engine.connect('error', self._onUtterError)\n        self.engine.connect('finished-utterance', _onEnd)\n        self.engine.say(self.utters[0], self.names[0])\n        self.engine.startLoop(False)\n        self.engine.iterate()\n        # number of events check\n        self.assert_(len(self.events) == len(self.correct[0]))\n        # event data check\n        for cevent, tevent in zip(self.correct[0], self.events):\n            self.assert_(cevent == tevent)\n\n    def testMultipleRuns(self):\n        self.testSay()\n        self.events = []\n        self.testSay()\n\ndef suite():\n    suite = unittest.TestLoader().loadTestsFromTestCase(TestSay)\n    #suite = unittest.TestLoader().loadTestsFromName('testExternalLoop', TestSay)\n    return suite\n\nif __name__ == '__main__':\n    unittest.TextTestRunner(verbosity=2).run(suite())"
  },
  {
    "path": "tests/unit/test_setup.py",
    "content": "'''\nConfigures the test fixture.\n\nCopyright (c) 2009, 2013 Peter Parente\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n'''\nimport sys\nimport os\nsys.path.insert(0, os.path.join('..', '..'))"
  }
]