// file:$ISIP_IFC/util/demo/isip_comm_client_speech_recognition/SpeechRecognitionServer.java
// version: $Id: SpeechRecognitionServer.java 10572 2006-06-26 21:54:34Z rei5 $

// import necessary java libraries
//
import java.net.*;
import java.io.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import javax.swing.border.*;
import javax.sound.sampled.*;
import java.text.DecimalFormat;
import javax.swing.JOptionPane;
import javax.swing.JFrame;


// import galaxy libraries
//
import galaxy.lang.*;
import galaxy.server.*;
import galaxy.server.ui.ServerUI;

/**
 * This class is responsible for the user interface of the
 * SpeechRecognition Demo.
 */
public class SpeechRecognitionServer extends galaxy.server.Server  {
    
    //-------------------------------------------------------------------------
    //
    // public constants
    //
    //-------------------------------------------------------------------------
    
    /**
     *  audio recorder server volume index
     */
    public static final int AudioRecorderServer_VOLUME_INDEX = 0;
    
    /**
     *  audio recorder server energy index
     */
    public static final int AudioRecorderServer_ENERGY_INDEX = 1;
    
    /**
     * Clause name for Galaxy frame
     */
    public static String MAIN = "main"; 
    
    /**
     * The variable that keeps the count of data frames that were sent.
     */
    public static int sent_frame_number_d = 0 ;
    
    /**
     * The flag for acknowledgement for audio ready signal.
     */
    public static int audio_ready_ack_d = 0;
    
    /**
     *  audio recorder UI frame
     */
    public static SpeechRecognitionUIFrame speechFrame_d;
    
    /**
     * Finite state for this server -- INITIALIZATION. 
     */
    public static final int INITIALIZATION = 1000;
    
    /**
     * Finite state for this server -- AUDIO_READY. 
     */
    public static final int AUDIO_READY = 2000;
    
    /**
     * Finite state for this server -- AUDIO_READY_ACK. 
     */
    public static final int AUDIO_READY_ACK = 3000;
    
    /**
     * Finite state for this server -- RAW_DATA_TRANSFER. 
     */
    public static final int RAW_DATA_TRANSFER = 4000;
    
    /**
     * Finite state for this server -- END_OF_UTTERANCE. 
     */
    public static final int END_OF_UTTERANCE = 5000;
    
    /**
     * Action state for this server -- IDLE.
     */
    public static final int IDLE = 100;
    
    /**
     * Action state for this server -- PLAYBACK.
     */
    public static final int PLAYBACK = 200;

    /**
     * Mode for playback.
     * PLAYBACK_SIGNAL_ONLY only the endpointed signal is played back
     */
    public static final int PLAYBACK_SIGNAL_ONLY = 250;
    
    /**
     * Mode for playback.
     * PLAYBACK_ALL playback the whole audio data
     */
    public static final int PLAYBACK_ALL = 230;
    
    /**
     * Action state for this server -- RECORDING.
     */
    public static final int RECORDING = 300;
    
    /**
     * The default audio format.
     */
    public static final AudioFormat SPEECH = new AudioFormat(
							     AudioFormat.Encoding.PCM_SIGNED, 
							     16000.0F, 16, 1, 2, 16000.0F, 
							     false);
    
    /**
     * Keeps track of the number of audio_ready acks got.
     */
    public static int audio_ready_ack_count = 0;
    
    /**
     * Keeps track of the number of end_of_utterance acks got.
     */
    public static int utterance_end_ack_count = 0;

    /**
     * The flag used to find whether the end points were detected or not.
     */
    public static int end_points = 0;

    /**
     * A float array that holds the audio data.
     */
    public float[][] audio_data; 
    
    /**
     * A JFrame object for the error window which pops up whenever the
     * audio format is not supported .
     */
    public JFrame frame;
   
    /**
     * the configdata object having audio parameters
     */
    ConfigData audio;
    
    /**
     * the configdata object having signal detector parameters
     */
    ConfigData detector;
    
    //-----------------------------------------------------------------------
    //
    // protected data
    //
    //-----------------------------------------------------------------------
    
    
    // button counter
    //
    protected int btn_press_counter_d = 0; 
     
    // data frame number index.
    //
    protected int data_frame_number_d = 0;
    
    // the state of the speech recognition
    //
    protected int finite_state_d;
    
    // the action state of the speech recognition(recording or playback or idle)
    //
    protected int action_state_d;

    // the flag that gets set from the user presses the stop button
    //
    protected int stop_d; 
    
    // the audiointerface object
    //
    protected AudioInterface audioInterface ;
  
    // the utterance id
    //
    protected static int utterance_id_d = 0;
    
    // flag to check whether an indentation has been set or not before
    // printing to the text field
    //
    protected boolean indent_d =  false;
    
    // recording string
    //
    protected static String recording = "Recording ...";

    // an audioformat object
    //
    protected AudioFormat format_d;
    
    // an array of float values containing the audio samples
    //
    protected float[] samples_d;
    
    // the channel to be displayed
    //
    protected int channel_display;
    
    // playback mode:
    // mode 1: signal_only
    // mode 2: all (default)
    //
    protected int playback_mode_d;

    // the flag that indicates whether recording has taken place
    // or not
    //
    protected boolean record_event;
    
    // the buffer size to be transferred from the AudioInterface
    //
    protected int buffer_size;
    
    // the string that holds the unicode to print the line in input
    // window
    //
    protected String unicode_line;

    // the number of unicode blocks needed to print the line
    //
    protected int unicode_count = 79;

    // the start time
    //
    protected Float start_index;
    
    // the stop time
    //
    protected Float stop_index;

    //-------------------------------------------------------------------------
    //
    // class_specific public methods
    //
    //-------------------------------------------------------------------------
    
    public SpeechRecognitionServer(SpeechRecognitionMainServer mainServer, 
				Socket socket) throws IOException {
	
	// call the constructor for super class
	//
	super(mainServer, socket);
	speechFrame_d = mainServer.getSpeechRecognitionUIFrame();
	
	// initilaize the graphic display
	//
	float percentage_1 = (float) 0.5;
	float percentage_2 = (float) 0.5;
	float percentage_3 = (float) 0;
		
	// set the sample rate
	//
	speechFrame_d.speech_plot_d.setSampleRate((int)(SPEECH.getSampleRate()));
	
	// set the space the energy, waveform and spectrogram monitor
	// occupy
	//
	speechFrame_d.speech_plot_d.setConfiguration(percentage_1,percentage_2,percentage_3);
	javax.swing.SwingUtilities.invokeLater(new Runnable() {
		public void run() {
		    speechFrame_d.speech_plot_d.run();
		}
	    });
	
	// action listener for the stop button
	//
	speechFrame_d.stop_d.addActionListener(new ActionListener() {
		
		public void actionPerformed(ActionEvent e) {
		    
		    // check to make sure recording or playback is in progress
		    // 
		    if((action_state_d == RECORDING)|| (action_state_d == PLAYBACK)) {
			
			// get the mode of operation
			//
			if (audioInterface.getMode() == audioInterface.READ) {
			    System.out.println("Closing the line");
			}
			else if (audioInterface.getMode() == audioInterface.WRITE) {
			    audioInterface.stopPlayBack();
			    
			    // stop the line
			    //
			    audioInterface.stop();
			    
			    // close the line
			    //
			    audioInterface.close();  
			}
			
			action_state_d = IDLE;
			
			// set the stop flag to 1
			//
			stop_d = 1; 
		    }
		    else {
			JFrame frame = new JFrame("Warning"); 
			String warningMessage = new 
			    String("You can press stop only when recording or playback is in progress.");
			JOptionPane.showMessageDialog(frame,warningMessage);
		    }
		}
		    
});
	
	// action listener for the play_back button
	//
	speechFrame_d.play_back_d.addActionListener(new ActionListener() {
		
		public void actionPerformed(ActionEvent e) {
		    
		    // if recording has not taken place before
		    // playback pop up a message asking the user to
		    // record first..
		    //
		    if(!record_event) {
			JFrame frame = new JFrame("Warning"); 
			String warningMessage = new 
			    String("Need to record audio data before you playback.");
			JOptionPane.showMessageDialog(frame,warningMessage);
		    }
		    
		    else {
			
			// disable the push to talk and the quit button
			// until this utterrance end 
			//
			speechFrame_d.push_to_talk_d.setEnabled(false);
			speechFrame_d.play_back_d.setEnabled(false);
			speechFrame_d.quit_button_d.setEnabled(false);
			action_state_d = PLAYBACK;
		    
			// switch to write mode
			//
			audioInterface.mode_d = audioInterface.WRITE;
			
			// create an SourceDataLine object and open the line
			//
			audioInterface.open();
			
			// start the line
			//
			audioInterface.start();
			
			AudioSignal signal_write = new AudioSignal();    
			
			// set the audioFormat to the signal object
			//
			signal_write.setFormat(audioInterface.getAudioFormat());
			
		   	// get the audioConfig object
			//
			audio = speechFrame_d.getAudioData();
			
			// make sure the object is not null. If null
			// set the default values
			//
			if (audio == null) {
			    
			    // set the data to the signal object
			    //
			    signal_write.setData(audio_data);   
			    playback_mode_d = PLAYBACK_ALL;
			}
			
			// if the object is not null then extract the
			// audio parameters from the audioConfig
			// object ad set to the AudioFormat object
			//
			else {
			    audioInterface.setAudioConfig(audio);			    
			    
			    // loop all values
			    //
			    for (int i = 0;
				 i < audio.getAssociation().size();
				 i++) {
				
				// check whether the name tag equals
				// ChannelDisplayed and if so get the
				// value
				//
				if (audio.getName().get(i)
				    .equals("PlaybackMode")) {
				    String playbackmode = 
					((String)(audio.getValue().get(i)));
				    
				    // if the parsed string is equal to "SIGNAL_ONLY"
				    // set the palyback_mode_d to signal_only
				    //
				    if(playbackmode.equals("SIGNAL_ONLY")) {
					
					// set the decimal format
					//
					DecimalFormat df = new DecimalFormat("0.###");
					
					// round off the values to third significant decimal point
					//
					Float  start = Float.valueOf(df.format((double)
									       (start_index.floatValue())));
					Float  stop = Float.valueOf(df.format((double)
									      (stop_index.floatValue())));
					
					// get the start and the stop sample number
					//
					int start_sample = (int)(start_index.floatValue() * 
								 (float)format_d.getSampleRate());
					int stop_sample = (int)(stop_index.floatValue() * 
								(float)format_d.getSampleRate());
					
					int f = 0;
					int num_channels = audioInterface.getNumOfChannels();
					
					// initialise the float array
					//
					float[][] data_endpointed = new float [num_channels][stop_sample-start_sample+1];
					
					// put each channel in a separate float array and set
					// it to the frame that is to be sent
					//
		      			for(int k = 0; k < num_channels; k++) {
					    for( int j = start_sample; j < stop_sample; j++) {
						data_endpointed[k][f] = audio_data[k][j]; 
						f++;
					    }
					    f = 0; 
					} 
					
					// set the data to the signal object
					//
					signal_write.setData(data_endpointed);   
					playback_mode_d = PLAYBACK_SIGNAL_ONLY;
				    }
				    
				    // else set it to palyback_all;
				    //
				    else {
					
					// set the data to the signal object
					//
					signal_write.setData(audio_data);   
					playback_mode_d = PLAYBACK_ALL;   
				    }			       
				}
			    }
			}
		    
		    // pass the signal object to the startPlayback
		    // function of the audioInterface for playback
		    //
		    audioInterface.startPlayBack(signal_write);
		    System.out.println("Playback has started");
		    
		    // disable the push to talk and the quit button
		    // until this utterrance end 
		    //
		    speechFrame_d.push_to_talk_d.setEnabled(true);
		    speechFrame_d.play_back_d.setEnabled(true);
		    speechFrame_d.quit_button_d.setEnabled(true);
		    
		    }
		}
	    });
	
	// action listener for the push to talk button
	//
	speechFrame_d.push_to_talk_d.addActionListener(new ActionListener() {
		
		public void actionPerformed(ActionEvent e) {
		    String prog = null;
		    
		    try {
			
			// set the flag to true
			//
			record_event = true;
			
			// initialise the audiointerface object
			//
			audioInterface = new AudioInterface();
			
			// reset the display
			//
			speechFrame_d.speech_plot_d.reset();
			
			// set the mode to realtime
			//
			speechFrame_d.speech_plot_d.setMode(true);
			
			// set the flags
			//
			stop_d = 0;
			end_points = 0;
			audio_ready_ack_count = 0;
			utterance_end_ack_count = 0;
			action_state_d = IDLE;
			if (prog == null) prog = "main";
			start_index =  new Float(0.0);
			stop_index = new Float(0.0);
			unicode_line = new String();
			
			// create a new frame and send the audio_ready signal
			//
			GFrame fr = new Clause(prog);
					
			// get the audioConfig object
			//
			audio = speechFrame_d.getAudioData();
			
			// make sure the object is not null. If null
			// set the default values
			//
			if (audio == null) {
			    audioInterface.setAudioFormat(SPEECH);
			    channel_display = 1;
			    buffer_size = 16000;
			    
			}
			
			// if the object is not null then extract the
			// audio parameters from the audioConfig
			// object ad set to the AudioFormat object
			//
			else {
			    audioInterface.setAudioConfig(audio);
			    			    
			    // loop all values
			    //
			    for (int i = 0; i < audio.getAssociation().size(); i++) {
				
				// check whether the name tag equals
				// ChannelDisplayed and if so get the
				// value
				//
				if (audio.getName().get(i).equals("ChannelDisplayed")) {
				    channel_display = (int)(Float.parseFloat((String)(audio.getValue().get(i))));
				    System.out.println("channel_display" + channel_display);
				}
				
				// check whether the name tag equals
				// ChannelDisplayed and if so get the
				// value
				//
				if (audio.getName().get(i)
				    .equals("PlaybackMode")) {
				    String playbackmode = 
					((String)(audio.getValue().get(i)));
				}
				
				// check whether the name tag equals
				// BufferSize and if so get the value
				//
				else if (audio.getName().get(i).equals("BufferSize")) {
				    
				     float buffer_size_in_secs = (float)
					(Float.parseFloat
					 ((String)(audio.getValue().get(i))));
				    
				    buffer_size = (int) (buffer_size_in_secs * 
							     audioInterface.getSampleRate());
				    System.out.println("buffer_size" +
						       buffer_size);
				}
				
				// check whether the name tag equal
				//
				else if (audio.getName().get(i).equals("FileFormat")) {
				    fr.setProperty(":file_format",(String)(audio.getValue().get(i)));
				}
				    
			    }
			}
				  
				
			// get the audioConfig object
			//
			detector = speechFrame_d.getDetectorData();
			
			// make sure the object is not null. If null
			// set the default values
			//
			if (detector != null) {
			    
			    // loop all values
			    //
			    for (int i = 0; i < detector.getAssociation().size(); i++) {
				
				// set the channel to be processed
				//
				if (detector.getName().get(i).equals("channel_d")) {
				    
				    fr.setProperty(":channel_d",
						   (Float.parseFloat
						    ((String)
						     (detector.getValue().
						      get(i)))));
				}
				
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("frame_duration_d")) {
				    
				    fr.setProperty(":frame_duration_d",(Float.parseFloat
									((String)
									 (detector.getValue()
									  .get(i)))));
				}
				
				// set the window duration
				//
				else if (detector.getName().get(i).equals("window_duration_d")) {
				    
				    fr.setProperty(":window_duration_d",(Float.parseFloat
									 ((String)
									  (detector.getValue()
									   .get(i)))));
				}
				
					
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("nominal_signal_d")) {
				    
				    fr.setProperty(":nominal_signal_d",(Float.parseFloat
									((String)
									 (detector.getValue()
									  .get(i)))));
				}

		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("signal_adaptation_delta_d")) {
				    
				    fr.setProperty(":signal_adaptation_delta_d",(Float.parseFloat
										 ((String)
										  (detector
										   .getValue()
										   .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("signal_adaptation_constant_d")) {
				    
				    fr.setProperty(":signal_adaptation_constant_d",(Float.parseFloat
										    ((String)
										     (detector
										      .getValue()
										      .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("nominal_noise_d")) {
				    
				    fr.setProperty(":nominal_noise_d",(Float.parseFloat
								       ((String)
									(detector
									 .getValue()
									 .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("noise_adaptation_delta_d")) {
				    
				    fr.setProperty(":noise_adaptation_delta_d",(Float.parseFloat
										((String)
										 (detector
										  .getValue()
										  .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("noise_adaptation_constant_d")) {
				    
				    fr.setProperty(":noise_adaptation_constant_d",(Float.parseFloat
										   ((String)
										    (detector
										     .getValue()
										     .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("noise_floor_d")) {
				    
				    fr.setProperty(":noise_floor_d",(Float.parseFloat
								     ((String)
								      (detector
								       .getValue()
								       .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("utterance_delta_d")) {
				    
				    fr.setProperty(":utterance_delta_d",(Float.parseFloat
									 ((String)
									  (detector
									   .getValue()
									   .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("min_utt_dur_d")) {
				    
				    fr.setProperty(":min_utt_dur_d",(Float.parseFloat
								     ((String)
								      (detector
								       .getValue()
								       .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("min_utt_sep_d")) {
				    
				    fr.setProperty(":min_utt_sep_d",(Float.parseFloat
								     ((String)
								      (detector
								       .getValue()
								       .get(i)))));
				}
		
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("max_utt_dur_d")) {
				    
				    fr.setProperty(":max_utt_dur_d",(Float.parseFloat
								     ((String)
								      (detector
								       .getValue()
								       .get(i)))));
				}
				
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("zc_utt_thresh_d")) {
				    
				    fr.setProperty(":zc_utt_thresh_d",(Float.parseFloat
								       ((String)
									(detector
									 .getValue()
									 .get(i)))));
				}
				
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("preemph_coef_d")) {
				    
				    fr.setProperty(":preemph_coef_d",(Float.parseFloat
								      ((String)
								       (detector
									.getValue()
									.get(i)))));
				}
				
				// set the frame duration
				//
				else if (detector.getName().get(i).equals("pad_time_d")) {
				    
				    fr.setProperty(":pad_time_d",(Float.parseFloat
								  ((String)
								   (detector
								    .getValue()
								    .get(i)))));
				}
			    }
			}


			// create the neccesary keys and their
			// corresponding values
			//
			fr.setProperty(":program",prog);
			fr.setProperty(":audio_ready", 1);
			fr.setProperty(":utterance_id", utterance_id_d);
			fr.setProperty(":source_name","speech_recognition"); 
			fr.setProperty(":sample_rate", 
				       audioInterface.getSampleRate());
			fr.setProperty(":num_channels",
				       audioInterface.getNumOfChannels());
			fr.setProperty(":sample_bytes",
				       audioInterface.getSampleSize());
			fr.setProperty(":client_name" ,"IBM");
			
			// counter to keep track of the number of
			// button clicks
			//
			btn_press_counter_d = btn_press_counter_d + 1;
			System.out.println("\n");
			
			// print the number of button presses 
			//
			System.out.println("This is the "+ 
					   btn_press_counter_d +" Button press");
			System.out.println("");  
			System.out.println("Sending the audio ready" + 
					   "signal to the data" + 
					   "recorder server");
			
			// set the button_press_counter info in the
			// frame
			//
			fr.setProperty(":button_press_counter",
				       btn_press_counter_d); 
			send(fr);
			
			// once the audio_ready signal is sent the
			// state is set to audio_redy_ack
			//
			finite_state_d = AUDIO_READY_ACK;
			
			} 
		    
		    catch (Exception ex) {
			System.out.println("Caught exception in serverOp: " +ex.toString());
		    }
		    
		    // set the recording to true and set the display
		    // to realtime mode
		    //
		    speechFrame_d.setRecording(true);
		    speechFrame_d.play_back_d.setEnabled(false);
		    speechFrame_d.speech_plot_d.setMode(true);
		    
		    // disable the push to talk and the quit button
		    // until this utterrance end 
		    //
		    speechFrame_d.push_to_talk_d.setEnabled(false);
		    speechFrame_d.quit_button_d.setEnabled(false);
		    
		    // initialize the graphic display
		    //
		    float percentage_1 = (float) 0.5;
		    float percentage_2 = (float) 0.5;
		    float percentage_3 = (float) 0;
		    
		    // set the sampling rate
		    //
		    speechFrame_d.speech_plot_d.setSampleRate((int)(SPEECH.getSampleRate()));
		    
		    // set the data to the speech plot to null
		    //
		    speechFrame_d.speech_plot_d.setData(null);
		    javax.swing.SwingUtilities.invokeLater(new Runnable() {
			    public void run() {
				
				speechFrame_d.speech_plot_d.run();
			    }
			});
		    speechFrame_d.cards_d.repaint();	
		}
	    });
    }
    
    
    /**
     * This function checks for different properties of the frame it
     * receives. One of its uses is that it gets the process id and
     * server name of all the other servers by querying through the
     * Hub.  
     *
     * @param frame_a a Galaxy frame from Hub.
     *
     * @return a Galaxy frame to Hub.
     */
    public GFrame enableInput(GFrame frame_a) {
	
	String prog = null;
	
	// enable the push_to_talk and the quit buttons 
	//
	speechFrame_d.push_to_talk_d.setEnabled(true);
	speechFrame_d.quit_button_d.setEnabled(true);
	
	// set the recording to false
	//
	speechFrame_d.setRecording(false);
	prog = frame_a.getString(":input_string");
	
	if (prog != null) {
            speechFrame_d.rows_d.setForeground(Color.blue);
	    System.out.println("[System]: "+prog);
	    speechFrame_d.setText("[System]: "+ prog, 
				  SpeechRecognitionUIFrame.APPEND);
	}
	
	// get the file name and display in the main windows
	//
	prog = frame_a.getString(":filename");
	
	if (prog != null) {
	    speechFrame_d.rows_d.setForeground(Color.blue);
	    speechFrame_d.setText("File: " + prog + "/n", 
				  SpeechRecognitionUIFrame.APPEND);
	}

	try {
	    Environment env = getCurrentEnvironment();
       	} 
	catch (Exception ex) {
	    System.out.println("Caught exception in serverOpEnableInput: " + 
			       ex.toString());
	}
	return frame_a;
    }
    
    /**
     * It is used to reset the whole interface once the end of
     * utterance is sent. This method enables the pushtotalk and the
     * quit button which are diabled during recording.
     */    
    public void enableButton() {
	
	// enable the pushtotalk anf quit buttons
	//
	speechFrame_d.push_to_talk_d.setEnabled(true);
	speechFrame_d.play_back_d.setEnabled(true);
	speechFrame_d.quit_button_d.setEnabled(true);
	
	// set the recording to false
	//
	speechFrame_d.setRecording(false);
	
	// reset the stop flag to zero
	//
	stop_d = 0;
    }
   
    /**
     * Create Galaxy acknowledgement frame
     *
     * @param source_name_a source name for the signal.
     * @param destination_name_a destination name for the signal.
     * @param message_name_a a message intended to send.
     *
     * @return a Galaxy frame for acknowledgement a signal.
     */
    public GFrame acknowledgementSignal (String source_name_a, 
					 String destination_name_a,
					 String message_name_a) {
	
	// construct a new acknowledgement message
	//
	String prog = MAIN;

	// create a new frame
	//
	GFrame ack_frame = new Clause(prog);

	// set properties
	//
	ack_frame.setProperty(":source_name", source_name_a);
	ack_frame.setProperty(":" + destination_name_a + "_ack",
			      message_name_a);
	ack_frame.setProperty(":button_press_counter", 
			      btn_press_counter_d);
    
	// return the ack frame
	//
    	return ack_frame;
    }


    /**
     * Send Galaxy frame to hub.
     *
     * @param frame_a a Galaxy frame to be sent.
     *
     * @return a boolean value indicating status.
     */
    public boolean send(GFrame frame_a) {
	
	// get environment and send the frame
	//
	try {
	    Environment env = getCurrentEnvironment();
	    env.writeFrame(frame_a);
	}
	catch (Exception send) { 
	    System.out.println("Couldn't send the frame." + send);
	}
	
        // exit gracefully
        //
	return true;
    }
    
    /**
     * This method gets the data from the Audio Interface as a signal
     * object sends the data to the server side.
     *
     * @return a boolean value indicating status.
     */
    public boolean sendData() {

	// set some default value
	//
	int status_indicator;
	AudioSignal signal = new AudioSignal();
	float[][] data;
	
	// make sure there is enough data to get from the 
	// audioInterface's circularbuffer 
	//
	if ((status_indicator = audioInterface.read(signal,buffer_size))!= -1) {
	    System.out.println("The status_indicator value" +status_indicator);
	    
	    // if there is no data available then sleep for sometime
	    // ad try again
	    //
	    while(status_indicator == 0) {
		try {
		    Thread.sleep(10);
		}
		catch (Exception e) { }
		status_indicator = audioInterface.read(signal,buffer_size);
	    }
	    
	    // make sure we got data ehiel reading the circular buffer
	    //
	    if (status_indicator != 0) { 
		
		// get the data from the signal object
		//
		data = signal.getData();
		
		// get the format 
		//
		format_d = signal.getFormat();
		int channel_len = data.length;
		int data_len = data[0].length;
		int audio_channel_len = audio_data.length;
		int audio_data_len = audio_data[0].length;
		
		if (channel_len != audio_channel_len) {
		    System.out.println("The Number of channels differ in the sent and already stored data.");
		}
		System.out.println("This is data length"+audio_data[0].length);

		// initialise a float array
		//
		float[][] temp_audio_data = new float 
		    [audio_channel_len][data_len+audio_data_len];
		
		// copy the data in the audio_data array to the temporary array
		//
		if(audio_data_len != 0) {
		    for (int i = 0; i < audio_channel_len; i++) {
			for(int j = 0; j < audio_data_len; j++) {
			    temp_audio_data[i][j]  = audio_data[i][j];
			}
		    }
		}
		
		// add the data got from the read to the temporary
		// array
		//
		for(int i = 0; i < channel_len; i++) {
		    for(int j = audio_data_len; j < audio_data_len+data_len; j++) {
			temp_audio_data[i][j]= data [i][j - audio_data_len];
		    }
		}
		
		// copy back the temporary array to the audio_data
		// object
		//
		audio_data = temp_audio_data;
		System.out.println("the float buffer length of audio data" + 
				   audio_data.length);
		System.out.println("the float buffer length of audio data" + 
				   audio_data[0].length);
		
		// keep count of the number of data frames sent
		//
		data_frame_number_d += 1;
		
		// local variable
		//	    
		String prog = MAIN;
		
		// create a new Galaxy frame
		//
		GFrame data_frame = new Clause(prog);
		
		// set the properties for this frame
		//
		data_frame.setProperty(":raw_data", "raw_data");
		int num_channels = audioInterface.getNumOfChannels();
		int count = 0;
		
		// put each channel in a separate float array and set
		// it to the frame that is to be sent
		//
		while(count < num_channels) {
		    float[] channel_data = new float[data_len];
		    for( int i = 0; i < data_len; i++) {
			channel_data[i] = data[count][i];
		    }
		    data_frame.setProperty(":channel" + count,
					   new Float32(channel_data));
		    count++;
		}     
		
		// set the data frame number and source name info
		//
		data_frame.setProperty(":frame_index", data_frame_number_d);
		data_frame.setProperty(":source_name", "speech_recognition");
		
		// send the data frame
		//
		send(data_frame);
		System.out.println(data_frame_number_d + 
				   " frame has been sent.");		
		
		// set the mode to real time and also set the sample
		// rate
		//
		speechFrame_d.speech_plot_d.setMode(true);
		float[] data_sent = new float[data_len];
		
		// send the user defined channel to be diplayed on the
		// display monitor
		//
		for(int i=0;i<data_len;i++) {
		    data_sent[i] = data[0][i];
		    data_sent[i] = data[channel_display - 1][i];
		}

		System.out.println("the float buffer length sent to display" +
				   data_sent.length);
		speechFrame_d.speech_plot_d.setData(data_sent);
		
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
			    speechFrame_d.speech_plot_d.run();
			}
		    });
	    }
	}
	else {
	    
	    return false;
	}
	
	
	// exit gracefully
        //
        return true;	
    }    
    
   
    //-------------------------------------------------------------------------
    //
    // class-specific public methods that can be called directly from
    // the hub script:
    //
    //-------------------------------------------------------------------------
    
     /**
     * This method is used by the AudioRecorderServer to get the Hub's
     * process id and it's name. It also sends a frame with process_id
     * to query other process's id through the hub which in turn
     * distributes it to other servers.
     *
     * @param frame_a a Galaxy frame from Hub.
     */
    public void serverOpReinitialize(GFrame frame_a) {
	
	// extract the program from the incoming key
	//	
	String prog = frame_a.getString(":program");
	
	if (prog == null) prog = "main";
	
	// create a new frame and set to hub to query the process id
	// from other servers
	//
	GFrame fr = new Clause(prog);
	
	// set the key and the values
	//
	fr.setProperty(":int",1);
	fr.setProperty(":program", prog);
		
	// send the frame
	//
	try {
	    getCurrentEnvironment().writeFrame(fr);
	} 
	catch (Exception ex) {
	    System.out.println("Caught exception while writing to Hub");
	}
	
	// display welcome information in the main user interface window
	//
	speechFrame_d.setText("\n" + "Welcome to Speech Recognition Demo.", 
			      SpeechRecognitionUIFrame.APPEND);
	finite_state_d = INITIALIZATION;
    }
    
    
    /**
     * Returns back the frame.
     */
    public GFrame serverOpEchoFrame(GFrame frame) {
	return frame;
    }

    /**
     * This method receives all the frames that are sent from other
     * servers through the hub to the speech recognition
     * server. Depending on the state when the frame was received
     * different actions are taken.
     *
     * @param frame_a a Galaxy frame received from Hub.
     *
     * @return a GFrame return to Hub.
     */    
    public GFrame serverOpReceiveSignal (GFrame frame_a) {
	
	// check whether the current state is initialization
 	//	
	if (finite_state_d == INITIALIZATION) {
	
	    // enable input
	    //
	    enableInput(frame_a);
	    
	    // set the flag to zero
	    //
	    stop_d = 0;
	}
	
	// set the current state to audio_ready_ack
	//
	else if (finite_state_d == AUDIO_READY_ACK) {
	    
	    // get the string stored in the "speech_recognition_ack" key
	    //
	    String check = (String)frame_a.getProperty(":speech_recognition_ack");
	    	    
	    // get the filename and pat where the audio data is stored
	    // on the server side and print the path along with the
	    // filename on the output window in the client side
	    //
	    String prog = (String)frame_a.getProperty(":filename");
	    int code_count = unicode_count;
	    while (code_count > 0) {
		unicode_line +="\u2500";
		    code_count--; 
		    }
	    if (prog != null) {
		speechFrame_d.rows_d.setForeground(Color.blue);
		speechFrame_d.setText(unicode_line + "\n", 
				      SpeechRecognitionUIFrame.APPEND);
		speechFrame_d.setText(" File:" + prog + "\n", 
				      SpeechRecognitionUIFrame.APPEND);
	    }
	    
	    // check if the string equals audio_ready
	    //
	    if (check.equals("audio_ready") && audio_ready_ack_count == 0) {
		audio_ready_ack_count++;
		System.out.println("Received acknowledgement for audio ready");
	    }	    
	    
	    // check if the string equals audio_ready
	    //
	    else if (check.equals("audio_ready") && audio_ready_ack_count == 1) {
		audio_ready_ack_count++;
		System.out.println("Received acknowledgement for audio ready");
	    }	    
	    
	    // check if the acknowledgement has been got from both the servers
	    //
	    else if(check.equals("audio_ready") && audio_ready_ack_count == 2) {
		
		System.out.println("Received acknowledgement for audio ready");
		
		// set the mode to READ
		//
		audioInterface.mode_d = audioInterface.READ;
		
		// initialise the audio_data object that will contain
		// all the recorded audio data on the client side
		//
		audio_data = new float [audioInterface.getNumOfChannels()] [0];
	
		// try opening a line with the user defined audio
		// parameters. If audioFormat not supported then pop
		// up an error window
		//
		if (audioInterface.open()== false) {
		    frame = new JFrame(); 
		    JOptionPane.showMessageDialog(frame, 
						  "Format not Supported." + 
						  "Click ok to restart the demo.");
		    
		    // local variable
		    //	    
		    String prog_reset = MAIN;
		    
		    // create a new Galaxy frame
		    //
		    GFrame reset_frame = new Clause(prog_reset);
		    
		    // set the key and value to reset
		    //
		    reset_frame.setProperty(":reset", "reset");
		    
		    // send the reset frame so that all the states in
		    // the other servers get resetted.
		    //
		    send(reset_frame);
		    finite_state_d = AUDIO_READY;
		    enableButton();
		    
		    // return a null galaxy frame
		    //
		    return (GFrame)null;
		    
		}

		// start the line
		//
		audioInterface.start();
		
		System.out.println("System is ready to record");
		
		// start the recording thread and keep writing the audio data
		// into the circular buffer
		//
		audioInterface.startRecording();
	      
		// set the action state to recording
		//
		action_state_d = RECORDING;
		
		// print the status to the output window
		//
		speechFrame_d.setText("\n" + "    Recording..." + "\n", 
				      SpeechRecognitionUIFrame.APPEND);

		System.out.println("before send data");
		// send the first block of data to the server side
		//
		sendData();
		System.out.println("after send data");
		System.out.println("DATA SENT" + System.currentTimeMillis());
		
		// set the state to raw_data_transfer
		//
		finite_state_d = RAW_DATA_TRANSFER;
	    }	
	}  
	
	else if (finite_state_d == RAW_DATA_TRANSFER) {
	    
	    // get the string value from the "speech_recognition_ack" key 
	    //
	    String check = (String)frame_a.getProperty(":speech_recognition_ack");
	    
	    // check if the string is raw_data
	    //
	     if(check.equals("raw_data")) {
		 
		 System.out.println("ack for raw frame");
		 Integer frame_index = (Integer) frame_a.getProperty
		     (":frame_index");
		 System.out.println("Acknowledgement for the " + 
				    frame_index +" data frame.");

		 // check whether the end points have been detected or
		 // the stop button has been pressed
		 //
		 if (stop_d == 1 || end_points == 1) {
		     
		     // stop the recording
		     //
		     audioInterface.stopRecording();
		     
		     // stop the line
		     //
		     audioInterface.stop();
		     
		     // close the line
		     //
		     audioInterface.close();  
		     
		     speechFrame_d.setText("    End of Recoding." + "\n" ,
					   SpeechRecognitionUIFrame.APPEND);	     
		     // local variable
		     //		 
		     String prog = MAIN;
		     
		     // create a Galaxy frame
		     //
		     GFrame fr = new Clause(prog);
		     
		     // set the properties for this frame
		     //
		     fr.setProperty(":input_string", "End of Decoding.");
		     fr.setProperty(":utterance_status", "end");
		     fr.setProperty(":source_name","speech_recognition");
		     
		     // send the frame through Hub
		     //
		     send(fr);
		     System.out.println("end of utterance"+System.currentTimeMillis());
		     System.out.println("The end of utterance has been sent.");
		
		     
		     // get the user defined channel of data from the
		     // audio_data object
		     //
		     float[] data_float = new float [audio_data[0].length];
		     for(int i = 0; i <audio_data[0].length;i++) {
			 data_float[i] = audio_data[channel_display - 1][i];
			 //data_float[i] = audio_data[0][i];
		     } 
		     
		    // set the overall plot
		    //
		    speechFrame_d.speech_plot_d.setMode(false);
		    float percentage_1 = (float) 0.5;
		    float percentage_2 = (float) 0.5;
		    float percentage_3 = (float) 0;
		    
		    speechFrame_d.speech_plot_d.
			setStartTime(start_index.floatValue());
		    speechFrame_d.speech_plot_d.
			setEndTime(stop_index.floatValue()); 
		    speechFrame_d.speech_plot_d.
			setData(data_float);
		    
		    javax.swing.SwingUtilities.invokeLater(new Runnable() {
			    public void run() {
				speechFrame_d.speech_plot_d.run();
			    }
			});
		    
		    // change the finite state
		    //
		    finite_state_d = END_OF_UTTERANCE;
		    action_state_d = IDLE;
		 }
		 else {
		    
		    // keep sending the data till the end points are
		    // detected or stop is pressed
		    //
		    sendData();
		    System.out.println("DATA SENT"+System.currentTimeMillis());
		 } 
		 
	     } 
	}
	
	// check if the state is end_of_utterance state
	//
	else if (finite_state_d == END_OF_UTTERANCE) {
	    
	    String check = (String)frame_a.getProperty(":speech_recognition_ack");
	    
	    //  here we wait for three acks. one from the signal
	    //  detector server and the second from the data_recorder
	    //  server and the third from the recognizer
	    //
	    if (check.equals("utterance_status") && utterance_end_ack_count == 0) {
		
		System.out.println("ack for end of utterance");
		utterance_end_ack_count++;
	    }

 
	    // waiting on the second ack
	    // 
	    else if (check.equals("utterance_status") && 
		     utterance_end_ack_count == 1) {
		System.out.println("ack for end of utterance");
		utterance_end_ack_count++;
	    }

	    // waiting on the third ack
	    // 
	    else if(check.equals("utterance_status") 
		    && utterance_end_ack_count == 2) {
		System.out.println("Acknowledgement for the end of utterance signal.");
		speechFrame_d.setText("    End of Decoding.",
				      SpeechRecognitionUIFrame.APPEND);
		speechFrame_d.setText("\n", SpeechRecognitionUIFrame.APPEND);
		int code_count = unicode_count;
		unicode_line = new String();
		while (code_count > 0) {
		    unicode_line +="\u2500";
		    code_count--; 
		}
		 speechFrame_d.setText(unicode_line + "\n" +"\n", 
				       SpeechRecognitionUIFrame.APPEND);
		System.out.println("*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*" + 
				   "_*_*_*_*_*_*_*_*_*_*_*_*");
		enableButton();
	    }
	}
	
	// return a null galaxy frame
	//
	return (GFrame)null;
    }
  
     /**
     * Gets the hypothesis frame and display it on the screen
     *
     * @param frame_a a Galaxy frame containing the hypotheses
     *
     * @return GFrame return back a null GFrame
     */
    public GFrame serverOpDisplayHypotheses(GFrame frame_a) {
	
	String hypotheses = (String) frame_a.getProperty(":input_string");
	speechFrame_d.setText("       The Hypotheses:  " + hypotheses + "\n",SpeechRecognitionUIFrame.APPEND);
	return (GFrame)null;
    }
    

    /**
     * This function gets the endpoints from the signal detector and
     * sets the end_points flag to 1. It also sends the endpointed
     * data to the data recorder.
     *
     * @param frame_a a Galaxy frame to be sent.
     *
     * @return a boolean value indicating status.
     */
    public GFrame serverOpEndPoints(GFrame frame_a) {
	
	// get the start and the stop times
	//
	 start_index = (Float) frame_a.getProperty(":start_time");
	 stop_index = (Float) frame_a.getProperty(":stop_time");
	
	// set the decimal format
	//
	DecimalFormat df = new DecimalFormat("0.###");
	
	// round off the values to third significant decimal point
	//
	Float  start = Float.valueOf(df.format((double)
					       (start_index.floatValue())));
	Float  stop = Float.valueOf(df.format((double)
					      (stop_index.floatValue())));
	
	// display the start and the stop time on the text field
	//
	speechFrame_d.setText("        Start Time: "+ start + " secs" +"    ",
			      SpeechRecognitionUIFrame.APPEND);
	speechFrame_d.setText("End Time: "+ stop + " secs" + "\n", 
			      SpeechRecognitionUIFrame.APPEND);
	System.out.println("end points calculated"+ 
			   System.currentTimeMillis());
	
	// get the start and the stop sample number
	//
	int start_sample = (int)(start_index.floatValue() * 
				 (float)format_d.getSampleRate());
	int stop_sample = (int)(stop_index.floatValue() * 
				(float)format_d.getSampleRate());
	
	// initialise the float array
	//
	float[] data_endpointed = new float [stop_sample - start_sample + 1];
	int f = 0;
	
	int channel_count = 0;

	
	// local variable
	//	    
	String prog = MAIN;
	
	// create a new Galaxy frame
	//
	GFrame data_frame = new Clause(prog);


	int num_channels = audioInterface.getNumOfChannels();
		
	// put each channel in a separate float array and set
	// it to the frame that is to be sent
	//
	while(channel_count < num_channels) {
	    for( int i = start_sample; i < stop_sample; i++) {
		data_endpointed[f] = audio_data[channel_count][i];
		f++;
	    }
	    data_frame.setProperty(":channel"+channel_count,new Float32(data_endpointed));
	    f = 0;
	    channel_count++;
	}    
	
	// set the endpointed data in the frame
	//
	data_frame.setProperty(":raw_data_endpointed", "endpointed");
	data_frame.setProperty(":source_name", "speech_recognition");
	
	// send the data frame to the data recorder
	//
	send(data_frame);

	// set the end_pointd flag to 1
	//
	end_points = 1;
	
	return (GFrame) null;
    }


     /**
     * Displays the start of decoding
     *
     * @param frame_a a Galaxy frame to be sent.
     *
     * @return a boolean value indicating status.
     */
    public GFrame serverOpDisplayDecoding(GFrame frame_a) {
	speechFrame_d.setText("    Decoding......" + "\n",
			      SpeechRecognitionUIFrame.APPEND);
	return (GFrame)null;
    }
    

    
     /**
     * resets the client side all the other servers
     *
     * @param frame_a a Galaxy frame to be sent.
     *
     * @return a boolean value indicating status.
     */
    public GFrame serverOpResetState(GFrame frame_a) {

	finite_state_d = AUDIO_READY;
	enableButton();
	
	// local variable
	//	    
	String prog_reset = MAIN;
	GFrame reset_frame = new Clause(prog_reset);
	
	// set the key and value to reset
	//
	reset_frame.setProperty(":reset_all", "reset");
	
	// send the reset frame so that all the states in
	// the other servers get resetted.
	//
	send(reset_frame);
	 JFrame frame = new JFrame("Error Checking"); 
	    String warningMessage = new 
		String("Model Compatibility: The sampling frequency you have" + 
		       "choosen is not compatible with the model.Please go to " + 
		       "the Configuration menu to change it");
	    JOptionPane.showMessageDialog(frame, warningMessage, "Error Checking", 
					  JOptionPane.WARNING_MESSAGE);
	    speechFrame_d.setText(" ",SpeechRecognitionUIFrame.CLEAR);

	return (GFrame)null;
    }


    
    //-------------------------------------------------------------------------
    //
    // class-specific other private methods:
    //  
    //
    //-------------------------------------------------------------------------
    
    /** 
     * Convert float array to byte array.
     *
     * @param byteSound User provided byte array to return result in.
     * @param dbuf User provided float array to convert.
     */
    private void floatToByte(byte[] byteSound, float [][] dbuf) {
	
	// check whether this will work
	//
	int bufsz = dbuf[0].length;
	int ib = 0;
	if(format_d.isBigEndian()) {
	    for(int i = 0; i < bufsz; i++) {
		short y = (short)Math.round(32767 * dbuf[0][i]);
		byteSound[ib] = (byte)(y >> 8);
		ib++;
		byteSound[ib] = (byte)(y & 0x00ff);
		ib++;
	    }
	} 
	else {
	    for(int i=0;i<bufsz;i++) {
		short y = (short)Math.round(32767 * dbuf[0][i]);
		byteSound[ib] = (byte)(y & 0x00ff);
		ib++;
		byteSound[ib] = (byte)(y >> 8);
		ib++;
            }
	}
    }
    
    /** 
     * Convert byte array to float array.
     *
     * @param dbuf User provided float array to return result in.
     * @param dbuf User provided byte array to convert.
     * @param bufsz Number of float samples to write.
     */
    private void byteToFloat(float [][] dbuf, byte[] bbuf, int bufsz) {
        int ib=0;
        if(format_d.isBigEndian()) {
            for(int i = 0; i < bufsz; i++) {
                short y = bbuf[ib];
                y = (short)(y << 8);
                y |= (bbuf[ib+1]&0x00ff);
                ib += 2;
                dbuf[0][i] = y / 32767.f;
            }
        } 
	else {
            for(int i = 0; i < bufsz; i++) {
                short y = (short)bbuf[ib+1];
                y = (short)(y << 8);
                y |= (bbuf[ib]&0x00ff);
                ib += 2;
                dbuf[0][i] = y / 32767.f;
            }
        }
    }	
    
     


    //------------------------------------------------------------------------
    //
    // class-specific public methods:
    //  error handler code
    //
    //------------------------------------------------------------------------
  
    /**
     * Method to simply print the passed error, a stack trace, and then exit.
     *
     *@param e Exception that was caught
     */
    private void handleError(Exception e){
	System.out.println("Exception in ISIPAudioRecorder: " + e);
	e.printStackTrace();
    }   
}

