Package com.sun.speech.freetts

Source Code of com.sun.speech.freetts.Voice$FreeTTSSpeakableTokenizer

/**
* Portions Copyright 2001 Sun Microsystems, Inc.
* Portions Copyright 1999-2001 Language Technologies Institute,
* Carnegie Mellon University.
* All Rights Reserved.  Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*/
package com.sun.speech.freetts;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

import com.sun.speech.freetts.audio.AudioPlayer;
import com.sun.speech.freetts.lexicon.Lexicon;
import com.sun.speech.freetts.relp.LPCResult;
import com.sun.speech.freetts.util.BulkTimer;
import com.sun.speech.freetts.util.Utilities;


/**
* Performs text-to-speech using a series of
* <code>UtteranceProcessors</code>. It is the main conduit to the FreeTTS
* speech synthesizer. It can perform TTS on ASCII text,
* a JSML document, an <code>InputStream</code>, or a
* <code>FreeTTSSpeakable</code>, by invoking the method <code>speak</code>.
*
* <p>Before a Voice can perform TTS, it must have a
* <code>Lexicon</code>, from which it gets the vocabulary, and
* an <code>AudioPlayer</code>, to which it sends the synthesized output.
*
* <p><b>Example</b> (using the <code>CMUDiphoneVoice</code>,
* <code>CMULexicon</code> and <code>JavaClipAudioPlayer</code>):
*
* <pre>
* Voice voice = new CMUDiphoneVoice();
*
* // sets the Lexicon
* voice.setLexicon(new CMULexicon());
*
* // sets the AudioPlayer
* voice.setAudioPlayer(new JavaClipAudioPlayer());
*
* // loads the Voice
* voice.allocate();
*
* // start talking
* voice.speak("I can talk forever without getting tired!");
* </pre>
*
*
* <p>A user can override the AudioPlayer to use by defining the
* "com.sun.speech.freetts.voice.defaultAudioPlayer" system property.
* The value of this property must be the name of a class that
* implements the AudioPlayer interface, and which also has a no-arg
* constructor.
*
* @see VoiceManager
* @see VoiceDirectory
*/
public abstract class Voice implements UtteranceProcessor, Dumpable {
    /** Logger instance. */
    private static final Logger LOGGER =
        Logger.getLogger(Voice.class.getName());
   
    /**
     * Constant that describes the name of the unit database used by
     * this voice.
     */
    public final static String DATABASE_NAME = "databaseName";
   
    private List utteranceProcessors;
    private Map featureProcessors;
    private FeatureSetImpl features;
    private boolean metrics = false;
    private boolean detailedMetrics = false;
    private boolean dumpUtterance = false;
    private boolean dumpRelations = false;
    private String runTitle = "unnamed run";
    private Lexicon lexicon = null;
    private AudioPlayer defaultAudioPlayer = null;
    private AudioPlayer audioPlayer = null;
    private UtteranceProcessor audioOutput;
    private OutputQueue outputQueue = null;
    private String waveDumpFile = null;
    private BulkTimer runTimer = new BulkTimer();
    private BulkTimer threadTimer = new BulkTimer();
    private boolean externalOutputQueue = false;
    private boolean externalAudioPlayer = false;


    private float nominalRate = 150// nominal speaking rate for this voice
    private float pitch = 100;    // pitch baseline (hertz)
    private float range = 10;    // pitch range (hertz)
    private float pitchShift = 1// F0 Shift
    private float volume = 0.8f// the volume (range 0 to 1)
    private float durationStretch = 1f// the duration stretch

    private boolean loaded = false;

    private String name = "default_name";
    private Age age = Age.DONT_CARE;
    private Gender gender = Gender.DONT_CARE;
    private String description = "default description";
    private Locale locale = Locale.getDefault();
    private String domain = "general";
    private String style = "standard";
    private String organization = "unknown";

    /**
     * Prefix for System property names.
     */
    public final static String PROP_PREFIX = "com.sun.speech.freetts.voice.";

    /**
     * Feature name for the silence phone string.
     */
    public final static String FEATURE_SILENCE = "silence";

    /**
     * Feature name for the join type string.
     */
    public final static String FEATURE_JOIN_TYPE = "join_type";

    /**
     * Feature name for the default AudioPlayer class to use.
     */
    public final static String DEFAULT_AUDIO_PLAYER =
            PROP_PREFIX + "defaultAudioPlayer";   


    /**
     * The default class to use for the DEFAULT_AUDIO_PLAYER.
     */
    public final static String DEFAULT_AUDIO_PLAYER_DEFAULT =
            "com.sun.speech.freetts.audio.JavaStreamingAudioPlayer";
   

    /**
     * Creates a new Voice. Utterances are sent to an
     * output queue to be rendered as audio.  Utterances are placed
     * on the queue by an output thread. This
     * queue is usually created via a call to 'createOutputThread,'
     * which creates a thread that waits on the queue and sends the
     * output to the audio player associated with this voice. If
     * the queue is null, the output is rendered in the calling
     * thread.
     *
     * @see #createOutputThread
     */
    public Voice() {
        /* Make the utteranceProcessors a synchronized list to avoid
         * some threading issues.
         */
        utteranceProcessors = Collections.synchronizedList(new ArrayList());
  features = new FeatureSetImpl();
  featureProcessors = new HashMap();

  try {
      nominalRate = Float.parseFloat(
        Utilities.getProperty(PROP_PREFIX + "speakingRate","150"));
      pitch = Float.parseFloat(
        Utilities.getProperty(PROP_PREFIX + "pitch","100"));
      range = Float.parseFloat(
        Utilities.getProperty(PROP_PREFIX + "range","10"));
      volume = Float.parseFloat(
        Utilities.getProperty(PROP_PREFIX + "volume","1.0"));
  } catch (SecurityException se) {
       // can't get properties, just use defaults
  }
        outputQueue = null;
        audioPlayer = null;
        defaultAudioPlayer = null;
    }

    /**
     * Creates a new Voice like above, except that it also
     * stores the properties of the voice.
     * @param name the name of the voice
     * @param gender the gender of the voice
     * @param age the age of the voice
     * @param description a human-readable string providing a
     * description that can be displayed for the users.
     * @param locale the locale of the voice
     * @param domain the domain of this voice.  For example,
     * @param organization the organization which created the voice
     * &quot;general&quot;, &quot;time&quot;, or
     * &quot;weather&quot;.
     *
     * @see #Voice()
     */
    public Voice(String name, Gender gender, Age age,
            String description, Locale locale, String domain,
            String organization) {
        this();
        setName(name);
        setGender(gender);
        setAge(age);
        setDescription(description);
        setLocale(locale);
        setDomain(domain);
        setOrganization(organization);
    }


    /**
     * Speaks the given text.
     *
     * @param text the text to speak
     *
     * @return <code>true</code> if the given text is spoken properly;
     *   otherwise <code>false</code>
     */
    public boolean speak(String text) {
  return speak(new FreeTTSSpeakableImpl(text));
    }


    /**
     * Speaks the given document.
     *
     * @param doc the JSML document to speak
     *
     * @return <code>true</code> if the given document is spoken properly;
     *   otherwise <code>false</code>
     */
    public boolean speak(Document doc) {
  return speak(new FreeTTSSpeakableImpl(doc));
    }

   
    /**
     * Speaks the input stream.
     *
     * @param inputStream the inputStream to speak
     *
     * @return <code>true</code> if the given input stream is spoken properly;
     *   otherwise <code>false</code>
     */
    public boolean speak(InputStream inputStream) {
  return speak(new FreeTTSSpeakableImpl(inputStream));
    }


    /**
     * Speak the given queue item. This is a synchronous method that
     * does not return until the speakable is completely
     * spoken or has been cancelled.
     *
     * @param speakable the item to speak
     *
     * @return <code>true</code> if the utterance was spoken properly,
     *         <code>false</code> otherwise
     */
    public boolean speak(FreeTTSSpeakable speakable) {
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("speak(FreeTTSSpeakable) called");
        }
        boolean ok = true;
  boolean posted = false;

  getAudioPlayer().startFirstSampleTimer();

  for (Iterator i = tokenize(speakable);
             !speakable.isCompleted() && i.hasNext() ; ) {
      try {
    Utterance utterance = (Utterance) i.next();
    if (utterance != null) {
        processUtterance(utterance);
        posted = true;
    }
      } catch (ProcessException pe) {
    ok = false;
      }
  }
  if (ok && posted) {
      runTimer.start("WaitAudio");
            ok = speakable.waitCompleted();
            runTimer.stop("WaitAudio");
  }
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("speak(FreeTTSSpeakable) completed");
        }
  return ok;
    }


    /**
     * @deprecated  As of FreeTTS 1.2, replaced by {@link #allocate}.
     */
    public void load() {
        allocate();
    }
   
    /**
     * Allocate this Voice. It loads the lexicon and the
     * audio output handler, and creates an audio output thread by
     * invoking <code>createOutputThread()</code>, if
     * one is not already created. It then calls the <code>loader()</code>
     * method to load Voice-specific data, which include utterance processors.
     */
    public void allocate() {
  if (isLoaded()) {
      return;
  }
  BulkTimer.LOAD.start();


  if (!lexicon.isLoaded()) {
      try {
    lexicon.load();
      } catch (IOException ioe) {
          LOGGER.severe("Can't load voice " + ioe);
          throw new Error(ioe);
      }
  }

  try {
      audioOutput = getAudioOutput();
  } catch (IOException ioe) {
      LOGGER.severe("Can't load audio output handler for voice " + ioe);
      throw new Error(ioe);
  }
  if (outputQueue == null) {
      outputQueue = createOutputThread();
  }
  try {
      loader();
  } catch (IOException ioe) {
      LOGGER.severe("Can't load voice " + ioe);
      throw new Error(ioe);
  }
  BulkTimer.LOAD.stop();
  if (isMetrics()) {
      BulkTimer.LOAD.show("loading " + toString() + " for " +
        getRunTitle());
  }
  setLoaded(true);
    }
  

    /**
     * Returns true if this voice is loaded.
     *
     * @return <code>true</code> if the voice is loaded;
     *   otherwise <code>false</code>
     */
    public boolean isLoaded() {
  return loaded;
    }

    /**
     * Sets the loaded state
     *
     * @param loaded the new loaded state
     *   otherwise <code>false</code>
     */
    protected void setLoaded(boolean loaded) {
  this.loaded = loaded;
    }

    /**
     * Processes the given Utterance by passing it to each
     * UtteranceProcessor managed by this Voice.  The
     * UtteranceProcessors are called in the order they were added to
     * the Voice.
     *
     * @param u the Utterance to process
     *
     * @throws ProcessException if an exception occurred while performing
     *   operations on the Utterance
     */
    public void processUtterance(Utterance u) throws ProcessException {
        UtteranceProcessor[] processors;

        if (utteranceProcessors == null) {
            return;
        }
        if (u == null) {
            throw new ProcessException("Utterance is null.");
        }

  runTimer.start("processing");
        processors = new UtteranceProcessor[utteranceProcessors.size()];
        processors = (UtteranceProcessor[])
            utteranceProcessors.toArray(processors);
       
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Processing Utterance: " + u.getString("input_text"));
        }
  try {
      for (int i = 0; i < processors.length &&
                     !u.getSpeakable().isCompleted(); i++) {
                runProcessor(processors[i], u, runTimer);
            }
            if (!u.getSpeakable().isCompleted()) {
                if (outputQueue == null) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine("To AudioOutput");
                    }
                    outputUtterance(u, runTimer);
                } else {
                    runTimer.start("..post");
                    outputQueue.post(u);
                    runTimer.stop("..post");
                }
            }
  }  catch (ProcessException pe) {
      System.err.println("Processing Utterance: " + pe);
  catch (Exception e) {
      System.err.println("Trouble while processing utterance " + e);
      e.printStackTrace();
      u.getSpeakable().cancelled();
  }

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Done Processing Utterance: "
                    + u.getString("input_text"));
        }
  runTimer.stop("processing");

  if (dumpUtterance) {
      u.dump("Utterance");
  }
  if (dumpRelations) {
      u.dumpRelations("Utterance");
  }

  dumpASCII(u);
    }


    /**
     * Dumps the wave for the given utterance.
     *
     * @param utterance the utterance of interest
     */
    private void dumpASCII(Utterance utterance) {
  if (waveDumpFile != null) {
      LPCResult lpcResult =
    (LPCResult) utterance.getObject("target_lpcres");
      try {
    if (waveDumpFile.equals("-")) {
        lpcResult.dumpASCII();
    } else {
        lpcResult.dumpASCII(waveDumpFile);
    }
      } catch (IOException ioe) {
    LOGGER.severe("Can't dump file to " + waveDumpFile + " " + ioe);
    throw new Error(ioe);
      }
  }
    }


    /**
     * Creates an output thread that will asynchronously
     * output utterances that are generated by this voice (and other
     * voices).
     *
     * @return the queue where utterances should be placed.
     */
    public static OutputQueue createOutputThread() {
  final OutputQueue queue =  new OutputQueue();
  Thread t = new Thread() {
      public void run() {
    Utterance utterance = null;
    do {
        utterance = queue.pend();
        if (utterance != null) {
      Voice voice = utterance.getVoice();
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("OUT: "
                        + utterance.getString("input_text"));
            }
                        voice.outputUtterance(utterance, voice.threadTimer);
        }
    } while (utterance != null);
      }
  };
  t.setDaemon(true);
  t.start();
  return queue;
    }


    /**
     * Sends the given utterance to the audio output processor
     * associated with this voice. If the queue item associated with
     * this utterance is completed, then this set of utterances has
     * been cancelled or otherwise aborted and the utterance should
     * not be output.
     *
     * @param utterance the utterance to be output
     * @param timer the timer for gathering performance metrics
     *
     * @return  true if the utterance was output properly; otherwise
     *    false
     */
    private boolean outputUtterance(Utterance utterance, BulkTimer timer) {
  boolean ok = true;
  FreeTTSSpeakable speakable = utterance.getSpeakable();

  if (!speakable.isCompleted())  {
      if (utterance.isFirst()) {
    getAudioPlayer().reset();
    speakable.started();
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine(" --- started ---");
          }
      }

      // log("   utt: " + utterance.getString("input_text"));
      try {
                if (!speakable.isCompleted()) {
                    runProcessor(audioOutput, utterance, timer);
                } else {
                    ok = false;
                }
      }  catch (ProcessException pe) {
    ok = false;
      }
      if (ok && utterance.isLast()) {
    getAudioPlayer().drain();
                speakable.completed();
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(" --- completed ---");
                }
      } else if (!ok) {
    // getAudioPlayer().drain();
    speakable.cancelled();
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine(" --- cancelled ---");
          }
      } else {
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine(" --- not last: " + speakable.getText()
                      + " --- ");
          }
            }
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine("Calling speakable.completed() on "
                      + speakable.getText());
          }
        } else {
      ok = false;
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine("STRANGE: speakable already completed: "
                      + speakable.getText());
          }
  }
  return ok;
    }


    /**
     * Runs the given utterance processor.
     *
     * @param processor the processor to run.   If the processor
     *    is null, it is ignored
     * @param utterance the utterance to process
     *
     * @throws ProcessException if an exceptin occurs while processing
     *     the utterance
     */
    private void runProcessor(UtteranceProcessor processor,
                              Utterance utterance, BulkTimer timer)
        throws ProcessException {
  if (processor != null) {
      String processorName = ".." + processor.toString();
          if (LOGGER.isLoggable(Level.FINE)) {
              LOGGER.fine("   Running " + processorName);
          }
      timer.start(processorName);
      processor.processUtterance(utterance);
      timer.stop(processorName);
  }
    }


    /**
     * Returns the tokenizer associated with this voice.
     *
     * @return the tokenizer
     */
    public abstract Tokenizer getTokenizer();


    /**
     * Return the list of UtteranceProcessor instances.  Applications
     * should use this to obtain and modify the contents of the
     * UtteranceProcessor list.
     *
     * @return a List containing UtteranceProcessor instances
     */
    public List getUtteranceProcessors() {
        return utteranceProcessors;
    }


    /**
     * Returns the feature set associated with this voice.
     *
     * @return the feature set.
     */
    public FeatureSet getFeatures() {
  return features;
    }


    /**
     * Starts a batch of utterances. Utterances are sometimes
     * batched in groups for timing purposes.
     *
     * @see #endBatch
     */
    public void startBatch() {
  runTimer.setVerbose(detailedMetrics);
  runTimer.start();
    }

   
    /**
     * Ends a batch of utterances.
     *
     * @see #startBatch
     */
    public void endBatch() {
  runTimer.stop();

  if (metrics) {
      runTimer.show(getRunTitle() + " run");
      threadTimer.show(getRunTitle() + " thread");
      getAudioPlayer().showMetrics();
      long totalMemory = Runtime.getRuntime().totalMemory();
      LOGGER.info
    ("Memory Use    : "
     + (totalMemory - Runtime.getRuntime().freeMemory()) / 1024
     + "k  of " + totalMemory / 1024 + "k");
  }
    }

    /**
     * Sets the output queue for this voice. If no output queue is set
     * for the voice when the voice is loaded, a queue and thread will
     * be created when the voice is loaded.  If the outputQueue is set
     * by an external entity by calling setOutputQueue, the caller is
     * responsible for shutting down the output thread. That is, if
     * you call 'setOutputQueue' then you are responsible for shutting
     * down the output thread on your own. This is necessary since the
     * output queue may be shared by a number of voices.
     *
     * <p>Utterances are placed on the
     *    queue to be output by an output thread. This queue is
     *    usually created via a call to 'createOutputThread' which
     *    creates a thread that waits on the queue and sends the
     *    output to the audio player associated with this voice. If
     *    the queue is null, the output is rendered in the calling
     *    thread.
     *
     * @param queue the output queue
     */
    public void setOutputQueue(OutputQueue queue) {
  externalOutputQueue = true;
  outputQueue = queue;
    }

    /**
     * Returns the output queue associated with this voice.
     *
     * @return the output queue associated with this voice
     */
    public OutputQueue getOutputQueue() {
  return outputQueue;
    }

    /**
     * Loads voice specific data. Subclasses of voice should
     * implement this to perform class specific loading.
     */
    protected abstract void loader() throws IOException;

    /**
     * tokenizes the given the queue item.
     *
     * @return an iterator that will yield a series of utterances
     */
    private Iterator tokenize(FreeTTSSpeakable speakable) {
  return new FreeTTSSpeakableTokenizer(speakable).iterator();
    }
   
    /**
     * Converts the document to a string (a placeholder for more
     * sophisticated logic to be done).
     *
     * @param dom the jsml document
     *
     * @return the document as a string.
     */
    private String documentToString(Document dom) {
  StringBuffer buf = new StringBuffer();
  linearize(dom, buf);
  return buf.toString();
    }
   
    /**
     * Appends the text for this node to the given StringBuffer.
     *
     * @param n the node to traverse in depth-first order
     * @param buf the buffer to append text to
     */
    private  void linearize(Node n, StringBuffer buf) {
        StringBuffer endText = processNode(n, buf);
        for (Node child = n.getFirstChild();
             child != null;
             child = child.getNextSibling()) {
            linearize(child, buf);
        }

        if (endText != null) {
            buf.append(endText);
        }
    }

    /**
     * Adds text for just this node and returns any text that might
     * be needed to undo the effects of this node after it is
     * processed.
     *
     * @param n the node to traverse in depth-first order
     * @param buf the buffer to append text to
     *
     * @return a <code>String</code> containing text to undo the
     *   effects of the node
     */
    protected StringBuffer processNode(Node n, StringBuffer buf) {
        StringBuffer endText = null;
       
        int type = n.getNodeType();
        switch (type) {
            case Node.ATTRIBUTE_NODE:
                 break;
                
            case Node.DOCUMENT_NODE:
                break;
               
            case Node.ELEMENT_NODE:
                // endText = processElement((Element) n, buf);
                break;
               
            case Node.TEXT_NODE:
                buf.append(((Text) n).getData());
                break;

            // Pass processing instructions (e.g., <?blah?>
            // right on to the synthesizer.  These types of things
            // probably should not be used.  Instead the 'engine'
            // element is probably the best thing to do.
            //
            case Node.PROCESSING_INSTRUCTION_NODE:
                break;
               
            // The document type had better be JSML.
            //
            case Node.DOCUMENT_TYPE_NODE:
                break;

            // I think NOTATION nodes are only DTD's.
            //
            case Node.NOTATION_NODE:
                break;

            // Should not get COMMENTS because the JSMLParser
            // ignores them.
            //
            case Node.COMMENT_NODE:
                break;

            // Should not get CDATA because the JSMLParser is
            // coalescing.
            //   
            case Node.CDATA_SECTION_NODE:
                break;

            // Should not get ENTITY related notes because
            // entities are expanded by the JSMLParser
            //
            case Node.ENTITY_NODE:
            case Node.ENTITY_REFERENCE_NODE:
                break;

            // Should not get DOCUMENT_FRAGMENT nodes because I
            // [[[WDW]]] think they are only created via the API's
            // and cannot be defined via content.
            //
            case Node.DOCUMENT_FRAGMENT_NODE:
                break;

            default:
                break;
        }
       
        return endText;
    }

    /**
     * Dumps the voice in textual form.
     *
     * @param output where to send the formatted output
     * @param pad the initial padding
     * @param title the title to print when dumping out
     */
    public void dump(PrintWriter output, int pad, String title) {
  Utilities.dump(output, pad, title);
  features.dump(output, pad + 4, title + " Features");
  dumpProcessors(output, pad + 4, title + " Processors");
    }


    /**
     * Dumps the voice processors.
     *
     * @param output where to send the formatted output
     * @param pad the initial padding
     * @param title the title to print when dumping out
     */
    public void dumpProcessors(PrintWriter output, int pad, String title) {
        UtteranceProcessor[] processors;
        if (utteranceProcessors == null) {
            return;
        }

        processors = new UtteranceProcessor[utteranceProcessors.size()];
        processors = (UtteranceProcessor[])
            utteranceProcessors.toArray(processors);
       
  Utilities.dump(output, pad, title);
        for (int i = 0; i < processors.length; i++) {
      Utilities.dump(output, pad + 4, processors[i].toString());
        }
    }


    /**
     * Returns a language/voice specific Feature Processor.
     *
     * @param name the name of the processor
     *
     * @return the processor associated with the name or null if none
     *   could be found
     */
    public FeatureProcessor getFeatureProcessor(String name) {
  return (FeatureProcessor) featureProcessors.get(name);
    }

    /**
     * Adds a language/voice specific Feature Processor to the set of
     * FeatureProcessors supported by this voice.
     *
     * @param name the name of the processor
     * @param fp  the processor
     */
    public void addFeatureProcessor(String name, FeatureProcessor fp) {
  featureProcessors.put(name, fp);
    }

    /**
     * Gets the state of the metrics mode.
     *
     * @return true if metrics mode is on
     */
    public boolean isMetrics() {
  return metrics;
    }

    /**
     * Sets the metrics mode.
     *
     * @param metrics true if metrics mode should be on
     */
    public void setMetrics(boolean metrics) {
  this.metrics = metrics;
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Metrics mode is " + metrics);
        }
    }

    /**
     * Gets the state of the detailedMetrics mode.
     *
     * @return true if detailedMetrics mode is on
     */
    public boolean isDetailedMetrics() {
  return detailedMetrics;
    }

    /**
     * Sets the state of the detailedMetrics mode.
     *
     * @param detailedMetrics true if detailedMetrics mode should be on
     */
    public void setDetailedMetrics(boolean detailedMetrics) {
  this.detailedMetrics = detailedMetrics;
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("DetailedMetrics mode is " + detailedMetrics);
        }
    }

    /**
     * Gets the state of the dumpUtterance mode.
     *
     * @return true if dumpUtterance mode is on
     */
    public boolean isDumpUtterance() {
  return dumpUtterance;
    }

    /**
     * Sets the state of the dumpUtterance mode.
     *
     * @param dumpUtterance true if dumpUtterance mode should be on
     */
    public void setDumpUtterance(boolean dumpUtterance) {
  this.dumpUtterance = dumpUtterance;
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("DumpUtterance mode is " + dumpUtterance);
        }
    }

    /**
     * Gets the state of the dumpRelations mode.
     *
     * @return true if dumpRelations mode is on
     */
    public boolean isDumpRelations() {
  return dumpRelations;
    }

    /**
     * Sets the state of the dumpRelations mode.
     *
     * @param dumpRelations true if dumpRelations mode should be on
     */
    public void setDumpRelations(boolean dumpRelations) {
  this.dumpRelations = dumpRelations;
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("DumpRelations mode is " + dumpRelations);
        }
    }
   
    /**
     * Sets the title for this run.
     *
     * @param runTitle the title for the run
     */
    public void setRunTitle(String runTitle) {
  this.runTitle = runTitle;
    }

    /**
     * Gets the title for this run.
     *
     * @return the title for the run
     */
    public String getRunTitle() {
  return runTitle;
    }

    /**
     * Given a phoneme and a feature name, returns the feature.
     *
     * @param phone the phoneme of interest
     * @param featureName the name of the feature of interest
     *
     * @return the feature with the given name
     */
    public String getPhoneFeature(String phone, String featureName) {
  return null;
    }

    /**
     * Shuts down the voice processing.
     */
    public void deallocate() {
  setLoaded(false);

        if (!externalAudioPlayer) {
            if (audioPlayer != null) {
                audioPlayer.close();
                audioPlayer = null;
            }
        }
       
  if (!externalOutputQueue) {
      outputQueue.close();
  }
    }

    /**
     * Sets the baseline pitch.
     *
     * @param hertz the baseline pitch in hertz
     */
    public void setPitch(float hertz) {
  this.pitch = hertz;
    }

    /**
     * Retreives the baseline pitch.
     *
     * @return  the baseline pitch in hertz
     */
    public float getPitch() {
  return pitch;
    }

    /**
     * Sets the pitch range.
     *
     * @param range the range in hertz
     */
    public void setPitchRange(float range) {
  this.range = range;
    }

    /**
     * Gets the pitch range.
     *
     * @return the range in hertz
     */
    public float getPitchRange() {
  return range;
    }

    /**
     * Sets the pitch shift
     *
     * @param shift the pitch shift (1.0 is no shift)
     */
    public void setPitchShift(float shift) {
  this.pitchShift = shift;
    }

    /**
     * Gets the pitch shift.
     *
     * @return the pitch shift
     */
    public float getPitchShift() {
  return pitchShift;
    }

    /**
     * Sets the duration  stretch
     *
     * @param stretch the duration stretch (1.0 is no stretch)
     */
    public void setDurationStretch(float stretch) {
  this.durationStretch = stretch;
    }

    /**
     * Gets the duration Stretch
     *
     * @return the duration stretch
     */
    public float getDurationStretch() {
  return durationStretch;
    }

    /**
     * Sets the rate of speech.
     *
     * @param wpm words per minute
     */
    public void setRate(float wpm) {
  if (wpm > 0 && wpm < 1000) {
      setDurationStretch(nominalRate / wpm);
  }
    }

    /**
     * Gets the rate of speech.
     *
     * @return words per minute
     */
    public float getRate() {
  return durationStretch * nominalRate;
    }


    /**
     * Sets the volume.
     *
     * @param vol the volume (0 to 1.0)
     */
    public void setVolume(float vol) {
  volume = vol;
    }

    /**
     * Gets the volume.
     *
     * @return the volume (0 to 1.0)
     */
    public float getVolume() {
  return volume;
    }

    /**
     * Gets the lexicon for this voice.
     *
     * @return the lexicon (or null if there is no lexicon)
     */
    public Lexicon getLexicon() {
  return lexicon;
    }

    /**
     * Sets the lexicon to be used by this voice.
     *
     * @param lexicon the lexicon to use
     */
    public void setLexicon(Lexicon lexicon) {
  this.lexicon = lexicon;

    }

    /**
     * Sets the dumpfile for this voice.
     *
     * @param waveDumpFile the dumpfile
     */
    public void setWaveDumpFile(String waveDumpFile) {
  this.waveDumpFile = waveDumpFile;
    }

    /**
     * Gets the dumpfile for this voice.
     *
     * @return the dumpfile
     */
    public String  getWaveDumpFile() {
  return waveDumpFile;
    }

    /**
     * Sets the audio player associated with this voice. The caller is
     * responsible for closing this player.
     *
     * @param player the audio player
     */
    public void setAudioPlayer(AudioPlayer player) {
  audioPlayer = player;
        externalAudioPlayer = true;
    }

    /**
     * Gets the default audio player for this voice.  The return
     * value will be non-null only if the DEFAULT_AUDIO_PLAYER
     * system property has been set to the name of an AudioPlayer
     * class, and that class is able to be instantiated via a
     * no arg constructor.  getAudioPlayer will automatically set
     * the audio player for this voice to the default audio player
     * if the audio player has not yet been set.
     *
     * @see #DEFAULT_AUDIO_PLAYER
     * @see #getAudioPlayer
     * @return the default AudioPlayer
     */
    public AudioPlayer getDefaultAudioPlayer() throws InstantiationException {
        if (defaultAudioPlayer != null) {
            return defaultAudioPlayer;
        }
       
        String className = Utilities.getProperty(
            DEFAULT_AUDIO_PLAYER, DEFAULT_AUDIO_PLAYER_DEFAULT);

        try {
            Class cls = Class.forName(className);
            defaultAudioPlayer = (AudioPlayer) cls.newInstance();
            return defaultAudioPlayer;
        } catch (ClassNotFoundException e) {
            throw new InstantiationException("Can't find class " + className);
        } catch (IllegalAccessException e) {
            throw new InstantiationException("Can't find class " + className);
        } catch (ClassCastException e) {
            throw new InstantiationException(className + " cannot be cast "
                                             + "to AudioPlayer");
        }
    }
   
    /**
     * Gets the audio player associated with this voice.  If the
     * audio player has not yet been set, the value will default
     * to the return value of getDefaultAudioPlayer.
     *
     * @see #getDefaultAudioPlayer
     * @return the audio player
     */
    public AudioPlayer getAudioPlayer() {
        if (audioPlayer == null) {
            try {
                audioPlayer = getDefaultAudioPlayer();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
  return audioPlayer;
    }

    /**
     * Get a resource for this voice.
     * By default, the voice is searched for in the package
     * to which the voice class belongs. Subclasses are free to
     * override this behaviour.
     */
    protected URL getResource(String resource) {
        return this.getClass().getResource(resource);
    }

    /**
     * Set the name of this voice.
     * [[[TODO: any standard format to the name?]]]
     *
     * @param name the name to assign this voice
     */
    protected void setName(String name) {
        this.name = name;
    }


    /**
     * Get the name of this voice.
     *
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * Returns the name of this Voice.
     *
     * @return the name of this Voice
     */
    public String toString() {
        return getName();
    }

    /**
     * Set the gender of this voice.
     *
     * @param gender the gender to assign
     */
    protected void setGender(Gender gender) {
        this.gender = gender;
    }

    /**
     * Get the gender of this voice.
     *
     * @return the gender of this voice
     */
    public Gender getGender() {
        return gender;
    }

    /**
     * Set the age of this voice.
     *
     * @param age the age to assign
     */
    protected void setAge(Age age) {
        this.age = age;
    }

    /**
     * Get the age of this voice.
     *
     * @return the age of this voice
     */
    public Age getAge() {
        return age;
    }

    /**
     * Set the description of this voice.
     *
     * @param description the human readable description to assign
     */
    protected void setDescription(String description) {
        this.description = description;
    }

    /**
     * Get the description of this voice.
     *
     * @return the human readable description of this voice
     */
    public String getDescription() {
        return description;
    }

    /**
     * Set the locale of this voice.
     *
     * @param locale the locale of this voice.
     */
    protected void setLocale(Locale locale) {
        this.locale = locale;
    }

    /**
     * Get the locale of this voice.
     *
     * @return the locale of this voice.
     */
    public Locale getLocale() {
        return locale;
    }

    /**
     * Set the domain of this voice.
     *
     * @param domain the domain of this voice.  For example,
     * &quot;general&quot;, &quot;time&quot;, or
     * &quot;weather&quot;.
     */
    protected void setDomain(String domain) {
        this.domain = domain;
    }

    /**
     * Get the domain of this voice.
     *
     * @return the domain of this voice.  For example,
     * &quot;general&quot;, &quot;time&quot;, or
     * &quot;weather&quot;.
     */
    public String getDomain() {
        return domain;
    }

    /**
     * Sets the voice style. This parameter is designed for human
     * interpretation. Values might include "business", "casual",
     * "robotic", "breathy"
     *
     * @param style the stile of this voice.
     */
    public void setStyle(String style) {
        this.style = style;
    }

    /**
     * Gets the voice style. This parameter is designed for human
     * interpretation. Values might include "business", "casual",
     * "robotic", "breathy".
     */
    public String getStyle() {
        return style;
    }

    /**
     * Sets the organization which created this voice.  For example
     * "cmu", "sun", ...
     *
     * @param organization the name of the organization
     */
    protected void setOrganization(String organization) {
        this.organization = organization;
    }

    /**
     * Gets the organization which created this voice.  For example
     * "cmu", "sun", ...
     *
     * @return the name of the organization
     */
    public String getOrganization() {
        return organization;
    }

    /**
     * Returns the AudioOutput processor to be used by this voice.
     * Derived voices typically override this to customize behaviors.
     *
     * @return the audio output processor
     *
     * @throws IOException if an IO error occurs while getting
     *     processor
     */
    protected abstract UtteranceProcessor getAudioOutput() throws IOException ;

    /**
     * Tokenizes a FreeTTSSpeakable
     */
    private class FreeTTSSpeakableTokenizer  {
  FreeTTSSpeakable speakable;
  Tokenizer tok = getTokenizer();

  /**
   * Constructor.
         *
   * @param speakable the queue item to be pretokenized
   */
      public FreeTTSSpeakableTokenizer(FreeTTSSpeakable speakable) {
      this.speakable = speakable;
      if (speakable.isPlainText()) {
    tok.setInputText(speakable.getText());
      } else if (speakable.isStream()) {
    Reader reader = new BufferedReader(
        new InputStreamReader(speakable.getInputStream()));
    tok.setInputReader(reader);
      } else if (speakable.isDocument()) {
    tok.setInputText(documentToString(speakable.getDocument()));
      }
  }
     
  /**
   * Returns an iterator for this text item.
   */
  public Iterator iterator() {
      return new Iterator() {
    boolean first = true;
    Token savedToken = null;

    /**
     * Determines if there are more utterances
     *
     * @return true if there are more tokens
     */
    public boolean hasNext() {
        return savedToken != null || tok.hasMoreTokens();
    }

    /**
     * Returns the next utterance.
                 *
     * @return the next utterance (as an object) or
     *    null if there is are no utterances left
     */
    public Object next() {
        ArrayList tokenList = new ArrayList();
        Utterance utterance = null;

        if (savedToken != null) {
      tokenList.add(savedToken);
      savedToken = null;
        }

        while (tok.hasMoreTokens()) {
      Token token = tok.getNextToken();
      if ((token.getWord().length() == 0) ||
          (tokenList.size() > 500) ||
          tok.isBreak()) {
          savedToken = token;
          break;
      }
      tokenList.add(token);
        }
        utterance =  new Utterance(Voice.this, tokenList);
        utterance.setSpeakable(speakable);
        utterance.setFirst(first);
        first = false;
                    boolean isLast =
                        (!tok.hasMoreTokens() &&
                         (savedToken == null ||
                          savedToken.getWord().length() == 0));
        utterance.setLast(isLast);
        return utterance;
    }

    public void remove() {
                    throw new UnsupportedOperationException("remove")
    }
      };
  }
    }
}

 


TOP

Related Classes of com.sun.speech.freetts.Voice$FreeTTSSpeakableTokenizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.