use of com.xenoage.zong.core.format.ScoreFormat in project Zong by Xenoage.
the class ScoreDocScoreView method updateScreen.
@Override
public void updateScreen(Size2i screenSizePx, float zoom) {
this.screenSizePx = screenSizePx;
this.zoom = zoom;
// recompute the layout, so that each page fits into the available screen space
Size2f pageSizeMm = pxToMm(screenSizePx, zoom);
float marginMm = pxToMm(marginPx, zoom);
PageFormat pageFormat = new PageFormat(pageSizeMm, new PageMargins(marginMm, marginMm, marginMm, marginMm));
Size2f frameSizeMm = new Size2f(pageFormat.getUseableWidth(), pageFormat.getUseableHeight());
// first page needs space for title text
titleTextHeightPx = screenSizePx.height / 20f;
float firstFrameOffsetY = pxToMm(titleTextHeightPx, zoom);
Size2f firstFrameSizeMm = new Size2f(frameSizeMm.width, frameSizeMm.height - firstFrameOffsetY);
// delete unnecessary layout information, like system distances or system breaks
Score score = doc.getScore();
score.setFormat(new ScoreFormat());
ScoreHeader header = score.getHeader();
for (int i : range(header.getSystemLayouts())) {
SystemLayout sl = header.getSystemLayout(i);
if (sl != null)
sl.setDistance(SystemLayout.defaultDistance);
}
for (int i : range(header.getColumnHeaders())) {
ColumnHeader ch = header.getColumnHeader(i);
if (ch.getMeasureBreak() != null)
ch.setBreak(null);
}
// layout the score to find out the needed space
Context context = new Context(score, App.getSymbolPool(), doc.getLayout().getDefaults().getLayoutSettings());
Target target = new Target(alist(new ScoreLayoutArea(firstFrameSizeMm)), new ScoreLayoutArea(frameSizeMm), true);
ScoreLayouter layouter = new ScoreLayouter(context, target);
ScoreLayout scoreLayout = layouter.createScoreLayout();
// create and fill at least one page
Layout layout = new Layout(doc.getLayout().getDefaults());
ScoreFrameChain chain = null;
for (int i = 0; i < scoreLayout.frames.size(); i++) {
Page page = new Page(pageFormat);
Point2f position;
Size2f size;
if (i == 0) {
// first page
position = new Point2f(pageSizeMm.width / 2, pageSizeMm.height / 2 + firstFrameOffsetY);
size = firstFrameSizeMm;
} else {
// other pages
position = new Point2f(pageSizeMm.width / 2, pageSizeMm.height / 2);
size = frameSizeMm;
}
ScoreFrame frame = new ScoreFrame();
frame.setPosition(position);
frame.setSize(size);
page.addFrame(frame);
layout.addPage(page);
if (chain == null) {
chain = new ScoreFrameChain(score);
chain.setScoreLayout(scoreLayout);
}
chain.add(frame);
}
this.layout = layout;
}
use of com.xenoage.zong.core.format.ScoreFormat in project Zong by Xenoage.
the class MusicXmlScoreFileInput method read.
/**
* Builds a {@link Score} entity from a {@link MxlScorePartwise} document.
* @param doc the provided score-partwise document
* @param errorHandling how to deal with errors
*/
public Score read(MxlScorePartwise mxlScore, Level errorHandling) throws InvalidFormatException {
try {
// create new score
Score score = new Score();
// read information about the score
ScoreInfo scoreInfo = new ScoreInfoReader(mxlScore.getScoreHeader()).read();
score.setInfo(scoreInfo);
// read score format
MxlScoreHeader mxlScoreHeader = mxlScore.getScoreHeader();
MxlDefaults mxlDefaults = mxlScoreHeader.getDefaults();
ScoreFormat scoreFormat = new ScoreFormatReader(mxlDefaults).read();
score.setFormat(scoreFormat);
// read layout format
MxlLayout mxlLayout = (mxlDefaults != null ? mxlDefaults.getLayout() : null);
LayoutFormat layoutFormat = new LayoutFormatReader(mxlLayout, scoreFormat.getInterlineSpace() / 10).read();
// TIDY
score.setMetaData("layoutformat", layoutFormat);
// create the list of staves
ErrorHandling mxlErrorHandling = new ErrorHandling(errorHandling);
StavesListReader stavesListReader = new StavesListReader(mxlScore, mxlErrorHandling);
StavesList stavesList = stavesListReader.read();
stavesList.setScore(score);
score.setStavesList(stavesList);
// read the musical contents
new ScoreReader(mxlScore).readToScore(score, mxlErrorHandling);
// remember the XML document for further application-dependend processing
// TIDY
score.setMetaData("mxldoc", mxlScore);
// when errors were collected, log them and save them as metadata
if (mxlErrorHandling.getErrorMessages().size() > 0) {
INSTANCE.log(Companion.warning("The file could be loaded, but the following error(s) were reported: " + mxlErrorHandling.getErrorMessages()));
score.setMetaData("mxlerrors", mxlErrorHandling.getErrorMessages());
}
return score;
} catch (RuntimeException ex) {
// catch runtime exceptions and rethrow them in the expected type
throw new InvalidFormatException(ex);
}
}
use of com.xenoage.zong.core.format.ScoreFormat in project Zong by Xenoage.
the class StavesSpacer method compute.
public StavesSpacing compute(Score score, int systemIndex) {
// compute staff distances
ScoreFormat scoreFormat = score.getFormat();
ScoreHeader scoreHeader = score.getHeader();
float[] distancesMm = new float[score.getStavesCount() - 1];
for (int iStaff : range(1, distancesMm.length)) {
StaffLayout staffLayout = scoreHeader.getStaffLayout(systemIndex, iStaff);
float staffDistanceMm = 0;
if (staffLayout != null) {
// use custom staff distance
staffDistanceMm = staffLayout.getDistance();
} else {
// use default staff distance
staffDistanceMm = scoreFormat.getStaffLayoutNotNull(iStaff).getDistance();
}
distancesMm[iStaff - 1] = staffDistanceMm;
}
// create spacing
StavesSpacing stavesSpacing = new StavesSpacing(score.getStavesList().getStaves(), distancesMm, scoreFormat.getInterlineSpace());
return stavesSpacing;
}
use of com.xenoage.zong.core.format.ScoreFormat in project Zong by Xenoage.
the class SystemSpacer method compute.
/**
* Arranges an optimum number of measures columns in a system, beginning at the given measure,
* if possible.
* @param context the context of the layouter, with the {@link MP} set to the start measure
* @param usableSizeMm the usable size within the score frame in mm
* @param offsetYMm the vertical offset of the system in mm
* @param systemIndex the global system index (over all frames)
* @param isFirst true, iff this system is the first one in a score frame
* @param isAdditional true, iff this system is created for an additional frame, which is created
* for a complete score layout, but is not part of the defined layout
* @param measureColumnSpacings a list of all measure column spacings without leading spacings
* @param notations the notations of the elements, needed when a column has to be recomputed
* because of a leading spacing
*/
public Optional<SystemSpacing> compute(Context context, Size2f usableSizeMm, float offsetYMm, int systemIndex, boolean isFirst, boolean isAdditional, List<ColumnSpacing> measureColumnSpacings, Notations notations) {
int startMeasure = context.mp.measure;
// test if there is enough height for the system
Score score = context.score;
ScoreFormat scoreFormat = score.getFormat();
ScoreHeader scoreHeader = score.getHeader();
// compute spacing of staves
StavesSpacing stavesSpacing = stavesSpacer.compute(score, systemIndex);
// enough space?
if (offsetYMm + stavesSpacing.getTotalHeightMm() > usableSizeMm.height) {
// when the system is the first one in an additional frame, we force it into the frame
if (false == (isFirst && isAdditional))
// not enough space
return absent();
}
// compute the usable width for the system
float systemLeftMarginMm = getLeftMarginMm(systemIndex, scoreFormat, scoreHeader);
float systemRightMarginMm = getRightMarginMm(systemIndex, scoreFormat, scoreHeader);
float usableWidthMm = usableSizeMm.width - systemLeftMarginMm - systemRightMarginMm;
// append system measure-by-measure, until there is no space any more
// or until there are no measures left
int measuresCount = score.getMeasuresCount();
List<ColumnSpacing> system = alist();
float usedWidthMm = 0;
int iMeasure;
while (startMeasure + system.size() < measuresCount) {
iMeasure = startMeasure + system.size();
// decide if to add a leading spacing to the current measure or not
boolean firstMeasure = system.size() == 0;
ColumnSpacing column;
if (firstMeasure) {
// first measure within this system: add leading elements (clef, time sig.)
column = columnSpacer.compute(context, true, /* leading! */
notations);
} else {
// otherwise: use the precomputed spacing (without leading spacing)
column = measureColumnSpacings.get(iMeasure);
}
// this system is created for a complete score layout
if (false == canAppend(column, iMeasure, usableWidthMm, usedWidthMm, scoreHeader, firstMeasure)) {
if (system.size() == 0 && isAdditional) {
// force the single measure in this system
usedWidthMm += column.getWidthMm();
system.add(column);
} else {
// no more space for another measure
break;
}
} else {
usedWidthMm += column.getWidthMm();
system.add(column);
}
}
// we are finished
if (system.size() == 0) {
// not enough space for the system on this area
return absent();
} else {
SystemSpacing ret = new SystemSpacing(system, systemLeftMarginMm, systemRightMarginMm, usedWidthMm, stavesSpacing, offsetYMm);
return of(ret);
}
}
use of com.xenoage.zong.core.format.ScoreFormat in project Zong by Xenoage.
the class FrameSpacer method compute.
/**
* Arranges an optimum number of systems in a frame, beginning at the given measure,
* if possible.
* @param context the context of the layouter, with the {@link MP} set to the start measure
* @param startSystem the index of the system where to start
* @param usableSizeMm the usable size within the score frame in mm
* @param isAdditional true, when this frame is created for a complete score layout,
* but is not part of the defined layout
* @param columnSpacings a list of all measure column spacings without leading spacings
* @param notations the notations of the elements, needed when a column has to be recomputed
* because of a leading spacing
*/
public FrameSpacing compute(Context context, int startSystem, Size2f usableSizeMm, boolean isAdditional, List<ColumnSpacing> columnSpacings, Notations notations) {
context.saveMp();
int startMeasure = context.mp.measure;
Score score = context.score;
ScoreFormat scoreFormat = score.getFormat();
ScoreHeader scoreHeader = score.getHeader();
int measuresCount = score.getMeasuresCount();
int measureIndex = startMeasure;
int systemIndex = startSystem;
// top margin
float offsetY = getTopSystemDistance(systemIndex, scoreFormat, scoreHeader);
// append systems to the frame
List<SystemSpacing> systems = alist();
while (measureIndex < measuresCount) {
// try to create system on this frame
context.mp = atMeasure(measureIndex);
boolean isFirst = (systems.size() == 0);
SystemSpacing system = systemSpacer.compute(context, usableSizeMm, offsetY, systemIndex, isFirst, isAdditional, columnSpacings, notations).orNull();
// was there enough place for this system?
if (system != null) {
// yes, there is enough place. add system
systems.add(system);
// update offset and start measure index for next system
// add height of this system
offsetY += system.getHeightMm();
// add system distance of the following system
offsetY += getSystemDistance(systemIndex + 1, scoreFormat, scoreHeader);
// increase indexes
systemIndex++;
measureIndex = system.getEndMeasure() + 1;
} else {
break;
}
}
context.restoreMp();
return new FrameSpacing(systems, usableSizeMm);
}
Aggregations