/*
* Created on 10.05.2005
*
*
* @author Felix Burkhardt
*/
package com.tlabs.speechalyzer;
import java.io.File;
import java.util.Collection;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jdom.Attribute;
import org.jdom.Element;
import com.felix.util.Constants;
import com.felix.util.FileUtil;
import com.felix.util.KeyValue;
import com.felix.util.KeyValues;
import com.felix.util.NumberToWord;
import com.felix.util.Preprocessor;
import com.felix.util.StringUtil;
import com.tlabs.speechalyzer.classifier.Categories;
import com.tlabs.speechalyzer.classifier.ClassificationResult;
import com.tlabs.speechalyzer.emotions.Emotion;
import com.tlabs.speechalyzer.emotions.VocabManager;
import com.tlabs.speechalyzer.synthesizer.EmofiltSynthesizer;
import com.tlabs.speechalyzer.synthesizer.ISynthesizer;
import com.tlabs.speechalyzer.synthesizer.IvonaSynthesizer;
import com.tlabs.speechalyzer.synthesizer.SvoxSynthesizer;
import com.tlabs.speechalyzer.util.EmlUtils;
/**
* @author Burkhardt.Felix
*
* Description:
*
*/
public class RecFile {
public File _file;
public String _dialog = "", _name = "", _path = "", _transcript = "",
_recognized = "", _emotionMLDimensionSet = "",
_emotionMLCategorySet = "", _emotionMLAppraisalSet = "",
_emotionMLActionTendencySet = "";
public ClassificationResult _classificationResult;
public Emotion[] _lab = null;
public long _size;
private KeyValues _config, _annotations;
private Logger _logger;
private Categories _categories;
private final String _transcriptIdentifier;
private final String _recognitionIdentifier;
private String _defaultOriginator = "";
/**
* @param _file
* @param _dialog
* @param _name
*/
public RecFile(String path, KeyValues config) {
_config = config;
_defaultOriginator = _config.getString("defaultUser");
_transcriptIdentifier = _config.getString("transcriptIdentifier");
_recognitionIdentifier = _config.getString("recognitionIdentifier");
_logger = Logger.getLogger("com.tlabs.speechalyzer.RecFile");
_file = new File(path);
_size = _file.length();
File parFile = _file.getParentFile();
if (parFile != null) {
_dialog = parFile.getName();
}
_path = path;
_name = _file.getName();
_categories = new Categories(_config.getString("categories"));
loadAnnotations();
}
public void initAnnotations() {
_lab = new Emotion[0];
_annotations = new KeyValues("", "\n", ":");
_transcript = "";
_recognized = "";
_classificationResult = null;
}
public void setDefaultOriginator(String dfo) {
_defaultOriginator = dfo;
}
public String toString() {
String ret = "";
String pathS = _path != null ? _path : "null";
String sizeS = "0";
if (_file != null)
sizeS = String.valueOf(_file.length());
String transS = _transcript != null ? _transcript : "null";
String labS = _lab != null ? labToString() : "null";
String predS = _classificationResult != null ? _classificationResult
.toString() : "null";
ret = "_path: " + pathS + "; _size: " + sizeS + "; _transcript: "
+ transS + "; _lab: " + labS + " cr: " + predS;
return ret;
}
public boolean hasLabel() {
if (_lab != null && _lab.length > 0)
return true;
return false;
}
public boolean hasPrediction() {
if (_classificationResult != null)
return true;
return false;
}
public void addInfoAndEmotion(Element infoElem, Emotion emotion) {
emotion.set_originator(_defaultOriginator);
if (infoElem != null) {
String test = infoElem.getTextTrim();
if (StringUtil.isFilled(test)) {
String originatorIdentifier = _config
.getString("originatorIdentifier");
String originTest = StringUtil.getStringBetween(test,
originatorIdentifier + ":", Emotion.INFO_SEPARATOR);
if (originTest != null && emotion != null) {
emotion.set_originator(originTest);
}
String transcriptTest = StringUtil.getStringBetween(test,
_transcriptIdentifier + ":", Emotion.INFO_SEPARATOR);
if (transcriptTest != null) {
storeTranscript(transcriptTest);
}
String recoTest = StringUtil.getStringBetween(test,
_recognitionIdentifier + ":", Emotion.INFO_SEPARATOR);
if (recoTest != null) {
storeRecongnition(recoTest);
}
}
}
addEmotion(emotion);
}
public void set_emotionMLDimensionSet(String _emotionMLDimensionSet) {
this._emotionMLDimensionSet = _emotionMLDimensionSet;
}
public void set_emotionMLCategorySet(String _emotionMLCategorySet) {
this._emotionMLCategorySet = _emotionMLCategorySet;
}
public void set_emotionMLAppraisalSet(String _emotionMLAppraisalSet) {
this._emotionMLAppraisalSet = _emotionMLAppraisalSet;
}
public void set_emotionMLActionTendencySet(
String _emotionMLActionTendencySet) {
this._emotionMLActionTendencySet = _emotionMLActionTendencySet;
}
public Collection<Element> getEmotionMLElement() {
Vector<Element> returnVec = new Vector<Element>();
if (hasLabel()) {
for (int i = 0; i < _lab.length; i++) {
Element emoElem = new Element(Emotion.EMOTIONML_ELEM_EMOTION,
Emotion.EMOTIONML_NAMESPACE);
if (StringUtil.isFilled(_emotionMLCategorySet))
emoElem.setAttribute(Emotion.EMOTIONML_ATT_CATEGORYSET,
_emotionMLCategorySet);
if (StringUtil.isFilled(_emotionMLDimensionSet))
emoElem.setAttribute(Emotion.EMOTIONML_ATT_DIMENSIONSET,
_emotionMLDimensionSet);
if (StringUtil.isFilled(_emotionMLAppraisalSet))
emoElem.setAttribute(Emotion.EMOTIONML_ATT_APPRAISALSET,
_emotionMLAppraisalSet);
if (StringUtil.isFilled(_emotionMLActionTendencySet))
emoElem.setAttribute(
Emotion.EMOTIONML_ATT_ACTIONTENDENCYSET,
_emotionMLActionTendencySet);
Element refElem = Emotion.getExpressedByReference();
refElem.setAttribute(Emotion.EMOTIONML_ATT_URI, "file:///"
+ _path);
emoElem.addContent(refElem);
Emotion emotion = (Emotion) _lab[i];
Element elem = null;
if (emotion.isCategory()) {
elem = Emotion.getCategory();
} else if (emotion.isDimension()) {
elem = Emotion.getDimension();
} else if (emotion.isAppraisal()) {
elem = Emotion.getAppraisal();
} else if (emotion.isActionTendency()) {
elem = Emotion.getActionTendemcy();
}
elem.setAttribute(new Attribute(Emotion.EMOTIONML_ATT_NAME,
emotion.get_name()));
elem.setAttribute(new Attribute(Emotion.EMOTIONML_ATT_VALUE,
emotion.get_value()));
elem.setAttribute(new Attribute(
Emotion.EMOTIONML_ATT_CONFIDENCE, emotion
.get_confidence()));
emoElem.addContent(elem);
Element infolem = Emotion.getInfo();
String infoS = "";
String transcriptIdentifier = _config
.getString("transcriptIdentifier");
String recognitionIdentifier = _config
.getString("recognitionIdentifier");
String originatorIdentifier = _config
.getString("originatorIdentifier");
if (hasTranscript()) {
infoS += transcriptIdentifier + ":" + _transcript
+ Emotion.INFO_SEPARATOR;
}
if (hasRecognition()) {
infoS += recognitionIdentifier + ":" + _recognized
+ Emotion.INFO_SEPARATOR;
}
infoS += originatorIdentifier + ":" + emotion.get_originator()
+ Emotion.INFO_SEPARATOR;
infolem.addContent(infoS);
emoElem.addContent(infolem);
returnVec.add(emoElem);
}
return returnVec;
}
return null;
}
public boolean hasTranscript() {
if (StringUtil.isFilled(_transcript))
return true;
return false;
}
public boolean hasRecognition() {
if (StringUtil.isFilled(_recognized))
return true;
return false;
}
public String getTrainingFormat() {
double val = computeLab(_lab);
String ret = singleLabelToString(val);
if (ret == null) {
ret = "NA";
}
try {
return new File(_path).getAbsolutePath() + " " + ret;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Return string value unified from numeric label values.
*
* @return The value.
*/
public String getStringLabel() {
double val = computeLab(_lab);
String ret = singleLabelToString(val);
if (ret == null) {
ret = com.tlabs.speechalyzer.Constants.CLASS_NO_CLASS_STRING;
}
return ret;
}
/**
* Try to recognize the words of an audio and store as transcript.
*
* @return The recognition result.
*/
public String recognize() {
String result = EmlUtils.recognizeFile(_path);
storeRecongnition(result);
return result;
}
/**
* Return one blank-separated string value for each numeric label.
*
* @return
*/
public String getStringLabels() {
String ret = "";
if (_lab == null || _lab.length == 0) {
return null;
}
try {
for (int i = 0; i < _lab.length; i++) {
double val = ((Emotion) _lab[i]).getValueAsDouble();
ret += singleLabelToString(val) + " ";
}
return ret.trim();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public ClassificationResult getClassificationResult() {
return _classificationResult;
}
/**
* Decide whether a numeric label is angry.
*
* @param val
* The numeric label.
* @return "A" for anger, "N" for non-anger, "U" for unsure and "G" for
* garbage / non-applicable.
*/
public String singleLabelToString(double val) {
return _categories.getCategoryForJudgement(val);
}
/**
* Return transcript and label, e.g. recs/rec.wav "bla bla" -3
*
* @return transcript and label or null of either isn't set.
*/
public String getTranscritpionAndLabel() {
if (_transcript.length() > 0 && _lab != null)
return _path + " " + "\"" + _transcript + "\"" + " "
+ computeLab(_lab);
else
return null;
}
/**
* Normalize (and store) the transcription automatically following the tlabs
* transcription rules.
*
* @return The normalized transciption.
*/
public String normalizeTranscription() {
String ret = "";
Preprocessor p = new Preprocessor(_config.getString("normalizeRules"),
_config.getString("normalizeVocab"));
ret = p.process(_transcript);
ret = new NumberToWord().filtNum(ret);
storeTranscript(ret);
return ret;
}
/**
* Compute a unified value from all labels.
*
* @param _lab
* @return
*/
private double computeLab(Emotion lab[]) {
if (lab == null || lab.length == 0) {
return -1;
}
double sum = 0;
int sumOfZero = 0;
;
for (int i = 0; i < lab.length; i++) {
double val = ((Emotion) lab[i]).getValueAsDouble();
sum += val;
if (val == 0) {
sumOfZero++;
}
}
// if most labelers judge "NA" return "NA"
if (sumOfZero > lab.length / 2) {
return 0;
}
return sum / lab.length;
}
/**
* Print all labels.
*
* @return The String.
*/
public String labToString() {
String ret = "";
if (_lab == null || _lab.length == 0) {
return "-1";
}
for (int i = 0; i < _lab.length; i++) {
double val = ((Emotion) _lab[i]).getValueAsDouble();
ret += val + " ";
}
return ret.trim();
}
/**
* Print all labels as integers.
*
* @return The String.
*/
public String labToIntString() {
String ret = "";
if (_lab == null || _lab.length == 0) {
return "-1";
}
for (int i = 0; i < _lab.length; i++) {
double val = ((Emotion) _lab[i]).getValueAsDouble();
val = val * _categories.getCatNumber() - 1;
ret += (int) val + " ";
}
return ret.trim();
}
/**
* Fill all internal fields with transcriptions and labels found in text
* _file.
*/
public void loadAnnotations() {
try {
String labelIdentifier = _config.getString("labelIdentifier");
String transcriptIdentifier = _config
.getString("transcriptIdentifier");
String recognitionIdentifier = _config
.getString("recognitionIdentifier");
String predIdentifer = _config.getString("predictionIdentifier");
String txtS = FileUtil.getNameWithoutExtension(_path) + "."
+ _config.getString("labelFileExtension");
_transcript = "";
if (FileUtil.existFile(txtS)) {
_annotations = new KeyValues(new File(txtS), ":",
_config.getString("charEnc"));
String prediction = null;
if (_annotations.getString(predIdentifer) != null) {
prediction = _annotations.getString(predIdentifer);
if (_config.getBool("emotionmlMode")) {
Emotion e = Emotion.parseEmotion(_config, prediction);
_classificationResult = new ClassificationResult(e);
} else {
_classificationResult = new ClassificationResult(prediction);
}
}
String labelsS = null;
if (_annotations.getString(labelIdentifier) != null) {
labelsS = _annotations.getString(labelIdentifier);
fillLabelArrayFromString(labelsS);
}
if (_annotations.getString(transcriptIdentifier) != null)
_transcript = _annotations.getString(transcriptIdentifier);
if (_annotations.getString(recognitionIdentifier) != null)
_recognized = _annotations.getString(recognitionIdentifier);
} else {
// System.out.println("no _transcript for " + txtS);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void fillLabelArrayFromString(String labelString) {
StringTokenizer st = new StringTokenizer(labelString, ";");
_lab = new Emotion[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
String label = st.nextToken();
_lab[i++] = Emotion.parseEmotion(_config, label);
}
}
/**
* Retrieve the _transcript.
*
* @return _transcript or null.
*/
public String getTranscript() {
String transcriptIdentifier = _config.getString("transcriptIdentifier");
return getAnnotationForLabel(transcriptIdentifier);
}
public String getRecognition() {
return getAnnotationForLabel(_config.getString("recognitionIdentifier"));
}
private String getAnnotationForLabel(String label) {
loadAnnotations();
return _annotations.getString(label);
}
private void checkInitLab() {
if (_lab == null)
_lab = new Emotion[0];
}
/**
* Adds a label to existing ones.
*
* @param label
*/
public void addLabel(String newLabel) {
checkInitAnnotationKeyValues();
checkInitLab();
try {
if (newLabel.indexOf(",") < 0) {
newLabel = convertOldToNewLabel(newLabel);
}
String labelIdentifier = _config.getString("labelIdentifier");
String labelsS = "";
if (_annotations.getString(labelIdentifier) != null)
labelsS = _annotations.getString(labelIdentifier);
int i = 0;
String newString = labelsS + newLabel;
Emotion[] newlab = new Emotion[_lab.length + 1];
for (Emotion e : _lab) {
newlab[i++] = e;
}
newlab[i] = Emotion.parseEmotion(_config,
newLabel.substring(0, newLabel.length() - 1));
_annotations.setValue(labelIdentifier, newString);
_lab = newlab;
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
_logger.error("error adding label: " + newLabel + " at " + _path);
}
}
public void addEmotion(Emotion e) {
if (e == null)
return;
addLabel(e.toString());
}
private String convertOldToNewLabel(String oldLabel) {
String defaultCat = _config.getString("defaultEmotionName");
String defaultType = _config.getString("defaultEmotionType");
String defaultUser = _config.getString("defaultUser");
String defaultConf = _config.getString("defaultConfidence");
String defaultVocabId = _config.getString("defaultConfidence");
return _config.getString("emotion.label.val") + "=" + oldLabel + ","
+ _config.getString("emotion.label.cat") + "=" + defaultCat
+ "," + _config.getString("emotion.label.orig") + "="
+ defaultUser + "," + _config.getString("emotion.label.type")
+ "=" + defaultType + ","
+ _config.getString("emotion.label.conf") + "=" + defaultConf
+ "," + _config.getString("emotion.label.vocabId") + "="
+ defaultVocabId + ";";
}
/**
* Replaces a label, overwrites if already existed.
*
* @param label
*/
public void replaceLabel(String newLabel) {
checkInitAnnotationKeyValues();
try {
if (newLabel.indexOf(",") < 0) {
newLabel = convertOldToNewLabel(newLabel);
}
String labelIdentifier = _config.getString("labelIdentifier");
_annotations.setValue(labelIdentifier, newLabel);
fillLabelArrayFromString(newLabel);
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove the last label that is stored in the _file.
*/
public void removeLastLabel() {
checkInitAnnotationKeyValues();
try {
String labelIdentifier = _config.getString("labelIdentifier");
String labelsS = _annotations.getString(labelIdentifier);
StringTokenizer st = new StringTokenizer(labelsS, ";");
int i = 0, sum = _lab.length;
String newString = "";
Emotion[] newlab = new Emotion[_lab.length - 1];
while (i < sum - 1) {
String label = st.nextToken();
newString += label + ";";
newlab[i++] = Emotion.parseEmotion(_config, label);
}
_annotations.setValue(labelIdentifier, newString);
_lab = newlab;
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove the annotation _file from disk.
*/
public void removeAnnotationFile() {
try {
String path = _file.getAbsolutePath();
String txtS = FileUtil.getNameWithoutExtension(path) + "."
+ _config.getString("labelFileExtension");
if (FileUtil.existFile(txtS)) {
new File(txtS).delete();
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove the annotation and audio file from disk.
*/
public void removeFiles() {
try {
String path = _file.getAbsolutePath();
String txtS = FileUtil.getNameWithoutExtension(path) + "."
+ _config.getString("labelFileExtension");
if (FileUtil.existFile(txtS)) {
new File(txtS).delete();
} else {
_logger.info("no annotation file for deletion");
}
if (FileUtil.existFile(path)) {
new File(path).delete();
} else {
_logger.info("no audio file for deletion");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove the recording from disk.
*/
public void removeAudioFile() {
try {
if (FileUtil.existFile(_path)) {
new File(_path).delete();
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove all labels from annotation _file.
*/
public void removeLabels() {
if (_annotations == null)
return;
try {
String identifer = _config.getString("labelIdentifier");
_annotations.removeKeyValue(identifer);
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Remove all labels from annotation _file.
*/
public void removePrediction() {
if (_annotations == null)
return;
try {
String predIdentifer = _config.getString("predictionIdentifier");
_annotations.removeKeyValue(predIdentifer);
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Store a new _transcript, i.e. replace an existing one.
*
* @param label
*/
public void storeTranscript(String transcript) {
String label = _config.getString("transcriptIdentifier");
storeAnnotation(label, transcript);
_transcript = transcript.trim();
}
/**
* Store a prediction from automatic emotion detector into annotation _file.
*
* @param res
*/
public void storePred(ClassificationResult cr) {
String predIdentifier = _config.getString("predictionIdentifier");
storeAnnotation(predIdentifier, cr.toString());
}
/**
* Store a new recognition result, i.e. replace an existing one.
*
* @param label
*/
public void storeRecongnition(String recognition) {
String label = _config.getString("recognitionIdentifier");
storeAnnotation(label, recognition);
_recognized = recognition.trim();
}
public void rename(String newName) {
try {
String oldName = _path;
String oldTextName = FileUtil.getNameWithoutExtension(_path)
+ ".txt";
String path = _file.getParentFile().getAbsolutePath();
String newPath = path + System.getProperty("file.separator")
+ newName;
FileUtil.rename(oldName, newPath);
_path = newPath;
_file = new File(_path);
newPath = FileUtil.getNameWithoutExtension(newPath) + ".txt";
FileUtil.rename(oldTextName, newPath);
} catch (Exception e) {
_logger.error(e.getMessage());
e.printStackTrace();
}
}
public void copyLabelsFromOtherRecFile(RecFile other) {
for (Emotion e : other._lab) {
addEmotion(e);
}
}
private void checkInitAnnotationKeyValues() {
if (_annotations == null) {
_annotations = new KeyValues("", "\n", ":");
}
}
private void storeAnnotation(String label, String annotation) {
if (annotation.trim().length() == 0)
return;
checkInitAnnotationKeyValues();
try {
_annotations.setValue(label, annotation);
storeAnnotationFile();
} catch (Exception e) {
e.printStackTrace();
}
}
private void storeAnnotationFile() {
checkInitAnnotationKeyValues();
// String transIdentifier = _config.getString("transcriptIdentifier");
// String predIdentifier = _config.getString("predictionIdentifier");
// String recoIdentifier = _config.getString("recognitionIdentifier");
// String labelIdentifer = _config.getString("labelIdentifier");
//
// if (StringUtil.isEmpty(_annotations.getString(transIdentifier))){
// _annotations.addKeyValue(new KeyValue(transIdentifier, "NA"));
// }
// if (StringUtil.isEmpty(_annotations.getString(predIdentifier))){
// _annotations.addKeyValue(new KeyValue(predIdentifier, "NA"));
// }
// if (StringUtil.isEmpty(_annotations.getString(recoIdentifier))){
// _annotations.addKeyValue(new KeyValue(recoIdentifier, "NA"));
// }
// if (StringUtil.isEmpty(_annotations.getString(labelIdentifer))){
// _annotations.addKeyValue(new KeyValue(labelIdentifer, "NA"));
// }
String path = _file.getAbsolutePath();
FileUtil.createDir(new File(path).getParent());
String txtS = path.substring(0, path.length() - 4) + ".txt";
removeAnnotationFile();
_annotations.fileStore(txtS);
if (!FileUtil.existFile(txtS)) {
_logger.info("no previous transcript for " + path);
}
}
public void generateAudioFile(boolean female, String lang) {
String rulesFile = _config.getString("ttsRulesFile");
String vocabFile = _config.getString("ttsVocabFile");
Preprocessor p = new Preprocessor(rulesFile, vocabFile);
String text = p.process(_transcript);
_logger.debug("Synthesizing audio from :" + text);
if (_config.isString("useTTS", "emofilt")) {
String emotions = _config.getString("emotions");
String mbrolaVoices = _config.getString("mbrolaVoices");
ISynthesizer synthesizer = new EmofiltSynthesizer(_config);
KeyValues voices = new KeyValues(mbrolaVoices, ";", ",");
StringTokenizer emoST = new StringTokenizer(emotions);
while (emoST.hasMoreElements()) {
String emotion = (String) emoST.nextElement();
for (int i = 0; i < voices.getKeyValues().length; i++) {
KeyValue kv = voices.getKeyValues()[i];
String voc = kv.getKey();
String sex = kv.getValue();
String filename = FileUtil.addNamePart(_path, "_" + emotion
+ "_" + voc);
RecFile recFile = new RecFile(filename, _config);
recFile.storeTranscript(_transcript);
synthesizer.synthesize(text, filename, emotion, sex, voc);
}
}
} else if (_config.isString("useTTS", "svox")) {
ISynthesizer synthesizer = new SvoxSynthesizer(_config);
synthesizer.synthesize(text, _path, female, lang);
} else if (_config.isString("useTTS", "ivona")) {
ISynthesizer synthesizer = new IvonaSynthesizer(_config);
String sex = female ? Constants.SEX_FEMALE : Constants.SEX_MALE;
synthesizer.synthesize(text, _path, sex);
}
}
public String getSize() {
if (_file != null) {
return Long.toString(_size);
}
return "na";
}
}