//----------------------------------------------------------------------------//
// //
// S c o r e E x p o r t 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.WellKnowns;
import omr.constant.Constant;
import omr.constant.ConstantSet;
import omr.glyph.Shape;
import static omr.glyph.Shape.*;
import omr.math.Rational;
import static omr.score.MusicXML.*;
import omr.score.entity.Arpeggiate;
import omr.score.entity.Articulation;
import omr.score.entity.Barline;
import omr.score.entity.Beam;
import omr.score.entity.Chord;
import omr.score.entity.ChordSymbol;
import omr.score.entity.Clef;
import omr.score.entity.Coda;
import omr.score.entity.DirectionStatement;
import omr.score.entity.Dynamics;
import omr.score.entity.Fermata;
import omr.score.entity.KeySignature;
import omr.score.entity.LyricsItem;
import omr.score.entity.Measure;
import omr.score.entity.MeasureId.MeasureRange;
import omr.score.entity.Notation;
import omr.score.entity.Ornament;
import omr.score.entity.Page;
import omr.score.entity.Pedal;
import omr.score.entity.ScorePart;
import omr.score.entity.ScoreSystem;
import omr.score.entity.Segno;
import omr.score.entity.Slot;
import omr.score.entity.Slur;
import omr.score.entity.Staff;
import omr.score.entity.SystemPart;
import omr.score.entity.Text;
import omr.score.entity.Text.CreatorText.CreatorType;
import omr.score.entity.TimeSignature;
import omr.score.entity.TimeSignature.InvalidTimeSignature;
import omr.score.entity.Tuplet;
import omr.score.entity.Voice;
import omr.score.entity.Voice.VoiceChord;
import omr.score.entity.Wedge;
import omr.score.midi.MidiAbstractions;
import omr.score.visitor.AbstractScoreVisitor;
import omr.sheet.Scale;
import omr.text.FontInfo;
import omr.util.OmrExecutors;
import omr.util.TreeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import com.audiveris.proxymusic.AboveBelow;
import com.audiveris.proxymusic.Accidental;
import com.audiveris.proxymusic.Articulations;
import com.audiveris.proxymusic.Attributes;
import com.audiveris.proxymusic.Backup;
import com.audiveris.proxymusic.BackwardForward;
import com.audiveris.proxymusic.BarStyle;
import com.audiveris.proxymusic.Bass;
import com.audiveris.proxymusic.BassAlter;
import com.audiveris.proxymusic.BassStep;
import com.audiveris.proxymusic.BeamValue;
import com.audiveris.proxymusic.ClefSign;
import com.audiveris.proxymusic.Credit;
import com.audiveris.proxymusic.Defaults;
import com.audiveris.proxymusic.Degree;
import com.audiveris.proxymusic.DegreeAlter;
import com.audiveris.proxymusic.DegreeType;
import com.audiveris.proxymusic.DegreeValue;
import com.audiveris.proxymusic.Direction;
import com.audiveris.proxymusic.DirectionType;
import com.audiveris.proxymusic.Empty;
import com.audiveris.proxymusic.EmptyPrintStyleAlign;
import com.audiveris.proxymusic.Encoding;
import com.audiveris.proxymusic.FontStyle;
import com.audiveris.proxymusic.FontWeight;
import com.audiveris.proxymusic.FormattedText;
import com.audiveris.proxymusic.Forward;
import com.audiveris.proxymusic.Harmony;
import com.audiveris.proxymusic.Identification;
import com.audiveris.proxymusic.Key;
import com.audiveris.proxymusic.Kind;
import com.audiveris.proxymusic.Lyric;
import com.audiveris.proxymusic.LyricFont;
import com.audiveris.proxymusic.MarginType;
import com.audiveris.proxymusic.MeasureNumberingValue;
import com.audiveris.proxymusic.MidiInstrument;
import com.audiveris.proxymusic.Notations;
import com.audiveris.proxymusic.NoteType;
import com.audiveris.proxymusic.Notehead;
import com.audiveris.proxymusic.NoteheadValue;
import com.audiveris.proxymusic.Ornaments;
import com.audiveris.proxymusic.OverUnder;
import com.audiveris.proxymusic.PageLayout;
import com.audiveris.proxymusic.PageMargins;
import com.audiveris.proxymusic.PartList;
import com.audiveris.proxymusic.PartName;
import com.audiveris.proxymusic.Pitch;
import com.audiveris.proxymusic.Repeat;
import com.audiveris.proxymusic.Rest;
import com.audiveris.proxymusic.RightLeftMiddle;
import com.audiveris.proxymusic.Root;
import com.audiveris.proxymusic.RootStep;
import com.audiveris.proxymusic.RootAlter;
import com.audiveris.proxymusic.Scaling;
import com.audiveris.proxymusic.ScoreInstrument;
import com.audiveris.proxymusic.ScorePartwise;
import com.audiveris.proxymusic.Sound;
import com.audiveris.proxymusic.StaffDetails;
import com.audiveris.proxymusic.StaffLayout;
import com.audiveris.proxymusic.StartStop;
import com.audiveris.proxymusic.StartStopChangeContinue;
import com.audiveris.proxymusic.StartStopContinue;
import com.audiveris.proxymusic.Stem;
import com.audiveris.proxymusic.StemValue;
import com.audiveris.proxymusic.SystemLayout;
import com.audiveris.proxymusic.SystemMargins;
import com.audiveris.proxymusic.TextElementData;
import com.audiveris.proxymusic.Tie;
import com.audiveris.proxymusic.Tied;
import com.audiveris.proxymusic.Time;
import com.audiveris.proxymusic.TimeModification;
import com.audiveris.proxymusic.TimeSymbol;
import com.audiveris.proxymusic.TypedText;
import com.audiveris.proxymusic.UprightInverted;
import com.audiveris.proxymusic.WedgeType;
import com.audiveris.proxymusic.Work;
import com.audiveris.proxymusic.YesNo;
import com.audiveris.proxymusic.util.Marshalling;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
/**
* Class {@code ScoreExporter} visits the score hierarchy to export
* the score to a MusicXML file, stream or DOM.
*
* @author Hervé Bitteur
*/
public class ScoreExporter
extends AbstractScoreVisitor
{
//~ Static fields/initializers ---------------------------------------------
/** Specific application parameters */
private static final Constants constants = new Constants();
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(ScoreExporter.class);
/** A future which reflects whether JAXB has been initialized * */
private static final Future<Void> loading = OmrExecutors.
getCachedLowExecutor().submit(
new Callable<Void>()
{
@Override
public Void call ()
throws Exception
{
try {
Marshalling.getContext();
} catch (JAXBException ex) {
logger.warn("Error preloading JaxbContext", ex);
throw ex;
}
return null;
}
});
/** Default page horizontal margin */
private static final BigDecimal pageHorizontalMargin =
new BigDecimal(constants.pageHorizontalMargin.getValue());
/** Default page vertical margin */
private static final BigDecimal pageVerticalMargin =
new BigDecimal(constants.pageVerticalMargin.getValue());
//~ Instance fields --------------------------------------------------------
/** The related score */
private final Score score;
/** The score proxy built precisely for export via JAXB */
private final ScorePartwise scorePartwise = new ScorePartwise();
/** Current context */
private Current current = new Current();
/** Current flags */
private IsFirst isFirst = new IsFirst();
/** Map of Slur numbers, reset for every scorePart */
private Map<Slur, Integer> slurNumbers = new HashMap<>();
/** Map of Tuplet numbers, reset for every measure */
private Map<Tuplet, Integer> tupletNumbers = new HashMap<>();
/** Potential range of selected measures */
private MeasureRange measureRange;
/** Factory for proxymusic entities */
private final com.audiveris.proxymusic.ObjectFactory factory = new com.audiveris.proxymusic.ObjectFactory();
//~ Constructors -----------------------------------------------------------
//---------------//
// ScoreExporter //
//---------------//
/**
* Create a new ScoreExporter object, on a related score instance.
*
* @param score the score to export (cannot be null)
* @throws InterruptedException
* @throws ExecutionException
*/
public ScoreExporter (Score score)
throws InterruptedException, ExecutionException
{
if (score == null) {
throw new IllegalArgumentException("Trying to export a null score");
}
// Make sure the JAXB context is ready
loading.get();
this.score = score;
}
//~ Methods ----------------------------------------------------------------
//
//--------//
// export //
//--------//
/**
* Export the score to a file.
*
* @param xmlFile the xml file to write (cannot be null)
* @param injectSignature should we inject out signature?
*/
public void export (File xmlFile,
boolean injectSignature)
throws Exception
{
export(new FileOutputStream(xmlFile), injectSignature);
}
//--------//
// export //
//--------//
/**
* Export the score to an output stream.
*
* @param os the output stream where XML data is written
* (cannot be null)
* @param injectSignature should we inject our signature?
* @throws IOException
* @throws Exception
*/
public void export (OutputStream os,
boolean injectSignature)
throws IOException, Exception
{
if (os == null) {
throw new IllegalArgumentException(
"Trying to export a score to a null output stream");
}
// Let visited nodes fill the scorePartWise proxy
try {
score.accept(this);
} finally {
// Marshal the proxy with what we've got
Marshalling.marshal(scorePartwise, os, injectSignature);
}
}
//--------//
// export //
//--------//
/**
* Export the score to DOM node.
* (No longer used, it was meant for Audiveris->Zong pure java transfer)
*
* @param node the DOM node to export to (cannot be null)
* @param injectSignature should we inject our signature?
* @throws java.io.IOException
* @throws java.lang.Exception
*/
public void export (Node node,
boolean injectSignature)
throws IOException, Exception
{
if (node == null) {
throw new IllegalArgumentException(
"Trying to export a score to a null DOM Node");
}
try {
// Let visited nodes fill the scorePartwise proxy
buildScorePartwise();
} finally {
// Finally, marshal the proxy with what we've got
Marshalling.marshal(scorePartwise, node, injectSignature);
}
}
//---------//
// preload //
//---------//
/**
* Empty static method, just to trigger class elaboration.
*/
public static void preload ()
{
}
//-----------------//
// setMeasureRange //
//-----------------//
/**
* Set a specific range of measures to export.
*
* @param measureRange the range of desired measures
*/
public void setMeasureRange (MeasureRange measureRange)
{
this.measureRange = measureRange;
}
//- All Visiting Methods ---------------------------------------------------
//------------------//
// visit Arpeggiate //
//------------------//
@Override
public boolean visit (Arpeggiate arpeggiate)
{
try {
logger.debug("Visiting {}", arpeggiate);
com.audiveris.proxymusic.Arpeggiate pmArpeggiate = factory.createArpeggiate();
// relative-x
pmArpeggiate.setRelativeX(
toTenths(
arpeggiate.getReferencePoint().x
- current.note.getCenterLeft().x));
// number ???
// TODO
//
getNotations().getTiedOrSlurOrTuplet().add(pmArpeggiate);
} catch (Exception ex) {
logger.warn("Error visiting " + arpeggiate, ex);
}
return false;
}
//--------------------//
// visit Articulation //
//--------------------//
@Override
public boolean visit (Articulation articulation)
{
try {
logger.debug("Visiting {}", articulation);
JAXBElement<?> element = getArticulationObject(
articulation.getShape());
// Staff ?
Staff staff = current.note.getStaff();
// Placement
Class<?> classe = element.getDeclaredType();
Method method = classe.getMethod(
"setPlacement",
AboveBelow.class);
method.invoke(
element.getValue(),
(articulation.getReferencePoint().y < current.note.
getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// Default-Y
method = classe.getMethod("setDefaultY", BigDecimal.class);
method.invoke(
element.getValue(),
yOf(articulation.getReferencePoint(), staff));
// Include in Articulations
getArticulations().getAccentOrStrongAccentOrStaccato().add(element);
} catch (Exception ex) {
logger.warn("Error visiting " + articulation, ex);
}
return false;
}
//---------------//
// visit Barline //
//---------------//
@Override
public boolean visit (Barline barline)
{
try {
if (barline == null) {
return false;
}
logger.debug("Visiting {}", barline);
Shape shape = barline.getShape();
if ((shape != omr.glyph.Shape.THIN_BARLINE)
&& (shape != omr.glyph.Shape.PART_DEFINING_BARLINE)) {
try {
com.audiveris.proxymusic.Barline pmBarline = factory.createBarline();
com.audiveris.proxymusic.BarStyleColor barStyleColor = factory.
createBarStyleColor();
if (barline == current.measure.getBarline()) {
// The bar is on right side
pmBarline.setLocation(RightLeftMiddle.RIGHT);
if ((shape == RIGHT_REPEAT_SIGN)
|| (shape == BACK_TO_BACK_REPEAT_SIGN)) {
barStyleColor.setValue(BarStyle.LIGHT_HEAVY);
Repeat repeat = factory.createRepeat();
repeat.setDirection(BackwardForward.BACKWARD);
pmBarline.setRepeat(repeat);
}
} else {
// Inside barline (on left)
// Or bar is on left side
pmBarline.setLocation(RightLeftMiddle.LEFT);
if ((shape == LEFT_REPEAT_SIGN)
|| (shape == BACK_TO_BACK_REPEAT_SIGN)) {
barStyleColor.setValue(BarStyle.HEAVY_LIGHT);
Repeat repeat = factory.createRepeat();
repeat.setDirection(BackwardForward.FORWARD);
pmBarline.setRepeat(repeat);
}
}
// Default: use style inferred from shape
// TODO: improve error handling here !!!!!!!!!
if (barStyleColor.getValue() == null) {
if (barline.getShape() != null) {
barStyleColor.setValue(
barStyleOf(barline.getShape()));
}
}
// Everything is now OK
pmBarline.setBarStyle(barStyleColor);
current.pmMeasure.getNoteOrBackupOrForward().add(pmBarline);
} catch (Exception ex) {
logger.warn("Cannot visit barline", ex);
}
}
} catch (Exception ex) {
logger.warn("Error visiting " + barline, ex);
}
return true;
}
//-------------//
// visit Chord //
//-------------//
@Override
public boolean visit (Chord chord)
{
logger.error("Chord objects should not be visited by ScoreExporter");
return false;
}
//------------//
// visit Clef //
//------------//
@Override
public boolean visit (Clef clef)
{
try {
logger.debug("Visiting {}", clef);
if (isNewClef(clef)) {
getAttributes().getClef().add(buildClef(clef));
}
} catch (Exception ex) {
logger.warn("Error visiting " + clef, ex);
}
return true;
}
//------------//
// visit Coda //
//------------//
@Override
public boolean visit (Coda coda)
{
try {
logger.debug("Visiting {}", coda);
Direction direction = factory.createDirection();
// Staff ?
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
com.audiveris.proxymusic.EmptyPrintStyleAlign pmCoda = factory.createEmptyPrintStyleAlign();
// default-x
pmCoda.setDefaultX(
toTenths(
coda.getReferencePoint().x - current.measure.getLeftX()));
// default-y
pmCoda.setDefaultY(yOf(coda.getReferencePoint(), staff));
DirectionType directionType = new DirectionType();
directionType.getCoda().add(pmCoda);
direction.getDirectionType().add(directionType);
// Need also a Sound element
Sound sound = factory.createSound();
direction.setSound(sound);
sound.setCoda("" + current.measure.getScoreId());
sound.setDivisions(
new BigDecimal(
score.simpleDurationOf(
omr.score.entity.Note.QUARTER_DURATION)));
// Everything is now OK
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
} catch (Exception ex) {
logger.warn("Error visiting " + coda, ex);
}
return true;
}
//--------------------------//
// visit DirectionStatement //
//--------------------------//
@Override
public boolean visit (DirectionStatement words)
{
try {
logger.debug("Visiting {}", words);
String content = words.getText().getContent();
if (content != null) {
Direction direction = factory.createDirection();
DirectionType directionType = factory.createDirectionType();
FormattedText pmWords = factory.createFormattedText();
pmWords.setValue(content);
// Staff
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
// Placement
direction.
setPlacement(
(words.getReferencePoint().y < current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// default-y
pmWords.setDefaultY(yOf(words.getReferencePoint(), staff));
// Font information
setFontInfo(pmWords, words.getText());
// relative-x
pmWords.setRelativeX(
toTenths(
words.getReferencePoint().x
- current.note.getCenterLeft().x));
// Everything is now OK
directionType.getWords().add(pmWords);
direction.getDirectionType().add(directionType);
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
}
} catch (Exception ex) {
logger.warn("Error visiting " + words, ex);
}
return true;
}
//-------------------//
// visit ChordSymbol //
//-------------------//
@Override
public boolean visit (ChordSymbol symbol)
{
try {
logger.debug("Visiting {}", symbol);
omr.score.entity.ChordInfo info = symbol.getInfo();
Staff staff = current.note.getStaff();
Harmony harmony = factory.createHarmony();
// default-y
harmony.setDefaultY(yOf(symbol.getReferencePoint(), staff));
// font-size
harmony.setFontSize("" + symbol.getText().getExportedFontSize());
// relative-x
harmony.setRelativeX(
toTenths(
symbol.getReferencePoint().x
- current.note.getCenterLeft().x));
// Placement
harmony.setPlacement(
(symbol.getReferencePoint().y < current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// Staff
insertStaffId(harmony, staff);
// Root
Root root = factory.createRoot();
RootStep rootStep = factory.createRootStep();
rootStep.setValue(stepOf(info.getRoot().step));
root.setRootStep(rootStep);
if (info.getRoot().alter != 0) {
RootAlter alter = factory.createRootAlter();
alter.setValue(new BigDecimal(info.getRoot().alter));
root.setRootAlter(alter);
}
harmony.getHarmonyChord().add(root);
// Kind
Kind kind = factory.createKind();
kind.setValue(kindOf(info.getKind().type));
kind.setText(info.getKind().text);
if (info.getKind().paren) {
kind.setParenthesesDegrees(YesNo.YES);
}
if (info.getKind().symbol) {
kind.setUseSymbols(YesNo.YES);
}
harmony.getHarmonyChord().add(kind);
// Bass
if (info.getBass() != null) {
Bass bass = factory.createBass();
BassStep bassStep = factory.createBassStep();
bassStep.setValue(stepOf(info.getBass().step));
bass.setBassStep(bassStep);
if (info.getBass().alter != 0) {
BassAlter bassAlter = factory.createBassAlter();
bassAlter.setValue(new BigDecimal(info.getBass().alter));
bass.setBassAlter(bassAlter);
}
harmony.getHarmonyChord().add(bass);
}
// Degrees?
for (omr.score.entity.ChordInfo.Degree deg : info.getDegrees()) {
Degree degree = factory.createDegree();
DegreeValue value = factory.createDegreeValue();
value.setValue(new BigInteger("" + deg.value));
degree.setDegreeValue(value);
DegreeAlter alter = factory.createDegreeAlter();
alter.setValue(new BigDecimal(deg.alter));
degree.setDegreeAlter(alter);
DegreeType type = factory.createDegreeType();
type.setValue(typeOf(deg.type));
degree.setDegreeType(type);
harmony.getHarmonyChord().add(degree);
}
// Everything is now OK
current.pmMeasure.getNoteOrBackupOrForward().add(harmony);
} catch (Exception ex) {
logger.warn("Error visiting " + symbol, ex);
}
return true;
}
//----------------//
// visit Dynamics //
//----------------//
@Override
public boolean visit (Dynamics dynamics)
{
try {
logger.debug("Visiting {}", dynamics);
// No point to export incorrect dynamics
if (dynamics.getShape() == null) {
return false;
}
Direction direction = factory.createDirection();
DirectionType directionType = factory.createDirectionType();
com.audiveris.proxymusic.Dynamics pmDynamics = factory.createDynamics();
// Precise dynamic signature
pmDynamics.getPOrPpOrPpp().add(
getDynamicsObject(dynamics.getShape()));
// Staff ?
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
// Placement
if (dynamics.getReferencePoint().y < current.note.getCenter().y) {
direction.setPlacement(AboveBelow.ABOVE);
} else {
direction.setPlacement(AboveBelow.BELOW);
}
// default-y
pmDynamics.setDefaultY(yOf(dynamics.getReferencePoint(), staff));
// Relative-x (No offset for the time being) using note left side
pmDynamics.setRelativeX(
toTenths(
dynamics.getReferencePoint().x
- current.note.getCenterLeft().x));
// Related sound level, if available
Integer soundLevel = dynamics.getSoundLevel();
if (soundLevel != null) {
Sound sound = factory.createSound();
sound.setDynamics(new BigDecimal(soundLevel));
direction.setSound(sound);
}
// Everything is now OK
directionType.getDynamics().add(pmDynamics);
direction.getDirectionType().add(directionType);
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
} catch (Exception ex) {
logger.warn("Error visiting " + dynamics, ex);
}
return false;
}
//---------------//
// visit Fermata //
//---------------//
@Override
public boolean visit (Fermata fermata)
{
try {
logger.debug("Visiting {}", fermata);
com.audiveris.proxymusic.Fermata pmFermata = factory.createFermata();
// default-y (of the fermata dot)
// For upright we use bottom of the box, for inverted the top of the box
Rectangle box = fermata.getBox();
Point dot;
if (fermata.getShape() == Shape.FERMATA_BELOW) {
dot = new Point(box.x + (box.width / 2), box.y);
} else {
dot = new Point(
box.x + (box.width / 2),
box.y + box.height);
}
pmFermata.setDefaultY(yOf(dot, current.note.getStaff()));
// Type
pmFermata.
setType(
(fermata.getShape() == Shape.FERMATA) ? UprightInverted.UPRIGHT
: UprightInverted.INVERTED);
// Everything is now OK
getNotations().getTiedOrSlurOrTuplet().add(pmFermata);
} catch (Exception ex) {
logger.warn("Error visiting " + fermata, ex);
}
return false;
}
//--------------------//
// visit KeySignature //
//--------------------//
@Override
public boolean visit (KeySignature keySignature)
{
try {
logger.debug("Visiting {}", keySignature);
if (isNewKeySignature(keySignature)) {
Key key = factory.createKey();
key.setFifths(new BigInteger("" + keySignature.getKey()));
// Trick: add this key signature only if it does not already exist
List<Key> keys = getAttributes().getKey();
for (Key k : keys) {
if (areEqual(k, key)) {
return true; // Already inserted, so give up
}
}
keys.add(key);
}
} catch (Exception ex) {
logger.warn("Error visiting " + keySignature, ex);
}
return true;
}
//---------------//
// visit Measure //
//---------------//
@Override
public boolean visit (Measure measure)
{
try {
logger.debug("Visiting {}", measure);
// Make sure this measure is within the range to be exported
if (!isDesired(measure)) {
logger.debug("{} skipped.", measure);
return false;
}
///logger.info("Visiting " + measure);
logger.debug("{} : {}", measure, isFirst);
current.measure = measure;
tupletNumbers.clear();
// Allocate Measure
current.pmMeasure = factory.createScorePartwisePartMeasure();
current.pmMeasure.setNumber(measure.getScoreId());
if (measure.getWidth() != null) {
current.pmMeasure.setWidth(toTenths(measure.getWidth()));
}
if (measure.isImplicit()) {
current.pmMeasure.setImplicit(YesNo.YES);
}
// Do we need to create & export a dummy initial measure?
if (((measureRange != null) && !measure.isTemporary()
&& (measure.getIdValue() > 1))
&& // TODO: Following line is illegal
(measure.getScoreId().equals(measureRange.getFirstId()))) {
insertCurrentContext(measure);
}
// Print?
new MeasurePrint(measure).process();
// Inside barline?
visit(measure.getInsideBarline());
// Right Barline
if (!measure.isDummy()) {
visit(measure.getBarline());
}
// Left barline ?
Measure prevMeasure = (Measure) measure.getPreviousSibling();
if ((prevMeasure != null) && !prevMeasure.isDummy()) {
visit(prevMeasure.getBarline());
}
// Divisions?
if (isFirst.page && isFirst.system && isFirst.measure) {
try {
getAttributes().setDivisions(
new BigDecimal(
score.simpleDurationOf(
omr.score.entity.Note.QUARTER_DURATION)));
} catch (Exception ex) {
if (score.getDurationDivisor() == null) {
logger.warn(
"Not able to infer division value for part {}",
current.scorePart.getPid());
} else {
logger.warn("Error on divisions", ex);
}
}
}
// Number of staves, if > 1
if (isFirst.page && isFirst.system && isFirst.measure
&& current.scorePart.isMultiStaff()) {
getAttributes().setStaves(
new BigInteger("" + current.scorePart.getStaffCount()));
}
// Tempo?
if (isFirst.page && isFirst.system && isFirst.measure
&& !measure.isDummy()) {
Direction direction = factory.createDirection();
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
DirectionType directionType = factory.createDirectionType();
direction.getDirectionType().add(directionType);
// Use a dummy words element
FormattedText pmWords = factory.
createFormattedText();
directionType.getWords().add(pmWords);
pmWords.setValue("");
Sound sound = factory.createSound();
sound.setTempo(
new BigDecimal(score.getTempoParam().getTarget()));
direction.setSound(sound);
}
// Specific browsing down the measure
// Insert KeySignatures, TimeSignatures
measure.getKeySigList().acceptChildren(this);
measure.getTimeSigList().acceptChildren(this);
// Clefs may be inserted further down the measure
ClefIterators clefIters = new ClefIterators(measure);
// Insert clefs that occur before first time slot
List<Slot> slots = measure.getSlots();
if (slots.isEmpty()) {
clefIters.push(null, null);
} else {
clefIters.push(slots.get(0).getX(), null);
}
// Now voice per voice
Rational timeCounter = Rational.ZERO;
for (Voice voice : measure.getVoices()) {
current.voice = voice;
// Need a backup ?
if (!timeCounter.equals(Rational.ZERO)) {
insertBackup(timeCounter);
timeCounter = Rational.ZERO;
}
if (voice.isWhole()) {
// Delegate to the chord children directly
Chord chord = voice.getWholeChord();
clefIters.push(measure.getRightX(), chord.getStaff());
chord.acceptChildren(this);
timeCounter = measure.getExpectedDuration();
} else {
for (Slot slot : measure.getSlots()) {
VoiceChord info = voice.getSlotInfo(slot);
if ((info != null) && // Skip free slots
(info.getStatus() == Voice.Status.BEGIN)) {
Chord chord = info.getChord();
clefIters.push(
chord.getCenter().x,
chord.getStaff());
// Need a forward before this chord ?
Rational startTime = chord.getStartTime();
if (timeCounter.compareTo(startTime) < 0) {
insertForward(
startTime.minus(timeCounter),
chord);
timeCounter = startTime;
}
// Delegate to the chord children directly
chord.acceptChildren(this);
timeCounter = timeCounter.plus(chord.getDuration());
}
}
// Need an ending forward ?
if (!measure.isImplicit() && !measure.isFirstHalf()) {
Rational termination = voice.getTermination();
if ((termination != null)
&& (termination.compareTo(Rational.ZERO) < 0)) {
Rational delta = termination.opposite();
insertForward(delta, voice.getLastChord());
timeCounter = timeCounter.plus(delta);
}
}
}
}
// Clefs that occur after time slots, if any
clefIters.push(null, null);
// Everything is now OK
current.pmPart.getMeasure().add(current.pmMeasure);
} catch (Exception ex) {
logger.warn("Error visiting " + measure + " in " + current.page, ex);
}
// Safer...
current.endMeasure();
tupletNumbers.clear();
isFirst.measure = false;
return false; // Not this way
}
//------------//
// visit Note //
//------------//
@Override
public boolean visit (omr.score.entity.Note note)
{
try {
logger.debug("Visiting {}", note);
current.note = note;
Chord chord = note.getChord();
// For first note in chord
if (chord.getNotes().indexOf(note) == 0) {
// Chord direction events
for (omr.score.entity.Direction node : chord.getDirections()) {
node.accept(this);
}
// Chord symbol, if any
if (chord.getChordSymbol() != null) {
chord.getChordSymbol().accept(this);
}
}
current.pmNote = factory.createNote();
Staff staff = note.getStaff();
// Chord notation events for first note in chord
if (chord.getNotes().indexOf(note) == 0) {
for (Notation node : chord.getNotations()) {
node.accept(this);
}
} else {
// Chord indication for every other note
current.pmNote.setChord(new Empty());
// Arpeggiate also?
for (Notation node : chord.getNotations()) {
if (node instanceof Arpeggiate) {
node.accept(this);
}
}
}
// Rest ?
if (note.isRest()) {
Rest rest = factory.createRest();
// Rest for the whole measure?
if (chord.isWholeDuration()) {
rest.setMeasure(YesNo.YES);
}
/// TODO ??? Set Step or Octave ???
current.pmNote.setRest(rest);
} else {
// Pitch
Pitch pitch = factory.createPitch();
pitch.setStep(stepOf(note.getStep()));
pitch.setOctave(note.getOctave());
if (note.getAlter() != 0) {
pitch.setAlter(new BigDecimal(note.getAlter()));
}
current.pmNote.setPitch(pitch);
}
// Default-x (use left side of the note wrt measure)
if (!note.getMeasure().isDummy()) {
int noteLeft = note.getCenterLeft().x;
current.pmNote.setDefaultX(
toTenths(noteLeft - note.getMeasure().getLeftX()));
}
// Tuplet factor ?
if (chord.getTupletFactor() != null) {
TimeModification timeModification = factory.
createTimeModification();
timeModification.setActualNotes(
new BigInteger("" + chord.getTupletFactor().actualDen));
timeModification.setNormalNotes(
new BigInteger("" + chord.getTupletFactor().actualNum));
current.pmNote.setTimeModification(timeModification);
}
// Duration
try {
Rational dur;
if (chord.isWholeDuration()) {
dur = chord.getMeasure().getActualDuration();
} else {
dur = chord.getDuration();
}
current.pmNote.setDuration(
new BigDecimal(score.simpleDurationOf(dur)));
} catch (Exception ex) {
if (score.getDurationDivisor() != null) {
logger.warn("Not able to get duration of note", ex);
}
}
// Voice
current.pmNote.setVoice("" + chord.getVoice().getId());
// Type
if (!note.getMeasure().isDummy()) {
NoteType noteType = factory.createNoteType();
noteType.setValue("" + getNoteTypeName(note));
if (!chord.isWholeDuration()) {
current.pmNote.setType(noteType);
}
}
// For specific mirrored note
if (note.getMirroredNote() != null) {
int fbn = note.getChord().getFlagsNumber()
+ note.getChord().getBeams().size();
if ((fbn > 0) && (note.getShape() == NOTEHEAD_VOID)) {
// Indicate that the head should not be filled
// <notehead filled="no">normal</notehead>
Notehead notehead = factory.createNotehead();
notehead.setFilled(YesNo.NO);
notehead.setValue(NoteheadValue.NORMAL);
current.pmNote.setNotehead(notehead);
}
}
// Stem ?
if (chord.getStem() != null) {
Stem pmStem = factory.createStem();
Point tail = chord.getTailLocation();
pmStem.setDefaultY(yOf(tail, staff));
if (tail.y < note.getCenter().y) {
pmStem.setValue(StemValue.UP);
} else {
pmStem.setValue(StemValue.DOWN);
}
current.pmNote.setStem(pmStem);
}
// Staff ?
if (current.scorePart.isMultiStaff()) {
current.pmNote.setStaff(new BigInteger("" + staff.getId()));
}
// Dots
for (int i = 0; i < chord.getDotsNumber(); i++) {
current.pmNote.getDot().add(factory.createEmptyPlacement());
}
// Accidental ?
if (note.getAccidental() != null) {
Accidental accidental = factory.createAccidental();
accidental.setValue(
accidentalValueOf(note.getAccidental().getShape()));
current.pmNote.setAccidental(accidental);
}
// Beams ?
for (Beam beam : chord.getBeams()) {
com.audiveris.proxymusic.Beam pmBeam = factory.createBeam();
pmBeam.setNumber(1 + chord.getBeams().indexOf(beam));
if (beam.isHook()) {
if (beam.getCenter().x > chord.getStem().getLocation().x) {
pmBeam.setValue(BeamValue.FORWARD_HOOK);
} else {
pmBeam.setValue(BeamValue.BACKWARD_HOOK);
}
} else {
List<Chord> chords = beam.getChords();
if (chords.get(0) == chord) {
pmBeam.setValue(BeamValue.BEGIN);
} else if (chords.get(chords.size() - 1) == chord) {
pmBeam.setValue(BeamValue.END);
} else {
pmBeam.setValue(BeamValue.CONTINUE);
}
}
current.pmNote.getBeam().add(pmBeam);
}
// Ties / Slurs
for (Slur slur : note.getSlurs()) {
slur.accept(this);
}
// Lyrics ?
if (note.getSyllables() != null) {
for (LyricsItem syllable : note.getSyllables()) {
if (syllable.getContent() != null) {
Lyric pmLyric = factory.createLyric();
pmLyric.setDefaultY(
yOf(syllable.getReferencePoint(), staff));
pmLyric.setNumber(
"" + syllable.getLyricsLine().getId());
TextElementData pmText = factory.createTextElementData();
pmText.setValue(syllable.getContent());
pmLyric.getElisionAndSyllabicAndText().
add(getSyllabic(syllable.
getSyllabicType()));
pmLyric.getElisionAndSyllabicAndText().add(pmText);
current.pmNote.getLyric().add(pmLyric);
}
}
}
// Everything is OK
current.pmMeasure.getNoteOrBackupOrForward().add(current.pmNote);
} catch (Exception ex) {
logger.warn("Error visiting " + note, ex);
}
// Safer...
current.endNote();
return true;
}
//----------------//
// visit Ornament //
//----------------//
@Override
@SuppressWarnings("unchecked")
public boolean visit (Ornament ornament)
{
try {
logger.debug("Visiting {}", ornament);
JAXBElement<?> element = getOrnamentObject(ornament.getShape());
// Placement?
Class<?> classe = element.getDeclaredType();
Method method = classe.getMethod(
"setPlacement",
AboveBelow.class);
method.invoke(
element.getValue(),
(ornament.getReferencePoint().y < current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// Everything is OK
// Include in ornaments
getOrnaments().getTrillMarkOrTurnOrDelayedTurn().add(element);
} catch (Exception ex) {
logger.warn("Error visiting " + ornament, ex);
}
return false;
}
//------------//
// visit Page //
//------------//
@Override
public boolean visit (Page page)
{
try {
logger.debug("Visiting {}", page);
isFirst.page = (page == score.getFirstPage());
isFirst.system = true;
isFirst.measure = true;
current.page = page;
Page prevPage = (Page) page.getPreviousSibling();
current.pageMeasureIdOffset = (prevPage == null) ? 0
: (current.pageMeasureIdOffset
+ prevPage.getDeltaMeasureId());
current.scale = page.getScale();
} catch (Exception ex) {
logger.warn("Error visiting " + page, ex);
}
return true;
}
//-------------//
// visit Pedal //
//-------------//
@Override
public boolean visit (Pedal pedal)
{
try {
logger.debug("Visiting {}", pedal);
Direction direction = new Direction();
DirectionType directionType = new DirectionType();
com.audiveris.proxymusic.Pedal pmPedal = new com.audiveris.proxymusic.Pedal();
// No line (for the time being)
pmPedal.setLine(YesNo.NO);
// Start / Stop type
pmPedal.setType(
pedal.isStart()
? StartStopChangeContinue.START
: StartStopChangeContinue.STOP);
// Staff ?
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
// default-x
pmPedal.setDefaultX(
toTenths(
pedal.getReferencePoint().x - current.measure.getLeftX()));
// default-y
pmPedal.setDefaultY(yOf(pedal.getReferencePoint(), staff));
// Placement
direction.setPlacement(
(pedal.getReferencePoint().y < current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// Everything is OK
directionType.setPedal(pmPedal);
direction.getDirectionType().add(directionType);
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
} catch (Exception ex) {
logger.warn("Error visiting " + pedal, ex);
}
return true;
}
//-------------//
// visit Score //
//-------------//
/**
* Allocate/populate everything that directly relates to the score
* instance.
* The rest of processing is delegated to the score children, that is to
* say pages (TBI), then systems, etc...
*
* @param score visit the score to export
* @return false, since no further processing is required after this node
*/
@Override
public boolean visit (Score score)
{
try {
logger.debug("Visiting {}", score);
// Reset durations for the score
score.setDurationDivisor(null);
// No version inserted
// Let the marshalling class handle it
// Identification
Identification identification = factory.createIdentification();
// Source
identification.setSource(score.getImagePath());
// Encoding
Encoding encoding = factory.createEncoding();
scorePartwise.setIdentification(identification);
// [Encoding]/Software
encoding.getEncodingDateOrEncoderOrSoftware().add(
factory.createEncodingSoftware(
WellKnowns.TOOL_NAME + " " + WellKnowns.TOOL_REF));
// [Encoding]/EncodingDate
// Let the Marshalling class handle it
identification.setEncoding(encoding);
// Defaults
Defaults defaults = new Defaults();
// [Defaults]/Scaling (using first page)
Page firstPage = score.getFirstPage();
if (current.scale == null) {
current.scale = firstPage.getScale();
}
if (current.scale != null) {
Scaling scaling = factory.createScaling();
defaults.setScaling(scaling);
scaling.setMillimeters(
new BigDecimal(
String.format("%.4f", (current.scale.getInterline() * 25.4 * 4) / 300))); // Assuming 300 DPI
scaling.setTenths(new BigDecimal(40));
// [Defaults]/PageLayout (using first page)
if (firstPage.getDimension() != null) {
PageLayout pageLayout = factory.createPageLayout();
defaults.setPageLayout(pageLayout);
pageLayout.setPageHeight(
toTenths(firstPage.getDimension().height));
pageLayout.setPageWidth(
toTenths(firstPage.getDimension().width));
PageMargins pageMargins = factory.createPageMargins();
pageMargins.setType(MarginType.BOTH);
pageMargins.setLeftMargin(pageHorizontalMargin);
pageMargins.setRightMargin(pageHorizontalMargin);
pageMargins.setTopMargin(pageVerticalMargin);
pageMargins.setBottomMargin(pageVerticalMargin);
pageLayout.getPageMargins().add(pageMargins);
}
}
// [Defaults]/LyricFont
Font lyricFont = omr.score.entity.Text.getLyricsFont();
LyricFont pmLyricFont = factory.createLyricFont();
pmLyricFont.setFontFamily(lyricFont.getName());
pmLyricFont.setFontSize(
"" + omr.score.entity.Text.getLyricsFontSize());
if (lyricFont.isItalic()) {
pmLyricFont.setFontStyle(FontStyle.ITALIC);
}
defaults.getLyricFont().add(pmLyricFont);
scorePartwise.setDefaults(defaults);
// PartList & sequence of parts
if (score.getPartList() != null) {
PartList partList = factory.createPartList();
scorePartwise.setPartList(partList);
// Here we browse the score hierarchy once for each score scorePart
isFirst.scorePart = true;
for (ScorePart p : score.getPartList()) {
partList.getPartGroupOrScorePart().add(getScorePart(p));
isFirst.scorePart = false;
}
}
} catch (Exception ex) {
logger.warn("Error visiting " + score, ex);
}
return false; // We don't go this way
}
//-------------------//
// visit ScoreSystem //
//-------------------//
/**
* Allocate/populate everything that directly relates to this
* system in the current scorePart.
* The rest of processing is directly delegated to the measures
*
* @param system the system to export
* @return false
*/
@Override
public boolean visit (ScoreSystem system)
{
try {
logger.debug("Visiting {}", system);
current.system = system;
isFirst.measure = true;
SystemPart systemPart = system.getPart(current.scorePart.getId());
if (systemPart != null) {
systemPart.accept(this);
} else {
// Need to build an artificial system scorePart
// Or simply delegating to the series of artificial measures
SystemPart dummyPart = system.getFirstRealPart().
createDummyPart(
current.scorePart.getId());
dummyPart.accept(this);
}
// If we have exported a measure, we are no longer in the first system
if (!isFirst.measure) {
isFirst.system = false;
}
} catch (Exception ex) {
logger.warn("Error visiting " + system, ex);
}
return false; // No default browsing this way
}
//-------------//
// visit Segno //
//-------------//
@Override
public boolean visit (Segno segno)
{
try {
logger.debug("Visiting {}", segno);
Direction direction = new Direction();
DirectionType directionType = factory.createDirectionType();
EmptyPrintStyleAlign empty = factory.createEmptyPrintStyleAlign();
// Staff ?
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
// default-x
empty.setDefaultX(
toTenths(
segno.getReferencePoint().x - current.measure.getLeftX()));
// default-y
empty.setDefaultY(yOf(segno.getReferencePoint(), staff));
// Need also a Sound element (TODO: We don't do anything with sound!)
Sound sound = factory.createSound();
sound.setSegno("" + current.measure.getScoreId());
sound.setDivisions(
new BigDecimal(
score.simpleDurationOf(
omr.score.entity.Note.QUARTER_DURATION)));
// Everything is OK
directionType.getSegno().add(empty);
direction.getDirectionType().add(directionType);
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
} catch (Exception ex) {
logger.warn("Error visiting " + segno, ex);
}
return true;
}
//------------//
// visit Slur //
//------------//
@Override
public boolean visit (Slur slur)
{
try {
logger.debug("Visiting {}", slur);
// Make sure we have notes (or extension) on both sides
// TODO: Make an exception for slurs at beginning of page!
if ((slur.getLeftNote() == null)
&& (slur.getLeftExtension() == null)) {
slur.addError("Non left-connected slur is not exported");
return false;
}
// TODO: Make an exception for slurs at end of page!
if ((slur.getRightNote() == null)
&& (slur.getRightExtension() == null)) {
slur.addError("Non right-connected slur is not exported");
return false;
}
// Note contextual data
boolean isStart = slur.getLeftNote() == current.note;
int noteLeft = current.note.getCenterLeft().x;
Staff staff = current.note.getStaff();
if (slur.isTie()) {
// Tie element
Tie tie = factory.createTie();
tie.setType(isStart ? StartStop.START : StartStop.STOP);
current.pmNote.getTie().add(tie);
// Tied element
Tied tied = factory.createTied();
// Type
tied.setType(isStart ? StartStopContinue.START : StartStopContinue.STOP);
// Orientation
if (isStart) {
tied.setOrientation(
slur.isBelow() ? OverUnder.UNDER : OverUnder.OVER);
}
// Bezier
if (isStart) {
tied.setDefaultX(
toTenths(slur.getCurve().getX1() - noteLeft));
tied.setDefaultY(yOf(slur.getCurve().getY1(), staff));
tied.setBezierX(
toTenths(slur.getCurve().getCtrlX1() - noteLeft));
tied.setBezierY(yOf(slur.getCurve().getCtrlY1(), staff));
} else {
tied.setDefaultX(
toTenths(slur.getCurve().getX2() - noteLeft));
tied.setDefaultY(yOf(slur.getCurve().getY2(), staff));
tied.setBezierX(
toTenths(slur.getCurve().getCtrlX2() - noteLeft));
tied.setBezierY(yOf(slur.getCurve().getCtrlY2(), staff));
}
getNotations().getTiedOrSlurOrTuplet().add(tied);
} else {
// Slur element
com.audiveris.proxymusic.Slur pmSlur = factory.createSlur();
// Number attribute
Integer num = slurNumbers.get(slur);
if (num != null) {
pmSlur.setNumber(num);
slurNumbers.remove(slur);
logger.debug("{} last use {} -> {}",
current.note.getContextString(),
num, slurNumbers.toString());
} else {
// Determine first available number
for (num = 1; num <= 6; num++) {
if (!slurNumbers.containsValue(num)) {
if (slur.getRightExtension() != null) {
slurNumbers.put(slur.getRightExtension(), num);
} else {
slurNumbers.put(slur, num);
}
pmSlur.setNumber(num);
logger.debug("{} first use {} -> {}",
current.note.getContextString(),
num, slurNumbers.toString());
break;
}
}
}
// Type
pmSlur.
setType(
isStart ? StartStopContinue.START : StartStopContinue.STOP);
// Placement
if (isStart) {
pmSlur.
setPlacement(
slur.isBelow() ? AboveBelow.BELOW : AboveBelow.ABOVE);
}
// Bezier
if (isStart) {
pmSlur.setDefaultX(
toTenths(slur.getCurve().getX1() - noteLeft));
pmSlur.setDefaultY(yOf(slur.getCurve().getY1(), staff));
pmSlur.setBezierX(
toTenths(slur.getCurve().getCtrlX1() - noteLeft));
pmSlur.setBezierY(yOf(slur.getCurve().getCtrlY1(), staff));
} else {
pmSlur.setDefaultX(
toTenths(slur.getCurve().getX2() - noteLeft));
pmSlur.setDefaultY(yOf(slur.getCurve().getY2(), staff));
pmSlur.setBezierX(
toTenths(slur.getCurve().getCtrlX2() - noteLeft));
pmSlur.setBezierY(yOf(slur.getCurve().getCtrlY2(), staff));
}
getNotations().getTiedOrSlurOrTuplet().add(pmSlur);
}
} catch (Exception ex) {
logger.warn("Error visiting " + slur, ex);
}
return true;
}
//------------------//
// visit SystemPart //
//------------------//
@Override
public boolean visit (SystemPart systemPart)
{
try {
logger.debug("Visiting {}", systemPart);
// Delegate to texts
for (TreeNode node : systemPart.getTexts()) {
((Text) node).accept(this);
}
// Delegate to measures
for (TreeNode node : systemPart.getMeasures()) {
((Measure) node).accept(this);
}
} catch (Exception ex) {
logger.warn("Error visiting " + systemPart, ex);
}
return false; // No default browsing this way
}
//------------//
// visit Text //
//------------//
@Override
public boolean visit (Text text)
{
try {
logger.debug("Visiting {}", text);
switch (text.getSentence().getRole().role) {
case Title:
getWork().setWorkTitle(text.getContent());
break;
case Number:
getWork().setWorkNumber(text.getContent());
break;
case Rights: {
TypedText typedText = factory.createTypedText();
typedText.setValue(text.getContent());
scorePartwise.getIdentification().getRights().add(typedText);
}
break;
case Creator: {
TypedText typedText = factory.createTypedText();
typedText.setValue(text.getContent());
CreatorType type = text.getSentence().getRole().creatorType;
if (type != null) {
typedText.setType(type.toString());
}
scorePartwise.getIdentification().getCreator().add(typedText);
}
break;
case UnknownRole:
break;
default: // LyricsItem, Direction, Chord
// Handle them through related Note
return false;
}
// Credits
Credit pmCredit = factory.createCredit();
// For MusicXML, page # is counted from 1, whatever the pageIndex
pmCredit.setPage(
new BigInteger("" + (1 + current.page.getChildIndex())));
FormattedText creditWords = factory.createFormattedText();
creditWords.setValue(text.getContent());
// Font information
setFontInfo(creditWords, text);
// Position is wrt page
Point pt = text.getReferencePoint();
creditWords.setDefaultX(toTenths(pt.x));
creditWords.setDefaultY(
toTenths(current.page.getDimension().height - pt.y));
pmCredit.getCreditTypeOrLinkOrBookmark().add(creditWords);
scorePartwise.getCredit().add(pmCredit);
} catch (Exception ex) {
logger.warn("Error visiting " + text, ex);
}
return true;
}
//---------------------//
// visit TimeSignature //
//---------------------//
@Override
public boolean visit (TimeSignature timeSignature)
{
try {
logger.debug("Visiting {}", timeSignature);
try {
Time time = factory.createTime();
// Beats
time.getTimeSignature().add(
factory.createTimeBeats(
"" + timeSignature.getNumerator()));
// BeatType
time.getTimeSignature().add(
factory.createTimeBeatType(
"" + timeSignature.getDenominator()));
// Symbol ?
if (timeSignature.getShape() != null) {
switch (timeSignature.getShape()) {
case COMMON_TIME:
time.setSymbol(TimeSymbol.COMMON);
break;
case CUT_TIME:
time.setSymbol(TimeSymbol.CUT);
break;
}
}
// Trick: add this time signature only if it does not already exist
List<Time> times = getAttributes().getTime();
for (Time t : times) {
if (areEqual(t, time)) {
return true; // Already inserted, so give up
}
}
times.add(time);
} catch (InvalidTimeSignature ex) {
}
} catch (Exception ex) {
logger.warn("Error visiting " + timeSignature, ex);
}
return true;
}
//--------------//
// visit Tuplet //
//--------------//
@Override
public boolean visit (Tuplet tuplet)
{
try {
logger.debug("Visiting {}", tuplet);
com.audiveris.proxymusic.Tuplet pmTuplet = factory.createTuplet();
// Brackets
if (constants.avoidTupletBrackets.isSet()) {
pmTuplet.setBracket(YesNo.NO);
}
// Placement
if (tuplet.getChord() == current.note.getChord()) { // i.e. start
pmTuplet.setPlacement(
(tuplet.getCenter().y <= current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
}
// Type
pmTuplet.setType(
(tuplet.getChord() == current.note.getChord())
? StartStop.START : StartStop.STOP);
// Number
Integer num = tupletNumbers.get(tuplet);
if (num != null) {
pmTuplet.setNumber(num);
tupletNumbers.remove(tuplet); // Release the number
} else {
// Determine first available number
for (num = 1; num <= 6; num++) {
if (!tupletNumbers.containsValue(num)) {
tupletNumbers.put(tuplet, num);
pmTuplet.setNumber(num);
break;
}
}
}
getNotations().getTiedOrSlurOrTuplet().add(pmTuplet);
} catch (Exception ex) {
logger.warn("Error visiting " + tuplet, ex);
}
return false;
}
//-------------//
// visit Wedge //
//-------------//
@Override
public boolean visit (Wedge wedge)
{
try {
logger.debug("Visiting {}", wedge);
Direction direction = factory.createDirection();
DirectionType directionType = factory.createDirectionType();
com.audiveris.proxymusic.Wedge pmWedge = factory.createWedge();
// Spread
pmWedge.setSpread(toTenths(wedge.getSpread()));
// Staff ?
Staff staff = current.note.getStaff();
insertStaffId(direction, staff);
// Start or stop ?
if (wedge.isStart()) {
// Type
pmWedge.
setType(
(wedge.getShape() == Shape.CRESCENDO) ? WedgeType.CRESCENDO
: WedgeType.DIMINUENDO);
// Placement
direction.
setPlacement(
(wedge.getReferencePoint().y < current.note.getCenter().y)
? AboveBelow.ABOVE : AboveBelow.BELOW);
// default-y
pmWedge.setDefaultY(yOf(wedge.getReferencePoint(), staff));
} else { // It's a stop
pmWedge.setType(WedgeType.STOP);
}
// // Relative-x (No offset for the time being) using note left side
// pmWedge.setRelativeX(
// toTenths(wedge.getReferencePoint().x - current.note.getCenterLeft().x));
// // default-x
// pmWedge.setDefaultX(
// toTenths(wedge.getReferencePoint().x - current.measure.getLeftX()));
// Everything is OK
directionType.setWedge(pmWedge);
direction.getDirectionType().add(directionType);
current.pmMeasure.getNoteOrBackupOrForward().add(direction);
} catch (Exception ex) {
logger.warn("Error visiting " + wedge, ex);
}
return true;
}
//- Utilities --------------------------------------------------------------
//
//----------//
// toTenths //
//----------//
/**
* Convert a distance expressed in pixels to a string value
* expressed in tenths of interline.
*
* @param dist the distance in pixels
* @return the number of tenths as a string
*/
private BigDecimal toTenths (double dist)
{
return new BigDecimal(
"" + (int) Math.
rint((10f * dist) / current.scale.getInterline()));
}
//-------------//
// setFontInfo //
//-------------//
private void setFontInfo (FormattedText formattedText,
Text text)
{
FontInfo fontInfo = text.getSentence().getFirstWord().getFontInfo();
formattedText.setFontSize("" + text.getExportedFontSize());
// Family
if (fontInfo.isSerif) {
formattedText.setFontFamily("serif");
} else if (fontInfo.isMonospace) {
formattedText.setFontFamily("monospace");
} else {
formattedText.setFontFamily("sans-serif");
}
// Italic?
if (fontInfo.isItalic) {
formattedText.setFontStyle(FontStyle.ITALIC);
}
// Bold?
if (fontInfo.isBold) {
formattedText.setFontWeight(FontWeight.BOLD);
}
}
//-----//
// yOf //
//-----//
/**
* Report the musicXML staff-based Y value of a Point ordinate.
*
* @param ordinate the ordinate (page-based, in pixels)
* @param staff the related staff
* @return the upward-oriented ordinate wrt staff top line (in tenths)
*/
private BigDecimal yOf (double ordinate,
Staff staff)
{
return toTenths(staff.getTopLeft().y - ordinate);
}
//-----//
// yOf //
//-----//
/**
* Report the musicXML staff-based Y value of a Point.
* This method is safer than the other one which simply accepts a (detyped)
* double ordinate.
*
* @param point the pixel point
* @param staff the related staff
* @return the upward-oriented ordinate wrt staff top line (in tenths)
*/
private BigDecimal yOf (Point point,
Staff staff)
{
return yOf(point.y, staff);
}
//----------//
// areEqual //
//----------//
private static boolean areEqual (Time left,
Time right)
{
return (getNum(left).equals(getNum(right)))
&& (getDen(left).equals(getDen(right)));
}
//----------//
// areEqual //
//----------//
private static boolean areEqual (Key left,
Key right)
{
return left.getFifths().equals(right.getFifths());
}
//------------------//
// getArticulations //
//------------------//
/**
* Report (after creating it if necessary) the articulations
* elements in the notations element of the current note.
*
* @return the note notations articulations element
*/
private Articulations getArticulations ()
{
for (Object obj : getNotations().getTiedOrSlurOrTuplet()) {
if (obj instanceof Articulations) {
return (Articulations) obj;
}
}
// Need to allocate articulations
Articulations articulations = factory.createArticulations();
getNotations().getTiedOrSlurOrTuplet().add(articulations);
return articulations;
}
//--------//
// getDen // A VERIFIER A VERIFIER A VERIFIER A VERIFIER A VERIFIER
//--------//
private static java.lang.String getDen (Time time)
{
for (JAXBElement<java.lang.String> elem : time.getTimeSignature()) {
if (elem.getName().getLocalPart().equals("beat-type")) {
return elem.getValue();
}
}
logger.error("No denominator found in {}", time);
return "";
}
//--------------//
// getNotations //
//--------------//
/**
* Report (after creating it if necessary) the notations element
* of the current note.
*
* @return the note notations element
*/
private Notations getNotations ()
{
// Notations allocated?
if (current.pmNotations == null) {
current.pmNotations = factory.createNotations();
current.pmNote.getNotations().add(current.pmNotations);
}
return current.pmNotations;
}
//--------//
// getNum // A VERIFIER A VERIFIER A VERIFIER A VERIFIER A VERIFIER
//--------//
private static java.lang.String getNum (Time time)
{
for (JAXBElement<java.lang.String> elem : time.getTimeSignature()) {
if (elem.getName().getLocalPart().equals("beats")) {
return elem.getValue();
}
}
logger.error("No numerator found in {}", time);
return "";
}
//-----------//
// buildClef //
//-----------//
private com.audiveris.proxymusic.Clef buildClef (Clef clef)
{
com.audiveris.proxymusic.Clef pmClef = factory.createClef();
// Staff number (only for multi-staff parts)
if (current.scorePart.isMultiStaff()) {
pmClef.setNumber(new BigInteger("" + (clef.getStaff().getId())));
}
// Line (General computation that could be overridden by more
// specific shape test below)
pmClef.setLine(
new BigInteger(
"" + (3 - (int) Math.rint(clef.getPitchPosition() / 2.0))));
Shape shape = clef.getShape();
switch (shape) {
case G_CLEF:
case G_CLEF_SMALL:
pmClef.setSign(ClefSign.G);
break;
case G_CLEF_8VA:
pmClef.setSign(ClefSign.G);
pmClef.setClefOctaveChange(new BigInteger("1"));
break;
case G_CLEF_8VB:
pmClef.setSign(ClefSign.G);
pmClef.setClefOctaveChange(new BigInteger("-1"));
break;
case C_CLEF:
pmClef.setSign(ClefSign.C);
break;
case F_CLEF:
case F_CLEF_SMALL:
pmClef.setSign(ClefSign.F);
break;
case F_CLEF_8VA:
pmClef.setSign(ClefSign.F);
pmClef.setClefOctaveChange(new BigInteger("1"));
break;
case F_CLEF_8VB:
pmClef.setSign(ClefSign.F);
pmClef.setClefOctaveChange(new BigInteger("-1"));
break;
case PERCUSSION_CLEF:
pmClef.setSign(ClefSign.PERCUSSION);
break;
default:
logger.error("Clef shape not exported {}", shape);
}
return pmClef;
}
//---------------//
// getAttributes //
//---------------//
/**
* Report (after creating it if necessary) the measure attributes
* element.
*
* @return the measure attributes element
*/
private Attributes getAttributes ()
{
if (current.pmAttributes == null) {
current.pmAttributes = new Attributes();
current.pmMeasure.getNoteOrBackupOrForward().add(current.pmAttributes);
}
return current.pmAttributes;
}
//--------------//
// getOrnaments //
//--------------//
/**
* Report (after creating it if necessary) the ornaments elements
* in the notations element of the current note.
*
* @return the note notations ornaments element
*/
private Ornaments getOrnaments ()
{
for (Object obj : getNotations().getTiedOrSlurOrTuplet()) {
if (obj instanceof Ornaments) {
return (Ornaments) obj;
}
}
// Need to allocate ornaments
Ornaments ornaments = factory.createOrnaments();
getNotations().getTiedOrSlurOrTuplet().add(ornaments);
return ornaments;
}
//--------------------//
// buildScorePartwise //
//--------------------//
/**
* Fill a ScorePartwise with the Score information.
*
* @return the filled document
*/
private ScorePartwise buildScorePartwise ()
{
// Let visited nodes fill the scorePartwise proxy
score.accept(this);
return scorePartwise;
}
//--------------//
// getScorePart //
//--------------//
/**
* Generate the proxymusic ScorePart instance that relates to the
* Audiveris provided ScorePart.
*
* @param scorePart provided ScorePart
* @return the newly built proxymusic ScorePart instance
*/
private com.audiveris.proxymusic.ScorePart getScorePart (ScorePart scorePart)
{
current.scorePart = scorePart;
///logger.info("Processing " + scorePart);
// Scorepart in partList
com.audiveris.proxymusic.ScorePart pmScorePart = factory.createScorePart();
pmScorePart.setId(scorePart.getPid());
PartName partName = factory.createPartName();
pmScorePart.setPartName(partName);
partName.setValue(
(scorePart.getName() != null) ? scorePart.getName()
: scorePart.getDefaultName());
// Score instrument
Integer midiProgram = scorePart.getMidiProgram();
if (midiProgram == null) {
midiProgram = scorePart.getDefaultProgram();
}
ScoreInstrument scoreInstrument = new ScoreInstrument();
pmScorePart.getScoreInstrument().add(scoreInstrument);
scoreInstrument.setId(pmScorePart.getId() + "-I1");
scoreInstrument.setInstrumentName(
MidiAbstractions.getProgramName(midiProgram));
// Midi instrument
MidiInstrument midiInstrument = factory.createMidiInstrument();
pmScorePart.getMidiDeviceAndMidiInstrument().add(midiInstrument);
midiInstrument.setId(scoreInstrument);
midiInstrument.setMidiChannel(scorePart.getId());
midiInstrument.setMidiProgram(midiProgram);
midiInstrument.setVolume(new BigDecimal(score.getVolume()));
// ScorePart in scorePartwise
current.pmPart = factory.createScorePartwisePart();
scorePartwise.getPart().add(current.pmPart);
current.pmPart.setId(pmScorePart);
// Delegate to children the filling of measures
logger.debug("Populating {}", current.scorePart);
isFirst.system = true;
slurNumbers.clear(); // Reset slur numbers
// Browse the whole score hierarchy for this score scorePart
score.acceptChildren(this);
return pmScorePart;
}
//---------//
// getWork //
//---------//
private Work getWork ()
{
if (current.pmWork == null) {
current.pmWork = factory.createWork();
scorePartwise.setWork(current.pmWork);
}
return current.pmWork;
}
//--------------//
// insertBackup //
//--------------//
private void insertBackup (Rational delta)
{
try {
Backup backup = factory.createBackup();
backup.setDuration(new BigDecimal(score.simpleDurationOf(delta)));
current.pmMeasure.getNoteOrBackupOrForward().add(backup);
} catch (Exception ex) {
if (score.getDurationDivisor() != null) {
logger.warn("Not able to insert backup", ex);
}
}
}
//----------------------//
// insertCurrentContext //
//----------------------//
private void insertCurrentContext (Measure measure)
{
// Browse measure, staff per staff
SystemPart part = measure.getPart();
for (TreeNode sn : part.getStaves()) {
Staff staff = (Staff) sn;
int right = measure.getLeftX(); // Right of dummy = Left of current
int midY = (staff.getTopLeft().y + (staff.getHeight() / 2))
- measure.getSystem().getTopLeft().y;
Point staffPoint = new Point(right, midY);
// Clef?
Clef clef = measure.getClefBefore(staffPoint, staff);
if (clef != null) {
clef.accept(this);
}
// Key?
KeySignature key = measure.getKeyBefore(staffPoint, staff);
if (key != null) {
key.accept(this);
}
// Time?
TimeSignature time = measure.getCurrentTimeSignature();
if (time != null) {
time.accept(this);
}
}
}
//---------------//
// insertForward //
//---------------//
private void insertForward (Rational delta,
Chord chord)
{
try {
Forward forward = factory.createForward();
forward.setDuration(new BigDecimal(score.simpleDurationOf(delta)));
forward.setVoice("" + current.voice.getId());
current.pmMeasure.getNoteOrBackupOrForward().add(forward);
// Staff ? (only if more than one staff in scorePart)
insertStaffId(forward, chord.getStaff());
} catch (Exception ex) {
if (score.getDurationDivisor() != null) {
logger.warn("Not able to insert forward", ex);
}
}
}
//---------------//
// insertStaffId //
//---------------//
/**
* If needed (if current scorePart contains more than one staff),
* we insert the id of the staff related to the element at hand.
*
* @param obj the element at hand
* @staff the related score staff
*/
@SuppressWarnings("unchecked")
private void insertStaffId (Object obj,
Staff staff)
{
if (current.scorePart.isMultiStaff()) {
Class<?> classe = obj.getClass();
try {
Method method = classe.getMethod("setStaff", BigInteger.class);
method.invoke(obj, new BigInteger("" + staff.getId()));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Could not setStaff for element {}", classe);
}
}
}
//- Utility Methods --------------------------------------------------------
//-----------//
// isDesired //
//-----------//
/**
* Check whether the provided measure is to be exported
*
* @param measure the measure to check
* @return true is desired
*/
private boolean isDesired (Measure measure)
{
return (measureRange == null) || // No range : take all of them
(measure.isTemporary()) || // A temporary measure for export
measureRange.contains(measure.getPageId()); // Part of the range
}
//-----------//
// isNewClef //
//-----------//
/**
* Make sure we have a NEW clef, not already assigned.
* We have to go back (on the same staff) in current measure, then in
* previous measures, then in same staff in previous systems, until we find
* a previous clef.
* And we compare the two shapes.
*
* @param clef the potentially new clef
* @return true if this clef is really new
*/
private boolean isNewClef (Clef clef)
{
if (current.measure.isDummy()) {
return true;
}
// Perhaps another clef before this one ?
Clef previousClef = current.measure.getClefBefore(
new Point(clef.getCenter().x - 1, clef.getCenter().y),
clef.getStaff());
if (previousClef != null) {
return previousClef.getShape() != clef.getShape();
}
return true; // Since no previous clef found
}
//-------------------//
// isNewKeySignature //
//-------------------//
/**
* Make sure we have a NEW key, not already assigned.
* We have to go back in current measure, then in current staff, then in
* same staff in previous systems, until we find a previous key.
* And we compare the two shapes.
*
* @param key the potentially new key
* @return true if this key is really new
*/
private boolean isNewKeySignature (KeySignature key)
{
if (current.measure.isDummy()) {
return true;
}
// Perhaps another key before this one ?
KeySignature previousKey = current.measure.getKeyBefore(
key.getCenter(),
key.getStaff());
if (previousKey != null) {
return !previousKey.getKey().equals(key.getKey());
}
return true; // Since no previous key found
}
//~ Inner Classes ----------------------------------------------------------
//
//---------//
// Current //
//---------//
/** Keep references of all current entities. */
private static class Current
{
//~ Instance fields ----------------------------------------------------
// Score dependent
com.audiveris.proxymusic.Work pmWork;
// Part dependent
ScorePart scorePart;
com.audiveris.proxymusic.ScorePartwise.Part pmPart;
// Page dependent
Page page;
int pageMeasureIdOffset = 0;
Scale scale;
// System dependent
ScoreSystem system;
// Measure dependent
Measure measure;
com.audiveris.proxymusic.ScorePartwise.Part.Measure pmMeasure;
Voice voice;
// Note dependent
omr.score.entity.Note note;
com.audiveris.proxymusic.Note pmNote;
com.audiveris.proxymusic.Notations pmNotations;
com.audiveris.proxymusic.Attributes pmAttributes;
//~ Methods ------------------------------------------------------------
// Cleanup at end of measure
void endMeasure ()
{
measure = null;
pmMeasure = null;
voice = null;
endNote();
}
// Cleanup at end of note
void endNote ()
{
note = null;
pmNote = null;
pmNotations = null;
pmAttributes = null;
}
}
//---------//
// IsFirst //
//---------//
/** Composite flag to help drive processing of any entity. */
private static class IsFirst
{
//~ Instance fields ----------------------------------------------------
/** We are writing the first score part of the score */
boolean scorePart;
/** We are writing the first page of the score */
Boolean page;
/** We are writing the first system in the current page */
boolean system;
/** We are writing the first measure in current system (in current
* scorePart) */
boolean measure;
//~ Methods ------------------------------------------------------------
@Override
public java.lang.String toString ()
{
StringBuilder sb = new StringBuilder();
if (scorePart) {
sb.append(" firstScorePart");
}
if (page == null) {
sb.append(" noPage");
} else if (page) {
sb.append(" firstPage");
}
if (system) {
sb.append(" firstSystem");
}
if (measure) {
sb.append(" firstMeasure");
}
return sb.toString();
}
}
//---------------//
// ClefIterators //
//---------------//
/**
* Class to handle the insertion of clefs in a measure.
* If needed, this class could be reused for some attribute other than clef,
* such as key signature or time signature (if these attributes can indeed
* occur in the middle of a mesure. To be checked).
*/
private class ClefIterators
{
//~ Instance fields ----------------------------------------------------
/** Containing measure */
private final Measure measure;
/** Staves of the containing part */
private final List<TreeNode> staves;
/** Per staff, iterator on Clefs sorted by abscissa */
private final Map<Staff, ListIterator<Clef>> iters;
//~ Constructors -------------------------------------------------------
public ClefIterators (Measure measure)
{
this.measure = measure;
staves = measure.getPart().getStaves();
Map<Staff, List<Clef>> map = new HashMap<>();
for (TreeNode tn : measure.getClefList().getChildren()) {
Clef clef = (Clef) tn;
Staff staff = clef.getStaff();
List<Clef> list = map.get(staff);
if (list == null) {
map.put(staff, list = new ArrayList<>());
}
list.add(clef);
}
iters = new HashMap<>();
for (Entry<Staff, List<Clef>> entry : map.entrySet()) {
List<Clef> list = entry.getValue();
Collections.sort(
list,
new Comparator<Clef>()
{
@Override
public int compare (Clef o1,
Clef o2)
{
return Integer.signum(
o1.getCenter().x - o2.getCenter().x);
}
});
iters.put(entry.getKey(), list.listIterator());
}
}
//~ Methods ------------------------------------------------------------
/**
* Push as far as possible the relevant clefs iterators,
* according to the current abscissa.
*
* @param abscissa the abscissa of chord to be exported, if any
* @param specificStaff a specific staff, or null for all staves
*/
public void push (Integer abscissa,
Staff specificStaff)
{
if (abscissa != null) {
for (TreeNode node : staves) {
Staff staff = (Staff) node;
if ((specificStaff == null) || (staff == specificStaff)) {
final ListIterator<Clef> it = iters.get(staff);
// Check pending clef WRT current abscissa
if ((it != null) && it.hasNext()) {
final Clef clef = it.next();
if (measure.isDummy()
|| measure.isTemporary()
|| (clef.getCenter().x <= abscissa)) {
// Consume this clef
clef.accept(ScoreExporter.this);
} else {
// Reset iterator
it.previous();
}
}
}
}
} else {
// Flush all iterators
for (ListIterator<Clef> it : iters.values()) {
while (it.hasNext()) {
it.next().accept(ScoreExporter.this);
}
}
}
}
}
//--------------//
// MeasurePrint //
//--------------//
/**
* Handles the print element for a measure.
*/
private class MeasurePrint
{
private final Measure measure;
private final com.audiveris.proxymusic.Print pmPrint;
/** Needed to remove the element if not actually used. */
private boolean used = false;
public MeasurePrint (Measure measure)
{
this.measure = measure;
// Allocate and insert Print immediately
pmPrint = factory.createPrint();
current.pmMeasure.getNoteOrBackupOrForward().add(pmPrint);
}
private com.audiveris.proxymusic.Print getPrint ()
{
used = true;
return pmPrint;
}
public void process ()
{
populatePrint();
// Something to print actually?
if (!used) {
current.pmMeasure.getNoteOrBackupOrForward().remove(pmPrint);
}
}
private void populatePrint ()
{
// New system?
if (isFirst.measure) {
if (!isFirst.system) {
getPrint().setNewSystem(YesNo.YES);
}
} else {
getPrint().setNewSystem(YesNo.NO);
}
// New page?
if (!isFirst.page && isFirst.system && isFirst.measure) {
getPrint().setNewPage(YesNo.YES);
}
// SystemLayout?
if (isFirst.measure && !measure.isDummy()) {
SystemLayout systemLayout = factory.createSystemLayout();
// SystemMargins
SystemMargins systemMargins = factory.createSystemMargins();
systemLayout.setSystemMargins(systemMargins);
systemMargins.setLeftMargin(
toTenths(current.system.getTopLeft().x)
.subtract(pageHorizontalMargin));
systemMargins.setRightMargin(
toTenths(
current.page.getDimension().width
- current.system.getTopLeft().x
- current.system.getDimension().width)
.subtract(pageHorizontalMargin));
if (isFirst.system) {
// TopSystemDistance
systemLayout.setTopSystemDistance(
toTenths(current.system.getTopLeft().y)
.subtract(pageVerticalMargin));
} else {
// SystemDistance
ScoreSystem prevSystem = (ScoreSystem) current.system.
getPreviousSibling();
systemLayout.setSystemDistance(
toTenths(
current.system.getTopLeft().y
- prevSystem.getTopLeft().y
- prevSystem.getDimension().height
- prevSystem.getLastPart().getLastStaff().
getHeight()));
}
getPrint().setSystemLayout(systemLayout);
}
// StaffLayout for all staves in this scorePart, except 1st system staff
if (isFirst.measure && !measure.isDummy()) {
for (TreeNode sNode : measure.getPart().getStaves()) {
Staff staff = (Staff) sNode;
if (!isFirst.scorePart || (staff.getId() > 1)) {
try {
StaffLayout staffLayout = factory.createStaffLayout();
staffLayout.setNumber(new BigInteger("" + staff.getId()));
Staff prevStaff = (Staff) staff.getPreviousSibling();
if (prevStaff == null) {
SystemPart prevPart = (SystemPart) measure.
getPart().getPreviousSibling();
if (!prevPart.isDummy()) {
prevStaff = prevPart.getLastStaff();
}
}
if (prevStaff != null) {
staffLayout.setStaffDistance(
toTenths(
staff.getTopLeft().y
- prevStaff.getTopLeft().y
- prevStaff.getHeight()));
getPrint().getStaffLayout().add(staffLayout);
}
} catch (Exception ex) {
logger.warn(
"Error exporting staff layout system#"
+ current.system.getId() + " part#"
+ current.scorePart.getId() + " staff#"
+ staff.getId(),
ex);
}
}
}
}
// Do not print artificial parts
if (isFirst.measure) {
StaffDetails staffDetails = factory.createStaffDetails();
staffDetails.setPrintObject(measure.isDummy() ? YesNo.NO : YesNo.YES);
getAttributes().getStaffDetails().add(staffDetails);
}
// Measure numbering?
if (isFirst.system && isFirst.measure) {
com.audiveris.proxymusic.MeasureNumbering pmNumbering =
factory.createMeasureNumbering();
if (isFirst.scorePart) {
pmNumbering.setValue(MeasureNumberingValue.SYSTEM);
} else {
pmNumbering.setValue(MeasureNumberingValue.NONE);
}
getPrint().setMeasureNumbering(pmNumbering);
}
}
}
//-----------//
// Constants //
//-----------//
private static final class Constants
extends ConstantSet
{
//~ Instance fields ----------------------------------------------------
Constant.Integer pageHorizontalMargin = new Constant.Integer(
"tenths",
80,
"Page horizontal margin");
Constant.Integer pageVerticalMargin = new Constant.Integer(
"tenths",
80,
"Page vertical margin");
Constant.Boolean avoidTupletBrackets = new Constant.Boolean(
false,
"Should we avoid brackets for all tuplets");
}
}