marytts.tools.voiceimport.HnmTimelineMaker Maven / Gradle / Ivy
The newest version!
/**
* Portions Copyright 2006 DFKI GmbH.
* Portions Copyright 2001 Sun Microsystems, Inc.
* Portions Copyright 1999-2001 Language Technologies Institute,
* Carnegie Mellon University.
* All Rights Reserved. Use is subject to license terms.
*
* Permission is hereby granted, free of charge, to use and distribute
* this software and its documentation without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of this work, and to
* permit persons to whom this work is furnished to do so, subject to
* the following conditions:
*
* 1. The code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Any modifications must be clearly marked as such.
* 3. Original authors' names are not deleted.
* 4. The authors' names are not used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE
* CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
package marytts.tools.voiceimport;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import marytts.signalproc.analysis.F0TrackerAutocorrelationHeuristic;
import marytts.signalproc.analysis.PitchFileHeader;
import marytts.signalproc.analysis.PitchMarks;
import marytts.signalproc.analysis.PitchReaderWriter;
import marytts.signalproc.sinusoidal.hntm.analysis.HntmAnalyzer;
import marytts.signalproc.sinusoidal.hntm.analysis.HntmAnalyzerParams;
import marytts.signalproc.sinusoidal.hntm.analysis.HntmSpeechSignal;
import marytts.signalproc.sinusoidal.hntm.synthesis.HntmSynthesizerParams;
import marytts.unitselection.data.HnmDatagram;
import marytts.util.data.ESTTrackReader;
import marytts.util.io.FileUtils;
import marytts.util.math.MathUtils;
import marytts.util.signal.SignalProcUtils;
/**
* HnmTimelineMaker class takes a database root directory and a list of basenames, and converts the related wav files into a hnm
* timeline in Mary format.
*
* @author Oytun Türk
*/
public class HnmTimelineMaker extends VoiceImportComponent {
protected DatabaseLayout db = null;
protected int percent = 0;
protected String hnmAnalysisFileExt = ".ana";
public final String HNMTIMELINE = "HnmTimelineMaker.hnmTimeline";
public final String HNMANADIR = "HnmTimelineMaker.hnmAnalysisDir";
public final String PMDIR = "db.pmDir";
public final String PMEXT = "db.pmExtension";
public String getName() {
return "HnmTimelineMaker";
}
public SortedMap getDefaultProps(DatabaseLayout theDb) {
this.db = theDb;
if (props == null) {
HntmAnalyzerParams analysisParams = new HntmAnalyzerParams();
HntmSynthesizerParams synthesisParams = new HntmSynthesizerParams();
props = new TreeMap();
props.put(HNMTIMELINE, db.getProp(db.FILEDIR) + "timeline_hnm" + db.getProp(db.MARYEXT));
props.put(HNMANADIR, db.getProp(db.ROOTDIR) + "hna" + System.getProperty("file.separator"));
props.put("HnmTimelineMaker.noiseModel", String.valueOf(analysisParams.noiseModel));
props.put("HnmTimelineMaker.numFiltStages",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.numFilteringStages));
props.put("HnmTimelineMaker.medianFiltLen",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.medianFilterLength));
props.put("HnmTimelineMaker.maFiltLen",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.movingAverageFilterLength));
props.put("HnmTimelineMaker.cumAmpTh",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.cumulativeAmpThreshold));
props.put("HnmTimelineMaker.maxAmpTh",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.maximumAmpThresholdInDB));
props.put("HnmTimelineMaker.harmDevPercent",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.harmonicDeviationPercent));
props.put("HnmTimelineMaker.sharpPeakAmpDiff",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.sharpPeakAmpDiffInDB));
props.put("HnmTimelineMaker.minHarmonics",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.minimumTotalHarmonics));
props.put("HnmTimelineMaker.maxHarmonics",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.maximumTotalHarmonics));
props.put("HnmTimelineMaker.minVoicedFreq",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.minimumVoicedFrequencyOfVoicing));
props.put("HnmTimelineMaker.maxVoicedFreq",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.maximumVoicedFrequencyOfVoicing));
props.put("HnmTimelineMaker.maxFreqVoicingFinalShift",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.maximumFrequencyOfVoicingFinalShift));
props.put("HnmTimelineMaker.neighsPercent",
String.valueOf(analysisParams.hnmPitchVoicingAnalyzerParams.neighsPercent));
props.put("HnmTimelineMaker.harmCepsOrder", String.valueOf(analysisParams.harmonicPartCepstrumOrder));
props.put("HnmTimelineMaker.regCepWarpMethod", String.valueOf(analysisParams.regularizedCepstrumWarpingMethod));
props.put("HnmTimelineMaker.regCepsLambda", String.valueOf(analysisParams.regularizedCepstrumLambdaHarmonic));
props.put("HnmTimelineMaker.noiseLpOrder", String.valueOf(analysisParams.noisePartLpOrder));
props.put("HnmTimelineMaker.preCoefNoise", String.valueOf(analysisParams.preemphasisCoefNoise));
props.put("HnmTimelineMaker.hpfBeforeNoiseAnalysis", String.valueOf(analysisParams.hpfBeforeNoiseAnalysis));
props.put("HnmTimelineMaker.harmNumPer", String.valueOf(analysisParams.numPeriodsHarmonicsExtraction));
}
return props;
}
protected void setupHelp() {
props2Help = new TreeMap();
props2Help.put(HNMTIMELINE, "file containing all hnm noise waveform files. Will be created by this module");
props2Help.put(HNMANADIR, "directory to write the harmnoics plus noise analysis results for each wav file");
props2Help.put("HnmTimelineMaker.noiseModel", "Noise model: 1=WAVEFORM, 2=LPC, Default=1");
props2Help
.put("HnmTimelineMaker.numFiltStages",
"Number of filtering stages to smooth out maximum frequency of voicing curve: Range={0, 1, 2, 3, 4, 5}. 0 means no smoothing. Default=2");
props2Help
.put("HnmTimelineMaker.medianFiltLen",
"Length of median filter for smoothing the maximum frequency of voicing curve: Range={4, 8, 12, 16, 20}, Default=12");
props2Help
.put("HnmTimelineMaker.maFiltLen",
"Length of moving average filter for smoothing the maximum frequency of voicing curve: Range={4, 8, 12, 16, 20}, Default=12");
props2Help
.put("HnmTimelineMaker.cumAmpTh",
"Cumulative amplitude threshold [linear scale] for harmonic band voicing detection; decrease to increase max. freq. of voicing values. Range=[0.1, 10.0], Default=2.0");
props2Help
.put("HnmTimelineMaker.maxAmpTh",
"Maximum amplitude threshold [in DB] for harmonic band voicing detection. Decrease to increase max. freq. of voicing values. Range=[0.0, 20.0], Default=13.0");
props2Help
.put("HnmTimelineMaker.harmDevPercent",
"Percent deviation allowed for harmonic peak. Increase to increase max. freq. of voicing values. Range=[0.0, 100.0], Default=20.0");
props2Help
.put("HnmTimelineMaker.sharpPeakAmpDiff",
"Minimum amplitude difference [in DB] to declare an isolated peak as harmonic. Decrease to increase max. freq. of voicing values. range=[0.0, 20.0], Default=12.0");
props2Help.put("HnmTimelineMaker.minHarmonics",
"Minimum total harmonics allowed in voiced regions. Range=[0, 100], Default=0");
props2Help.put("HnmTimelineMaker.maxHarmonics",
"Maximum total harmonics allowed in voiced regions. Range=[minHarmonics, 100], Default=100");
props2Help.put("HnmTimelineMaker.minVoicedFreq",
"Minimum voiced frequency for voiced regions [in Hz]. Range=[0.0, 0.5*samplingRate], Default=0");
props2Help
.put("HnmTimelineMaker.maxVoicedFreq",
"Maximum voiced frequency for voiced regions [in Hz]. Range=Default=[minVoicedFreq, 0.5*samplingRate], Default=5000");
props2Help
.put("HnmTimelineMaker.maxFreqVoicingFinalShift",
"Final amount of shift to be applied to the MWF curve [in Hz]. Range=[0.0, 0.5*samplingRate-maxVoicedFreq], Default=0");
props2Help
.put("HnmTimelineMaker.neighsPercent",
"Percentage of samples that the harmonic peak needs to be larger than within a band. Decrease to increase max. freq. of voicing values. Range=[0.0, 100.0], Default=50");
props2Help
.put("HnmTimelineMaker.harmCepsOrder",
"Cepstrum order to represent harmonic amplitudes. Increase to obtain better match with actual harmonic values. Range=[8, 40], Default=24");
props2Help.put("HnmTimelineMaker.regCepWarpMethod",
"Warping method for regularized cepstrum estimation. 1=POST_MEL, 2=PRE_BARK, Default=1");
props2Help
.put("HnmTimelineMaker.regCepsLambda",
"Regularization term for cepstrum estimation. Increase to obtain smoother spectral match for harmonic amplitudes. However, this reduces the match with the actual amplitudes. Range=[0.0, 0.1], Default=1.0e-5");
props2Help.put("HnmTimelineMaker.noiseLpOrder", "Linear prediction order for LPC noise part. Range=[8, 50], Default=12");
props2Help.put("HnmTimelineMaker.preCoefNoise",
"Pre-emphasis coefficient for linear prediction analysis of noise part. Range=[0.0, 0.99], Default=0.97");
props2Help.put("HnmTimelineMaker.hpfBeforeNoiseAnalysis",
"Remove lowpass frequency residual after harmonic subtraction? 0=NO, 1=YES, Default=1");
props2Help.put("HnmTimelineMaker.harmNumPer", "Total periods for harmonic analysis. Range=[2.0, 4.0], Default=2");
}
/**
* Performs HNM analysis and writes the results to a single timeline file
*
*/
public boolean compute() {
long start = System.currentTimeMillis(); // start timing
System.out.println("---- Importing Harmonics plus noise parameters\n\n");
System.out.println("Base directory: " + db.getProp(db.ROOTDIR) + "\n");
/* Export the basename list into an array of strings */
String[] baseNameArray = bnl.getListAsArray();
/* Prepare the output directory for the timelines if it does not exist */
File timelineDir = new File(db.getProp(db.FILEDIR));
File ptcDir = new File(db.getProp(db.PTCDIR));
if (!ptcDir.exists()) {
ptcDir.mkdir();
}
File hnaDir = new File(getProp(HNMANADIR));
if (!hnaDir.exists()) {
hnaDir.mkdir();
}
try {
/*
* 1) Determine the reference sampling rate as being the sample rate of the first encountered wav file
*/
WavReader wav = new WavReader(db.getProp(db.WAVDIR) + baseNameArray[0] + db.getProp(db.WAVEXT));
int globSampleRate = wav.getSampleRate();
System.out.println("---- Detected a global sample rate of: [" + globSampleRate + "] Hz.");
System.out.println("---- Performing HNM analysis...");
/* Make the file name */
System.out.println("Will create the hnm timeline in file [" + getProp(HNMTIMELINE) + "].");
/* An example of processing header: */
Properties headerProps = new Properties();
headerProps.setProperty("hnm.noiseModel", props.get("HnmTimelineMaker.noiseModel"));
headerProps.setProperty("hnm.numFiltStages", props.get("HnmTimelineMaker.numFiltStages"));
headerProps.setProperty("hnm.medianFiltLen", props.get("HnmTimelineMaker.medianFiltLen"));
headerProps.setProperty("hnm.maFiltLen", props.get("HnmTimelineMaker.maFiltLen"));
headerProps.setProperty("hnm.cumAmpTh", props.get("HnmTimelineMaker.cumAmpTh"));
headerProps.setProperty("hnm.maxAmpTh", props.get("HnmTimelineMaker.maxAmpTh"));
headerProps.setProperty("hnm.harmDevPercent", props.get("HnmTimelineMaker.harmDevPercent"));
headerProps.setProperty("hnm.sharpPeakAmpDiff", props.get("HnmTimelineMaker.sharpPeakAmpDiff"));
headerProps.setProperty("hnm.minHarmonics", props.get("HnmTimelineMaker.minHarmonics"));
headerProps.setProperty("hnm.maxHarmonics", props.get("HnmTimelineMaker.maxHarmonics"));
headerProps.setProperty("hnm.minVoicedFreq", props.get("HnmTimelineMaker.minVoicedFreq"));
headerProps.setProperty("hnm.maxVoicedFreq", props.get("HnmTimelineMaker.maxVoicedFreq"));
headerProps.setProperty("hnm.maxFreqVoicingFinalShift", props.get("HnmTimelineMaker.maxFreqVoicingFinalShift"));
headerProps.setProperty("hnm.neighsPercent", props.get("HnmTimelineMaker.neighsPercent"));
headerProps.setProperty("hnm.harmCepsOrder", props.get("HnmTimelineMaker.harmCepsOrder"));
headerProps.setProperty("hnm.regCepWarpMethod", props.get("HnmTimelineMaker.regCepWarpMethod"));
headerProps.setProperty("hnm.regCepsLambda", props.get("HnmTimelineMaker.regCepsLambda"));
headerProps.setProperty("hnm.noiseLpOrder", props.get("HnmTimelineMaker.noiseLpOrder"));
headerProps.setProperty("hnm.preCoefNoise", props.get("HnmTimelineMaker.preCoefNoise"));
headerProps.setProperty("hnm.hpfBeforeNoiseAnalysis", props.get("HnmTimelineMaker.hpfBeforeNoiseAnalysis"));
headerProps.setProperty("hnm.harmNumPer", props.get("HnmTimelineMaker.harmNumPer"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
headerProps.store(baos, null);
String processingHeader = baos.toString("latin1");
/* Instantiate the TimelineWriter: */
TimelineWriter hnmTimeline = new TimelineWriter(getProp(HNMTIMELINE), processingHeader, globSampleRate, 0.1);
// TO DO: Update these paratemers according to props
HntmAnalyzerParams analysisParams = new HntmAnalyzerParams();
HntmSynthesizerParams synthesisParamsBeforeNoiseAnalysis = new HntmSynthesizerParams();
analysisParams.noiseModel = Integer.valueOf(props.get("HnmTimelineMaker.noiseModel"));
analysisParams.hnmPitchVoicingAnalyzerParams.numFilteringStages = Integer.valueOf(props
.get("HnmTimelineMaker.numFiltStages"));
analysisParams.hnmPitchVoicingAnalyzerParams.medianFilterLength = Integer.valueOf(props
.get("HnmTimelineMaker.medianFiltLen"));
analysisParams.hnmPitchVoicingAnalyzerParams.movingAverageFilterLength = Integer.valueOf(props
.get("HnmTimelineMaker.maFiltLen"));
analysisParams.hnmPitchVoicingAnalyzerParams.cumulativeAmpThreshold = Float.valueOf(props
.get("HnmTimelineMaker.cumAmpTh"));
analysisParams.hnmPitchVoicingAnalyzerParams.maximumAmpThresholdInDB = Float.valueOf(props
.get("HnmTimelineMaker.maxAmpTh"));
analysisParams.hnmPitchVoicingAnalyzerParams.harmonicDeviationPercent = Float.valueOf(props
.get("HnmTimelineMaker.harmDevPercent"));
analysisParams.hnmPitchVoicingAnalyzerParams.sharpPeakAmpDiffInDB = Float.valueOf(props
.get("HnmTimelineMaker.sharpPeakAmpDiff"));
analysisParams.hnmPitchVoicingAnalyzerParams.minimumTotalHarmonics = Integer.valueOf(props
.get("HnmTimelineMaker.minHarmonics"));
analysisParams.hnmPitchVoicingAnalyzerParams.maximumTotalHarmonics = Integer.valueOf(props
.get("HnmTimelineMaker.maxHarmonics"));
analysisParams.hnmPitchVoicingAnalyzerParams.minimumVoicedFrequencyOfVoicing = Float.valueOf(props
.get("HnmTimelineMaker.minVoicedFreq"));
analysisParams.hnmPitchVoicingAnalyzerParams.maximumVoicedFrequencyOfVoicing = Float.valueOf(props
.get("HnmTimelineMaker.maxVoicedFreq"));
analysisParams.hnmPitchVoicingAnalyzerParams.maximumFrequencyOfVoicingFinalShift = Float.valueOf(props
.get("HnmTimelineMaker.maxFreqVoicingFinalShift"));
analysisParams.hnmPitchVoicingAnalyzerParams.neighsPercent = Float.valueOf(props
.get("HnmTimelineMaker.neighsPercent"));
analysisParams.harmonicPartCepstrumOrder = Integer.valueOf(props.get("HnmTimelineMaker.harmCepsOrder"));
analysisParams.regularizedCepstrumWarpingMethod = Integer.valueOf(props.get("HnmTimelineMaker.regCepWarpMethod"));
analysisParams.regularizedCepstrumLambdaHarmonic = Float.valueOf(props.get("HnmTimelineMaker.regCepsLambda"));
analysisParams.noisePartLpOrder = Integer.valueOf(props.get("HnmTimelineMaker.noiseLpOrder"));
analysisParams.preemphasisCoefNoise = Float.valueOf(props.get("HnmTimelineMaker.preCoefNoise"));
analysisParams.hpfBeforeNoiseAnalysis = Boolean.valueOf(props.get("HnmTimelineMaker.hpfBeforeNoiseAnalysis"));
analysisParams.numPeriodsHarmonicsExtraction = Float.valueOf(props.get("HnmTimelineMaker.harmNumPer"));
analysisParams.isSilentAnalysis = true;
//
/* 2) Write the datagrams and feed the index */
float totalDuration = 0.0f; // Accumulator for the total timeline duration
long totalTime = 0l;
long numDatagrams = 0l; // Total number of hnm datagrams in the timeline file
/* For each wav file: */
int n, i;
double f0WindowSizeInSeconds = 0;
double f0SkipSizeInSeconds = 0;
for (n = 0; n < baseNameArray.length; n++) {
percent = 100 * n / baseNameArray.length;
/* - open+load */
System.out.println(baseNameArray[n]);
String wavFile = db.getProp(db.WAVDIR) + baseNameArray[n] + db.getProp(db.WAVEXT);
ESTTrackReader pmFile = new ESTTrackReader(db.getProp(PMDIR) + baseNameArray[n] + db.getProp(PMEXT));
totalDuration += pmFile.getTimeSpan();
HntmAnalyzer ha = new HntmAnalyzer();
String hnmAnalysisFile = getProp(HNMANADIR) + baseNameArray[n] + hnmAnalysisFileExt;
HntmSpeechSignal hnmSignal = null;
if (FileUtils.exists(hnmAnalysisFile))
hnmSignal = new HntmSpeechSignal(hnmAnalysisFile, analysisParams.noiseModel);
else {
wav = new WavReader(wavFile);
short[] wave = wav.getSamples();
String ptcFile = db.getProp(db.PTCDIR) + baseNameArray[n] + db.getProp(db.PTCEXT);
PitchReaderWriter f0 = null;
if (FileUtils.exists(ptcFile))
f0 = new PitchReaderWriter(ptcFile);
else {
PitchFileHeader pitchDetectorParams = new PitchFileHeader();
// default values are problematic; for now, re-use the parameters from PraatPitchmarker:
pitchDetectorParams.minimumF0 = Double.parseDouble(db.getProperty("PraatPitchmarker.minPitch"));
pitchDetectorParams.maximumF0 = Double.parseDouble(db.getProperty("PraatPitchmarker.maxPitch"));
F0TrackerAutocorrelationHeuristic pitchDetector = new F0TrackerAutocorrelationHeuristic(
pitchDetectorParams);
f0 = pitchDetector.pitchAnalyzeWavFile(wavFile, ptcFile);
}
int frameStart = 0;
int frameEnd = 0;
long duration;
for (i = 0; i < pmFile.getNumFrames() - 1; i++) {
frameStart = (int) ((double) pmFile.getTime(i) * (double) (globSampleRate));
frameEnd = (int) ((double) pmFile.getTime(i + 1) * (double) (globSampleRate));
assert frameEnd <= wave.length : "Frame ends after end of wave data: " + frameEnd + " > " + wave.length;
duration = frameEnd - frameStart;
if (duration < 5)
System.out.println("Too short duration");
}
PitchMarks pm = new PitchMarks(pmFile, globSampleRate);
pm.findAndSetUnvoicedF0s(f0.contour, f0.header, globSampleRate);
if (n == 0) {
f0WindowSizeInSeconds = f0.header.windowSizeInSeconds;
if (pmFile.getNumFrames() > 1.0)
f0SkipSizeInSeconds = SignalProcUtils.sampleFloat2time(
((float) wave.length - SignalProcUtils.time2sample(f0WindowSizeInSeconds, globSampleRate))
/ (pmFile.getNumFrames() - 1.0f), globSampleRate);
else
f0SkipSizeInSeconds = f0.header.skipSizeInSeconds;
}
// Use pitch marks from pm folder
hnmSignal = ha.analyze(wave, wav.getSampleRate(), pm, f0WindowSizeInSeconds, f0SkipSizeInSeconds, pm.f0s,
null, analysisParams, synthesisParamsBeforeNoiseAnalysis, hnmAnalysisFile);
// Use autocorrelation pitch detector based pitch marks
// hnmSignal = ha.analyze(wave, wav.getSampleRate(), f0, null, analysisParams,
// synthesisParamsBeforeNoiseAnalysis, hnmAnalysisFile);
float tAnalysisInSeconds = hnmSignal.frames[0].deltaAnalysisTimeInSeconds;
for (i = 0; i < hnmSignal.frames.length; i++) {
frameStart = frameEnd;
frameEnd = SignalProcUtils.time2sample(tAnalysisInSeconds, hnmSignal.samplingRateInHz);
assert frameEnd <= wave.length : "Frame ends after end of wave data: " + frameEnd + " > " + wave.length;
duration = frameEnd - frameStart;
tAnalysisInSeconds += hnmSignal.frames[i].deltaAnalysisTimeInSeconds;
}
}
/* - For each frame in the hnm modeled speech signal: */
int frameStart = 0;
int frameEnd = 0;
int duration = 0;
long localTime = 0l;
int currentIndex;
int prevIndex = -1;
float[] analysisTimes = hnmSignal.getAnalysisTimes();
float tAnalysisInSeconds;
float[] pmTimes = new float[pmFile.getNumFrames()];
for (i = 0; i < pmFile.getNumFrames(); i++)
pmTimes[i] = pmFile.getTime(i);
tAnalysisInSeconds = hnmSignal.frames[0].deltaAnalysisTimeInSeconds;
for (i = 0; i < pmFile.getNumFrames(); i++) {
if (i < hnmSignal.frames.length) {
frameStart = frameEnd;
frameEnd = (int) ((double) pmFile.getTime(i) * (double) (globSampleRate));
duration = frameEnd - frameStart;
if (frameEnd > 0) {
currentIndex = MathUtils.findClosest(analysisTimes, pmFile.getTime(i));
// System.out.println(currentIndex + " " + i);
hnmSignal.frames[currentIndex].tAnalysisInSeconds = tAnalysisInSeconds;
// Feed the datagram to the timeline
hnmTimeline.feed(new HnmDatagram(duration, hnmSignal.frames[currentIndex]), globSampleRate);
totalTime += duration;
localTime += duration;
tAnalysisInSeconds += hnmSignal.frames[currentIndex].deltaAnalysisTimeInSeconds;
}
}
}
/*
* tAnalysisInSeconds = hnmSignal.frames[0].deltaAnalysisTimeInSeconds; for (i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy