//----------------------------------------------------------------------------// // // // D u r a t i o n R e t r i e v e r // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr.score; import omr.math.Rational; import omr.score.entity.Chord; import omr.score.entity.Measure; import omr.score.entity.MeasureId.PageBased; import omr.score.entity.Page; import omr.score.entity.ScoreSystem; import omr.score.entity.Slot; import omr.score.entity.TimeSignature.InvalidTimeSignature; import omr.score.visitor.AbstractScoreVisitor; import omr.util.TreeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; /** * Class {@code DurationRetriever} can visit a page hierarchy to compute * the actual duration of every measure * * @author Hervé Bitteur */ public class DurationRetriever extends AbstractScoreVisitor { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger( DurationRetriever.class); //~ Instance fields -------------------------------------------------------- // /** Map of Measure id -> Measure duration, whatever the containing part */ private final Map<PageBased, Rational> measureDurations = new HashMap<>(); /** Pass number, since we need 2 passes per system */ private int pass = 1; //~ Constructors ----------------------------------------------------------- // //-------------------// // DurationRetriever // //-------------------// /** * Creates a new DurationRetriever object. */ public DurationRetriever () { } //~ Methods ---------------------------------------------------------------- // //---------------// // visit Measure // //---------------// @Override public boolean visit (Measure measure) { try { logger.debug("Visiting Part#{} {}", measure.getPart().getId(), measure); Rational measureDur = Rational.ZERO; // Whole/multi rests are handled outside of slots for (Slot slot : measure.getSlots()) { if (slot.getStartTime() != null) { for (Chord chord : slot.getChords()) { Rational chordEnd = slot.getStartTime().plus(chord. getDuration()); if (chordEnd.compareTo(measureDur) > 0) { measureDur = chordEnd; } } } } if (!measureDur.equals(Rational.ZERO)) { // Make sure the measure duration is not bigger than limit if (measureDur.compareTo(measure.getExpectedDuration()) <= 0) { measure.setActualDuration(measureDur); } else { measure.setActualDuration(measure.getExpectedDuration()); } measureDurations.put(measure.getPageId(), measureDur); logger.debug("{}: {}", measure.getPageId(), measureDur); } else if (!measure.getWholeChords().isEmpty()) { if (pass > 1) { Rational dur = measureDurations.get(measure.getPageId()); if (dur != null) { measure.setActualDuration(dur); } else { measure.setActualDuration( measure.getExpectedDuration()); } } } } catch (InvalidTimeSignature ex) { } catch (Exception ex) { logger.warn( getClass().getSimpleName() + " Error visiting " + measure, ex); } return false; // Dead end, we don't go deeper than measure level } //------------// // visit Page // //------------// /** * Page hierarchy entry point * * @param page the page for which measure durations are to be computed * @return false, since no further processing is required after this node */ @Override public boolean visit (Page page) { // Delegate to children page.acceptChildren(this); return false; // No default browsing this way } //-------------// // visit Score // //-------------// /** * Score hierarchy entry point, to delegate to all pages * * @param score the score to process * @return false, since no further processing is required after this node */ @Override public boolean visit (Score score) { for (TreeNode pn : score.getPages()) { Page page = (Page) pn; page.accept(this); } return false; // No browsing } //--------------// // visit System // //--------------// /** * System processing. The rest of processing is directly delegated to the * measures * * @param system visit the system to export * @return false */ @Override public boolean visit (ScoreSystem system) { logger.debug("Visiting {}", system); // 2 passes are needed, to get the actual duration of whole notes // Since the measure duration may be specified in another system part for (pass = 1; pass <= 2; pass++) { logger.debug("Pass #{}", pass); // Browse the (SystemParts and the) Measures system.acceptChildren(this); logger.debug("Durations:{}", measureDurations); } return false; // No default browsing this way } }