001/**
002 * Portions Copyright 2001 Sun Microsystems, Inc.
003 * Portions Copyright 1999-2001 Language Technologies Institute, 
004 * Carnegie Mellon University.
005 * All Rights Reserved.  Use is subject to license terms.
006 * 
007 * See the file "license.terms" for information on usage and
008 * redistribution of this file, and for a DISCLAIMER OF ALL 
009 * WARRANTIES.
010 */
011package com.sun.speech.freetts.relp;
012
013import com.sun.speech.freetts.FeatureSet;
014import com.sun.speech.freetts.Item;
015import com.sun.speech.freetts.ProcessException;
016import com.sun.speech.freetts.Relation;
017import com.sun.speech.freetts.Unit;
018import com.sun.speech.freetts.Utterance;
019import com.sun.speech.freetts.UtteranceProcessor;
020import com.sun.speech.freetts.util.Utilities;
021
022/**
023 * Concatenates the Units in the given Utterance to the target_lpc
024 * result. This class is an UtteranceProcessor. It defines a method
025 * <code> processUtterance </code> that helps populate the
026 * target_lpcres relation.
027 *
028 * @see LPCResult
029 */
030public class UnitConcatenator implements UtteranceProcessor {
031    static private final int ADD_RESIDUAL_PULSE = 1;
032    static private final int ADD_RESIDUAL_WINDOWED = 2;
033    static private final int ADD_RESIDUAL = 3;
034    public final static String PROP_OUTPUT_LPC = 
035        "com.sun.speech.freetts.outputLPC";
036    private boolean outputLPC = Utilities.getBoolean(PROP_OUTPUT_LPC);
037
038
039    /**
040     * Concatenate the Units in the given Utterance to the target_lpc
041     * result.
042     *
043     * @param utterance the Utterance to do concatenation
044     *
045     * @see LPCResult
046     *
047     * @throws ProcessException if an error occurs while processing
048     *     the utterance
049     */
050    public void processUtterance(Utterance utterance) throws ProcessException {
051        float uIndex = 0, m;
052        int pmI = 0, targetResidualPosition = 0,
053            targetStart = 0, targetEnd, residualSize, numberFrames;
054        Relation unitRelation = utterance.getRelation(Relation.UNIT);
055
056        SampleInfo sampleInfo;
057        
058
059        int addResidualMethod = ADD_RESIDUAL;
060        
061        String residualType = utterance.getString("residual_type");
062        if (residualType != null) {
063            if (residualType.equals("pulse")) {
064                addResidualMethod = ADD_RESIDUAL_PULSE;
065            } else if (residualType.equals("windowed")) {
066                addResidualMethod = ADD_RESIDUAL_WINDOWED;
067            }
068        }
069
070        sampleInfo = (SampleInfo) utterance.getObject(SampleInfo.UTT_NAME);
071        if (sampleInfo == null) {
072            throw new IllegalStateException
073                ("UnitConcatenator: SampleInfo does not exist");
074        }
075
076        LPCResult lpcResult = (LPCResult) utterance.getObject("target_lpcres");
077        lpcResult.setValues(sampleInfo.getNumberOfChannels(),
078                            sampleInfo.getSampleRate(),
079                            sampleInfo.getResidualFold(),
080                            sampleInfo.getCoeffMin(),
081                            sampleInfo.getCoeffRange());
082
083        // create the array of final residual sizes
084        int[] targetTimes = lpcResult.getTimes();
085        int[] residualSizes = lpcResult.getResidualSizes();
086
087        int samplesSize = 0;
088        if (lpcResult.getNumberOfFrames() > 0) {
089                samplesSize = targetTimes[lpcResult.getNumberOfFrames() - 1];
090        }
091        lpcResult.resizeResiduals(samplesSize);
092        
093        for (Item unitItem = unitRelation.getHead(); unitItem != null;
094             unitItem = unitItem.getNext()) {
095            FeatureSet featureSet = unitItem.getFeatures();
096
097            targetEnd = featureSet.getInt("target_end");
098            Unit unit = (Unit) featureSet.getObject("unit");
099            int unitSize = unit.getSize();
100
101            uIndex = 0;
102            m = (float)unitSize/(float)(targetEnd - targetStart);
103            numberFrames = lpcResult.getNumberOfFrames();
104            
105            // for all the pitchmarks that are required
106            for (; (pmI < numberFrames) &&
107                     (targetTimes[pmI] <= targetEnd); pmI++) {
108
109                Sample sample = unit.getNearestSample(uIndex);
110                
111                // Get LPC coefficients by copying
112                lpcResult.setFrame(pmI, sample.getFrameData());
113
114                // Get residual by copying
115                residualSize = lpcResult.getFrameShift(pmI);
116                
117                residualSizes[pmI] = residualSize;
118                byte[] residualData = sample.getResidualData();
119
120                if (addResidualMethod == ADD_RESIDUAL_PULSE) {
121                    lpcResult.copyResidualsPulse
122                        (residualData, targetResidualPosition, residualSize);
123                } else {
124                    lpcResult.copyResiduals
125                        (residualData, targetResidualPosition, residualSize);
126                }
127                
128                targetResidualPosition += residualSize;
129                uIndex += ((float) residualSize * m);
130            }
131            targetStart = targetEnd;
132        }
133        lpcResult.setNumberOfFrames(pmI);
134
135        if (outputLPC) {
136            lpcResult.dump();
137        }
138    }
139
140    /**
141     * Converts this object to a string
142     * @return the string form of this object.
143     */
144    public String toString() {
145        return "UnitConcatenator";
146    }
147}
148