//----------------------------------------------------------------------------// // // // D y n a m i c s // // // //----------------------------------------------------------------------------// // <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.entity; import omr.constant.ConstantSet; import omr.glyph.Shape; import omr.glyph.facets.Glyph; import omr.score.visitor.ScoreVisitor; import omr.sheet.Scale; import omr.util.TreeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Point; import java.util.HashMap; import java.util.Map; /** * Class {@code Dynamics} represents a dynamics event. * * @author Hervé Bitteur */ public class Dynamics extends MeasureElement implements Direction, Notation { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger(Dynamics.class); /** Specific application parameters */ private static final Constants constants = new Constants(); /** Map Shape -> Signature. */ private static final Map<Shape, String> sigs = new HashMap<>(); static { // Additional characters : m, r, s & z sigs.put(Shape.DYNAMICS_CHAR_M, "m"); sigs.put(Shape.DYNAMICS_CHAR_R, "r"); sigs.put(Shape.DYNAMICS_CHAR_S, "s"); sigs.put(Shape.DYNAMICS_CHAR_Z, "z"); // // True dynamics symbols sigs.put(Shape.DYNAMICS_F, "f"); sigs.put(Shape.DYNAMICS_FF, "ff"); sigs.put(Shape.DYNAMICS_FFF, "fff"); sigs.put(Shape.DYNAMICS_FP, "fp"); sigs.put(Shape.DYNAMICS_FZ, "fz"); sigs.put(Shape.DYNAMICS_MF, "mf"); sigs.put(Shape.DYNAMICS_MP, "mp"); sigs.put(Shape.DYNAMICS_P, "p"); sigs.put(Shape.DYNAMICS_PP, "pp"); sigs.put(Shape.DYNAMICS_PPP, "ppp"); sigs.put(Shape.DYNAMICS_RF, "rf"); sigs.put(Shape.DYNAMICS_RFZ, "rfz"); sigs.put(Shape.DYNAMICS_SF, "sf"); sigs.put(Shape.DYNAMICS_SFFZ, "sffz"); sigs.put(Shape.DYNAMICS_SFP, "sfp"); sigs.put(Shape.DYNAMICS_SFPP, "sfpp"); sigs.put(Shape.DYNAMICS_SFZ, "sfz"); } /** Map Signature -> Shape. */ private static final Map<String, Shape> shapes = new HashMap<>(); static { shapes.put("f", Shape.DYNAMICS_F); shapes.put("ff", Shape.DYNAMICS_FF); shapes.put("fff", Shape.DYNAMICS_FFF); shapes.put("fp", Shape.DYNAMICS_FP); shapes.put("fz", Shape.DYNAMICS_FZ); shapes.put("mf", Shape.DYNAMICS_MF); shapes.put("mp", Shape.DYNAMICS_MP); shapes.put("p", Shape.DYNAMICS_P); shapes.put("pp", Shape.DYNAMICS_PP); shapes.put("ppp", Shape.DYNAMICS_PPP); shapes.put("rf", Shape.DYNAMICS_RF); shapes.put("rfz", Shape.DYNAMICS_RFZ); shapes.put("sf", Shape.DYNAMICS_SF); shapes.put("sffz", Shape.DYNAMICS_SFFZ); shapes.put("sfp", Shape.DYNAMICS_SFP); shapes.put("sfpp", Shape.DYNAMICS_SFPP); shapes.put("sfz", Shape.DYNAMICS_SFZ); } /** Map Shape -> Sound. (TODO: complete the table) */ private static final Map<Shape, Integer> sounds = new HashMap<>(); static { sounds.put(Shape.DYNAMICS_FFF, 144); sounds.put(Shape.DYNAMICS_FF, 122); sounds.put(Shape.DYNAMICS_F, 100); sounds.put(Shape.DYNAMICS_MF, 89); //------------ // Default: 78 //------------ sounds.put(Shape.DYNAMICS_MP, 67); sounds.put(Shape.DYNAMICS_P, 56); sounds.put(Shape.DYNAMICS_PP, 45); sounds.put(Shape.DYNAMICS_PPP, 34); // sounds.put(Shape.DYNAMICS_FP, "fp"); // sounds.put(Shape.DYNAMICS_FZ, "fz"); // sounds.put(Shape.DYNAMICS_RF, "rf"); // sounds.put(Shape.DYNAMICS_RFZ, "rfz"); // sounds.put(Shape.DYNAMICS_SF, "sf"); // sounds.put(Shape.DYNAMICS_SFFZ, "sffz"); // sounds.put(Shape.DYNAMICS_SFP, "sfp"); // sounds.put(Shape.DYNAMICS_SFPP, "sfpp"); // sounds.put(Shape.DYNAMICS_SFZ, "sfz"); } //~ Constructors ----------------------------------------------------------- //----------// // Dynamics // //----------// /** * Creates a new instance of Dynamics event. * * @param measure measure that contains this mark * @param point location of mark * @param chord the chord related to the mark * @param glyph the underlying glyph */ public Dynamics (Measure measure, Point point, Chord chord, Glyph glyph) { super(measure, true, point, chord, glyph); if (chord != null) { chord.addDirection(this); ////// TODO: Not always !!!!!!!!!!!!!!!!!!! } } //~ Methods ---------------------------------------------------------------- //---------------// // getSoundLevel // //---------------// public Integer getSoundLevel () { Shape shape = getShape(); if (shape != null) { return sounds.get(shape); } else { return null; } } //----------// // populate // //----------// /** * Used by SystemTranslator to allocate the dynamics marks. * * @param glyph underlying glyph * @param measure measure where the mark is located * @param point location for the mark */ public static void populate (Glyph glyph, Measure measure, Point point) { if (glyph.isVip()) { logger.info("Dynamics. populate {}", glyph.idString()); } // Can we gather with another dynamics letter? (e.g. m + p -> mp) for (TreeNode node : measure.getChildren()) { if (node instanceof Dynamics) { Dynamics d = (Dynamics) node; if (d.isCompatibleWith(point)) { d.addGlyph(glyph); glyph.setTranslation(d); return; } } } // Otherwise, create a brand new instance glyph.setTranslation( new Dynamics(measure, point, findChord(measure, point), glyph)); } //--------// // accept // //--------// @Override public boolean accept (ScoreVisitor visitor) { return visitor.visit(this); } //---------------// // computeCenter // //---------------// @Override protected void computeCenter () { setCenter(computeGlyphsCenter(getGlyphs())); } //--------------// // computeShape // //--------------// @Override protected Shape computeShape () { StringBuilder sig = new StringBuilder(); for (Glyph glyph : getGlyphs()) { sig.append(sigs.get(glyph.getShape())); } Shape shape = shapes.get(sig.toString()); if (shape == null) { addError("Invalid dynamics signature: " + sig); } return shape; } //------------------// // isCompatibleWith // //------------------// private boolean isCompatibleWith (Point point) { // Check x-proximity and y-alignment Scale scale = getSystem() .getScale(); int dx = scale.toPixels(constants.maxDx); int dy = scale.toPixels(constants.maxDy); // Horizontal distance int xDist = Math.min( Math.abs(getBox().x - point.x), Math.abs((getBox().x + getBox().width) - point.x)); // Vertical distance int yDist = Math.abs(getReferencePoint().y - point.y); return (xDist <= dx) && (yDist <= dy); } //~ Inner Classes ---------------------------------------------------------- //-----------// // Constants // //-----------// private static final class Constants extends ConstantSet { //~ Instance fields ---------------------------------------------------- /** Maximum abscissa difference */ Scale.Fraction maxDx = new Scale.Fraction( 1.5, "Maximum abscissa difference"); /** Maximum ordinate difference */ Scale.Fraction maxDy = new Scale.Fraction( 0.5, "Maximum ordinate difference"); } }