Package com.samir_ahmed.Iris

Source Code of com.samir_ahmed.Iris.Synthesizer$SpeechFileGenerator

package com.samir_ahmed.Iris;

/**
*
* SYNTHESIZER MODULE --
* LAST EDITED BY SAMIR AHMED - JUNE 20 2011
*
* OUTLINE: Synthesizer Used for Generating Speech Via Google Translate Text-to-Speech API
* This Class uses a CachedThreadPool To Increase Increase Efficiency
* Speed Test: Single Thread 4.3 seconds vs Multi-Threaded 1.2 Seconds
*
**/

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.FactoryRegistry;
import javazoom.jl.player.Player;

public class Synthesizer implements Runnable {

  // Testing Synthesizer Directly
  public static void main(String[] args) throws InterruptedException, ExecutionException {
   
    Iris.setStartTime();
    ExecutorService exs = Executors.newFixedThreadPool(10);
    Synthesizer outVoice = new Synthesizer(exs);
    outVoice.setAnswer("Robert Matthew Van Winkle, best known by his stage name Vanilla Ice, is an American rapper and home improvement television personality. Travis Landon Barker is an American musician, producer and entrepreneur, most noted as the drummer for the American pop punk band Blink-182, as well as the alternative rock band plus 44, the rap rock band The Transplants, and the alternative rock band Box Car Racer.");
    Future<?> playFuture = exs.submit(outVoice);
    playFuture.get();
    exs.shutdownNow();
 
  }


  /* Synthesizer Data Fields
   *
   * UserText    : LinkedList: String Container with Tokenized Stringfs
   * Files    : Integer   : The number of output files that will be generated
   * isUnassigned : Boolean  : True/False holds status of the AudioDevice object
   *
   * AudioLine and FutureAudioLine are AudioDevice objects for the JLayer Player
   *
   **/

  private LinkedList<String> UserText;
  private Integer Files;
  private boolean IsUnassigned;
  private AudioDevice AudioLine;
 
  private final ExecutorService exs;
  private final String GOOGLE_TRANSLATE_TTS_URL = "http://translate.google.com/translate_tts?tl=en&q=";
  private final Future<AudioDevice> futureAudioLine;

  /** Constructor: Will submit the AudioDeviceLoader to the executor */

  /**Constructor for Synthesizer Object**/
  public Synthesizer(ExecutorService executor){ 
    //Assign executor
    this.exs = executor;
    this.IsUnassigned = true;
    AudioDeviceLoader ADL = new AudioDeviceLoader();
    futureAudioLine = this.exs.submit(ADL);
  }
 
  /** Assigns the audioline if unassigned*/

  private void AssignAudioLine(){
   
    // If unassigned we assign it and flag as assigned, otherwise ignore
    if (this.IsUnassigned){
      try{
        AudioLine = futureAudioLine.get();
        this.IsUnassigned = false;
      }
      catch(Exception ee){
        ee.printStackTrace();
      }
    }
  }

  /** Public method to set desire text for Text to Speech Synthesis */

  public void setAnswer(String rawText){

    // Assign the audiodevice from the future it is stored in
    AssignAudioLine();
    //Iris.printTime();

    //Convert to good ole' plain english ascii characters
    rawText = Normalizer.normalize(rawText, Form.NFD)
    .replaceAll("\\p{InCombiningDiacriticalMarks}+", "");

    // Ensure we have only whitespaces that are single spaces characters
    rawText = rawText.replaceAll("%"," percent ");
    rawText = rawText.replaceAll("\\$"," Dollars ");
    rawText = rawText.replaceAll("&"," and ");
    rawText = rawText.replaceAll("\\+"," plus ");

    rawText = rawText.replaceAll("\\s"," ");
    rawText = rawText.replaceAll("\\s{2,}"," ");
    rawText = rawText.replaceAll("\"|\'|\\(|\\)|\\]|\\[","");


    Pattern allcapsPattern = Pattern.compile("([A-Z]){2,}[^A-Z]");
    Matcher allcapsMatch = allcapsPattern.matcher(rawText);
    while(allcapsMatch.find()){
      allcapsMatch.group().toCharArray();
      String replacement="";
      for (char cc: allcapsMatch.group().toCharArray())
      {
        replacement=replacement+cc+"-";
      }
      rawText = rawText.replace(allcapsMatch.group(),replacement);
    }

    // Tokenize userText and Retreive number of Files;
    UserText = smartTokenize(rawText);
    Files = UserText.size();

    System.out.println("\n"+rawText);
  }
 
  /** SmartTokenize : Function for parsing by grammar and restructuring output: Average Run Time ~ 12 ms **/
  private  LinkedList<String> smartTokenize(String oneString){
    // Check if we end on a period. If not Add one
    if(!oneString.endsWith(".")){oneString=oneString+".";}
   
    // Create a regex pattern parse by punctuation;
    Pattern tokenizerPattern = Pattern.compile("([^\\.,;:!]*[\\.,;:!])+?");
    Matcher tokenizerMatcher = tokenizerPattern.matcher(oneString);

    // Declare String variables.
    String buffer;
    String sentence="";
    int count = 0;
    int length = 0;

    // Create Linked list for putting in strings
    LinkedList<String> answerList = new LinkedList<String>();

    // For every punctuation separated value
    while (tokenizerMatcher.find()){

      // Instantiate Buffer count and length;
      buffer = tokenizerMatcher.group();
      count = sentence.length();
      length = buffer.length();

      // CASE 1: We can easily add buffer to our sentence because we are under the 100 char limit
      if( (count+length) <=100){
        sentence +=buffer;
      }

      // CASE 2: If buffer length is greater than 100...
      else if(length>100){

        // Add tack on however much of buffer is required to get a 100 character string
        int breakpoint = buffer.lastIndexOf(' ',100-sentence.length());
        answerList.addLast(sentence+buffer.subSequence(0,breakpoint));
        length-=breakpoint;

        // If we still have more than 100 characters we cut off the largest chunks until we are under one hundred
        if (length >100){
          while(length>100){
            int newbreakpoint = buffer.lastIndexOf(' ',breakpoint+100);
            answerList.addLast(buffer.substring(breakpoint,newbreakpoint));
            length-=(newbreakpoint-breakpoint);
            breakpoint=newbreakpoint;
          }
        }

        // In either case, we just tack on the remainder, assuming it is not zero
        if (length > 0){
          answerList.addLast(buffer.substring(breakpoint,buffer.length()));
          sentence = "";
        }
      }

      // CASE 3: Buffer is less than 100 but added to sentence is greater
      // We add sentence too list, we remake sentence as buffer
      else{
        answerList.addLast(sentence);
        sentence = buffer; 
      }
    }
    // Last case in the event we missed something
    if (sentence !=  "") { answerList.addLast(sentence); }

    return answerList;
  }

  /** getSpeech **/
 
  /** Speak  will create multiple SpeechFileGenerator Objects, which return mp3 chunks
   *  the method will concatenate all the files and then play them with the JLayer Mp3 Player Object.*/
  private synchronized void Speak(LinkedList<String> UserText, Integer Files){

    // Use the executor service to submit all the TTS strings simultaneously
    try {
      // For every file in UserText LinkedList; Generate a textToSpeech Object and execute it
      ArrayList <Future<byte []>> mp3_filelist = new ArrayList<Future<byte []>>(Files);
      for (int ii = 1; ii<=Files;ii++){
        SpeechFileGenerator tts = new SpeechFileGenerator(UserText.pop());
        mp3_filelist.add(exs.submit(tts));
      }

      /* Create a new mp3 file byte[] of size zero*/
      byte [] mp3_file = new byte[0];
      int size = mp3_file.length;

      /* For every future in the arrayList,
       * Append it to mp3_file variable;
       * */
      for( Future<byte[]> mp3_piece_Future : mp3_filelist ){

        /* Load the future into mp3_piece */
        byte[] mp3_piece= mp3_piece_Future.get();

        /* Calculate piece length */
        int pieceLength =  mp3_piece.length;

        /* Create a new temporary byte array with size large enough to accomadate the new piece  */
        byte []temp = new byte[size+pieceLength];

        /* Copy the original file into the byte array */
        System.arraycopy(mp3_file,0,temp,0,size);

        /* Copy the new piece into the byte array, offset by the old files length */
        System.arraycopy(mp3_piece,0,temp,size,pieceLength);

        /* Update the size of the whole file and reassign variables */
        mp3_file = temp;
        size+=pieceLength;

      }

      /* Create Input Stream from mp3_file and submit to JLayer MP3 Player*/
      InputStream mp3_stream = new ByteArrayInputStream(mp3_file);
      Player mp3_player = new Player(mp3_stream,this.AudioLine);

      /* Print Response time and play*/
      Iris.printTime();
      mp3_player.play();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  /** Run Interface**/
  public void run(){
    try{
      Speak(UserText,Files);
    }
    catch(Exception ee){
      ee.printStackTrace();
    }
  }
 
  /** Callable Object to loads audioDevice from registry for JLayer MP3 Player
   *  Tends to take 3 seconds for the the AudioDevice to Load
   *  */
  private class AudioDeviceLoader implements Callable <AudioDevice>{
 
    /** Implements callable interface: Loads the AudioDevice and returns it*/
    public AudioDevice call(){
      try{
        // Get AudioDevice from Registry
        FactoryRegistry factoryregistry = FactoryRegistry.systemRegistry();
        AudioDevice audio = factoryregistry.createAudioDevice();
        return audio;
      }
      catch(Exception ee){
        System.err.println("Could not load audio driver");
        ee.printStackTrace();
        return null;
      }
    }

  }
 
  /** Threadable textToSpeech Synthesis Objects **/
  private class SpeechFileGenerator implements Callable<byte[]>{

    /* textToSpeech Data Fields
     * text    : String   : String to pass to the ttsShell
     * mp3_file  : byte[]  : Byte Array with mp3 file contained in it
     * */
   
    private String text;
    private byte[] mp3_chunk;

    /** Constructor - Takes String Under 100 Characters and Encodes to URL safe Format**/
    public SpeechFileGenerator(String text){
      try{
        this.text = URLEncoder.encode(text,"UTF-8");
      }
      catch(UnsupportedEncodingException UEex){
        // If the result is unencodable by the means above,
        // we replace the spaces with plus and hope for the best
        this.text = text.replaceAll(" ","+");
      }
    }

    /** "call" : Callable method, will return future byte [] with the mp3 file containing the give text **/
    public byte[] call(){
      try{
        //
        mp3_chunk = httpGET.downloadToByteArray(GOOGLE_TRANSLATE_TTS_URL+text, this);
      }
      catch (Exception ee) {
        ee.printStackTrace();
        mp3_chunk = new byte[0];
      }

      return mp3_chunk;
    }
  }
}
TOP

Related Classes of com.samir_ahmed.Iris.Synthesizer$SpeechFileGenerator

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.