/**
 * Copyright 2002 DFKI GmbH.
 * 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 de.dfki.lt.freetts.mbrola;

import java.nio.ByteOrder;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.sound.sampled.AudioFormat;

import com.sun.speech.freetts.ProcessException;
import com.sun.speech.freetts.Utterance;
import com.sun.speech.freetts.UtteranceProcessor;
import com.sun.speech.freetts.audio.AudioPlayer;

/**
 * Supports generating audio output from an MBROLA-synthesized utterance. This
 * is an utterance processor. The primary method, <code> processUtterance
 * </code> takes an utterance containing an open BufferedInputStream, from
 * which to read raw audio data provided by the external MBROLA binary. The
 * audio data is read and sent to the proper audio player.
 *
 */
public class MbrolaAudioOutput implements UtteranceProcessor {
    /** Logger instance. */
    private static final Logger LOGGER =
        Logger.getLogger(MbrolaAudioOutput.class.getName());

    /**
     * The raw audio data coming out of MBROLA is in native byte order,
     * 16 kHz, 16 bit, mono
     */
    private final static AudioFormat MBROLA_AUDIO =
            new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                            16000, // samples per second
                            16, // bits per sample
                            1, // mono
                            2, // nr. of bytes per frame
                            16000, // nr. of frames per second
                            ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN);
    
    /**
     * Reads audio data generated by the external MBROLA binary for the given
     * Utterance. The data is read from the open BufferedInputStream associated
     * with the Utterance, and written into the AudioPlayer.
     *
     * @param  utterance  the utterance to generate waves
     *
     * @throws ProcessException if an IOException is thrown during the
     *         processing of the utterance
     */
    public void processUtterance(Utterance utterance) throws ProcessException {
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("=== " +
                                 utterance.getString("input_text"));
        }

        AudioPlayer audioPlayer = utterance.getVoice().getAudioPlayer();

	audioPlayer.setAudioFormat(MBROLA_AUDIO);
	audioPlayer.setVolume(utterance.getVoice().getVolume());

        // The AudioPlayer interface currently does not allow streaming audio.
        // We need to know the total number of samples that will be written
        // before we can start writing them. Therefore, we need to load all
        // audio data for this utterance into RAM.
        
        List audioData = (List) utterance.getObject("mbrolaAudio");
        if (audioData == null) {
            throw new ProcessException
                ("No \"mbrolaAudio\" object is associated with utterance");
        }

        // total number of audio bytes

        int totalSize;
        try {
            totalSize = utterance.getInt("mbrolaAudioLength");
        } catch (NullPointerException npe) {
            totalSize = 0;
        }

        audioPlayer.begin(totalSize);

        for (Iterator it = audioData.iterator(); it.hasNext();) {
            byte[] bytes = (byte[]) it.next();
            if (!audioPlayer.write(bytes)) {
                throw new ProcessException
                    ("Cannot write audio data to audio player");
            }
        }

        if (!audioPlayer.end()) {
            throw new ProcessException("audio player reports problem");
        }
    }

    
    /**
     * 
     * Returns the string form of this object
     * 
     * @return the string form of this object
     */
    public String toString() {
	return "MbrolaAudioOutput";
    }
}




