Skip to content

Commit

Permalink
Merge branch 'fix-570'
Browse files Browse the repository at this point in the history
  • Loading branch information
psibre committed Jul 20, 2016
2 parents 90d18d9 + f63ef2d commit 6d6e1bc
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
// DOM classes
import marytts.datatypes.MaryData;
import marytts.datatypes.MaryDataType;
import marytts.datatypes.MaryXML;
import marytts.util.data.text.PraatInterval;
import marytts.util.data.text.PraatIntervalTier;
import marytts.util.data.text.PraatTextGrid;
import marytts.util.dom.NameNodeFilter;
import marytts.util.dom.DomUtils;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;

import static marytts.datatypes.MaryXML.*;

/**
* Transforms a full MaryXML document into a Praat TextGrid containing various interesting information; in particular, the source
* units and basenames used in unit selection synthesis
Expand All @@ -45,7 +44,7 @@
public class PraatTextGridGenerator extends InternalModule {

public PraatTextGridGenerator() {
super("Praat TextGrid generator", MaryDataType.AUDIO, MaryDataType.PRAAT_TEXTGRID, null);
super("Praat TextGrid generator", MaryDataType.REALISED_ACOUSTPARAMS, MaryDataType.PRAAT_TEXTGRID, null);
}

public MaryData process(MaryData d) throws Exception {
Expand All @@ -60,13 +59,9 @@ public MaryData process(MaryData d) throws Exception {
Document doc = d.getDocument();

// initialize various variables:
Double xmin = 0.0;
Double xmax = 0.0;
Double duration;
Double duration = 0.0;
String phone = null;

Double sentenceStart = 0.0; // this is cumulatively added to counter sentence-initial timing resets

// initialize some class variables:
PraatIntervalTier phoneTier = new PraatIntervalTier("phones");
Double basenameDuration = 0.0;
Expand All @@ -79,30 +74,27 @@ public MaryData process(MaryData d) throws Exception {
PraatIntervalTier sourceTier = new PraatIntervalTier("sources");

// prepare to iterate only over the PHONE, SENTENCE, and BOUNDARY nodes in the MaryXML:
NodeIterator ni = ((DocumentTraversal) doc).createNodeIterator(doc, NodeFilter.SHOW_ELEMENT, new NameNodeFilter(
new String[] { MaryXML.SENTENCE, MaryXML.PHONE, MaryXML.BOUNDARY }), false);
NodeIterator ni = DomUtils.createNodeIterator(doc, PHONE, BOUNDARY);
Element element;

// now iterate over these nodes:
while ((element = (Element) ni.nextNode()) != null) {
String tagName = element.getTagName(); // <s>, <ph>, or <boundary> as specified above
if (tagName.equals(MaryXML.SENTENCE)) {
sentenceStart = xmax;
continue; // goto next node, do not collect $200
} else if (tagName.equals(MaryXML.PHONE)) {
switch (element.getTagName()) { // <s>, <ph>, or <boundary> as specified above
case PHONE:
phone = element.getAttribute("p");
xmin = xmax;
xmax = Double.parseDouble(element.getAttribute("end")) + sentenceStart; // TODO: diphone voices have end in ms!
duration = xmax - xmin;
xmin = xmax;
} else { // boundary
duration = Integer.parseInt(element.getAttribute("d")) / 1000.0; // duration is always in ms
break;
case BOUNDARY:
phone = "_"; // TODO: perhaps we should access TargetFeatureComputer.getPauseSymbol() instead
try {
if (element.hasAttribute("duration")) {
duration = Double.parseDouble(element.getAttribute("duration")) / 1000.0; // duration is always in ms
xmax += duration;
} catch (NumberFormatException nfe) {
continue; // HMM voices can have duration-less <boundary/> tags, which can't be processed here
} else {
duration = 0.0; // HMM voices can have duration-less <boundary/> tags
}
break;
default:
logger.error("NodeIterator should not find an element of type " + element.getTagName() + " here!");
break;
}

PraatInterval phoneInterval = new PraatInterval(duration, phone);
Expand Down Expand Up @@ -182,7 +174,7 @@ public MaryData process(MaryData d) throws Exception {
}

// return raw TextGrid as result:
MaryData result = new MaryData(outputType(), d.getLocale());
MaryData result = new MaryData(getOutputType(), d.getLocale());
result.setPlainText(textGrid.toString());
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,13 @@ public void setText(String text) {
*
* @param duration
* duration
* @throws IllegalArgumentException
* if duration is negative
*/
public void setDuration(double duration) {
public void setDuration(double duration) throws IllegalArgumentException {
if (Double.isNaN(duration) || duration < 0.0) {
throw new IllegalArgumentException("duration must be a non-negative value, but was " + duration);
}
this.duration = duration;
}

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.6</version>
<version>2.4.5</version>
</dependency>

<dependency>
Expand Down
1 change: 1 addition & 0 deletions src/site/markdown/download/releasenotes-5.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Development news
Fixed Issues/Bugs
-----------------

* [#570](https://github.com/marytts/marytts/issues/570): Praat TextGrid output is invalid with boundaries (times are not monotonic)
* [#564](https://github.com/marytts/marytts/pull/564): add missing TOKENS examples
* [#555](https://github.com/marytts/marytts/issues/555): HMMModel generates malformed XML duration attributes
* [#531](https://github.com/marytts/marytts/issues/531): java.awt.HeadlessException in (Half)PhoneLabelFeatureAligner
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package marytts.modules

import org.junit.*

import groovy.util.logging.Log4j

import marytts.LocalMaryInterface
import marytts.datatypes.MaryDataType

@Log4j
class PraatTextGridGeneratorIT {

def mary

@Before
void setUp() {
mary = new LocalMaryInterface()
mary.outputType = MaryDataType.PRAAT_TEXTGRID.name
}

@Test
void checkBoundaryTimes() {
def textGrid = mary.generateText('Foo, bar.\n\nBaz!')
def xmin = 0
def xmax = 0
def newInterval = false
textGrid.eachLine { line->
switch(line) {
case ~/.*intervals \[\d\]:.*/:
newInterval = true // begin interval block
log.info "begin new interval block: $line"
break
case { line =~ /.*xmin =.*/ && newInterval }:
xmin = Float.parseFloat(line.split().last())
log.info "xmin = $xmin"
assert xmin == xmax: "interval xmin must be equal to previous interval's xmax"
break
case { line =~ /.*xmax =.*/ && newInterval }:
xmax = Float.parseFloat(line.split().last())
log.info "xmax = $xmax"
assert xmax > xmin: "interval xmax must be bigger than xmin"
break
case ~/.*text = .*/:
newInterval = false // end interval block
log.info "end new interval block: $line"
break
case ~/.*class = "IntervalTier".*/:
// starting new tier; reset times
xmin = 0
xmax = 0
break
default:
// ignore other lines
break
}
}
}
}

0 comments on commit 6d6e1bc

Please sign in to comment.