use of com.xenoage.zong.musiclayout.spacing.ColumnSpacing in project Zong by Xenoage.
the class StretchMeasuresTest method createSystemWith1Measure.
/**
* Creates and returns a simple {@link SystemSpacing} with only one
* measure with a clef and two notes, using the given parameters.
* @param leadingWidth width of the leading spacing in mm
* @param offsetBeat0 offset of beat 1/4 in mm
* @param offsetBeat1 offset of beat 3/4 in mm
* @param offsetBeat2 width of the voice spacing in mm
*/
public static SystemSpacing createSystemWith1Measure(float leadingWidth, float offsetBeat0, float offsetBeat1, float offsetBeat2) {
Chord chord1 = chord(Companion.pi(0, 0, 4), Companion.fr(2, 4));
Chord chord2 = chord(Companion.pi(1, 0, 4), Companion.fr(2, 4));
Voice voice = new Voice(alist(chord1, chord2));
List<BeatOffset> beatOffsets = alist(new BeatOffset(Companion.fr(1, 4), offsetBeat0), new BeatOffset(Companion.fr(3, 4), offsetBeat1), new BeatOffset(Companion.fr(5, 4), offsetBeat2));
float is = 1;
List<VoiceSpacing> voiceSpacings = alist(new VoiceSpacing(voice, is, alist(new ChordSpacing(new ChordNotation(chord1), beatOffsets.get(0).getBeat(), beatOffsets.get(0).getOffsetMm()), new ChordSpacing(new ChordNotation(chord2), beatOffsets.get(1).getBeat(), beatOffsets.get(1).getOffsetMm()))));
MeasureSpacing measureSpacing = new MeasureSpacing(atMeasure(0, 0), is, voiceSpacings, empty, LeadingSpacingMock.createGClefSpacing(leadingWidth));
List<MeasureSpacing> measureSpacings = alist(measureSpacing);
ColumnSpacing mcs = new ColumnSpacing(-1, measureSpacings, beatOffsets, alist(new BeatOffset(Companion.fr(0, 4), 0), new BeatOffset(Companion.fr(6, 4), offsetBeat2)));
SystemSpacing system = new SystemSpacing(ilist(mcs), 0, 0, leadingWidth + offsetBeat2, null, 0);
return system;
}
use of com.xenoage.zong.musiclayout.spacing.ColumnSpacing in project Zong by Xenoage.
the class StretchMeasuresTest method computeSystemArrangementTestGrace.
/**
* Checking if the elements are stretched correctly in a simple system
* where there are grace notes. The space between grace notes and their following
* full chord may not be stretched.
*/
@Test
public void computeSystemArrangementTestGrace() {
// create an easy system for testing
float offsetChord1 = 3;
float offsetChord2 = 12;
float offsetMeasureEnd = 16;
float graceDistance = 2;
SystemSpacing system = createSystemWith1MeasureGrace(offsetChord1, offsetChord2, offsetMeasureEnd, graceDistance);
// stretch the system
float newWidth = 28;
testee.compute(system, newWidth);
// compare the result
ColumnSpacing newCol = system.columns.get(0);
float stretch = (newWidth - +newCol.getLeadingWidthMm()) / offsetMeasureEnd;
// beat offsets
assertEquals(offsetChord1 * stretch, newCol.getBeatOffsets().get(0).getOffsetMm(), df);
assertEquals(offsetChord2 * stretch, newCol.getBeatOffsets().get(1).getOffsetMm(), df);
// element spacings
VoiceSpacing newVoice = newCol.measures.get(0).voices.get(0);
assertEquals(offsetChord1 * stretch, newVoice.elements.get(0).xIs, df);
assertEquals(offsetChord2 * stretch - 2 * graceDistance, newVoice.elements.get(1).xIs, df);
assertEquals(offsetChord2 * stretch - 1 * graceDistance, newVoice.elements.get(2).xIs, df);
assertEquals(offsetChord2 * stretch, newVoice.elements.get(3).xIs, df);
}
use of com.xenoage.zong.musiclayout.spacing.ColumnSpacing in project Zong by Xenoage.
the class StretchMeasuresTest method computeTest.
@Test
public void computeTest() {
// create an easy system for testing
float leadingWidth = 4;
float offsetBeat1 = 3;
float offsetBeat2 = 7;
float offsetBeat3 = 12;
SystemSpacing system = createSystemWith1Measure(leadingWidth, offsetBeat1, offsetBeat2, offsetBeat3);
// stretch the system
float newWidth = 20;
testee.compute(system, newWidth);
// compare the result
// since the leading spacing (4 spaces) is not scaled, the
// remaining 12 spaces of the voices width have to be scaled
float stretch = (newWidth - leadingWidth) / offsetBeat3;
ColumnSpacing newCol = system.columns.get(0);
// beat offsets
assertEquals(offsetBeat1 * stretch, newCol.getBeatOffsets().get(0).getOffsetMm(), df);
assertEquals(offsetBeat2 * stretch, newCol.getBeatOffsets().get(1).getOffsetMm(), df);
// element spacings
VoiceSpacing newVoice = newCol.measures.get(0).voices.get(0);
assertEquals(offsetBeat1 * stretch, newVoice.elements.get(0).xIs, df);
assertEquals(offsetBeat2 * stretch, newVoice.elements.get(1).xIs, df);
}
use of com.xenoage.zong.musiclayout.spacing.ColumnSpacing in project Zong by Xenoage.
the class ColumnSpacer method compute.
/**
* Computes a {@link ColumnSpacing} from a measure column.
* @param context the current context, with the current {@link MP} and precomputed
* element {@link Notation}s
* @param createLeading true, if a leading spacing has to be created, otherwise false
* @param notations the precomputed notations of the measure and voice elements
*/
public ColumnSpacing compute(Context context, boolean createLeading, Notations notations) {
context.saveMp();
int measureIndex = context.mp.measure;
Column column = context.score.getColumn(measureIndex);
ColumnHeader columnHeader = context.score.getHeader().getColumnHeader(measureIndex);
// compute the optimal spacings for each voice separately
List<List<VoiceSpacing>> voiceSpacingsByStaff = alist();
for (int iStaff : range(column)) {
List<VoiceSpacing> vss = alist();
Measure measure = column.get(iStaff);
for (Voice voice : measure.getVoices()) {
context.mp = MP.atVoice(iStaff, measureIndex, measure.getVoices().indexOf(voice));
VoiceSpacing vs = singleVoiceSpacer.compute(context, notations);
vss.add(vs);
}
voiceSpacingsByStaff.add(vss);
}
// compute the measure elements (like inner clefs) and accordingly updated voice spacings
ArrayList<List<ElementSpacing>> optimalMeasureElementsSpacingsByStaff = alist();
for (int iStaff : range(column)) {
context.mp = MP.atMeasure(iStaff, measureIndex);
List<ElementSpacing> measureSpacing = measureElementsSpacer.compute(context, createLeading, voiceSpacingsByStaff.get(iStaff), notations);
optimalMeasureElementsSpacingsByStaff.add(measureSpacing);
}
// compute the common beat offsets of this measure column
Fraction measureBeats = context.score.getMeasureBeats(measureIndex);
VoiceSpacingsByStaff voiceSpacings = new VoiceSpacingsByStaff(voiceSpacingsByStaff);
List<BeatOffset> beatOffsets = voicesBeatOffsetter.compute(voiceSpacings.getAll(), measureBeats, context.settings.offsetBeatsMinimal);
// recompute beat offsets with respect to barlines
BarlinesBeatOffsetter.Result offsets = barlinesBeatOffsetter.compute(beatOffsets, columnHeader, context.score.getMaxIS());
beatOffsets = offsets.voiceElementOffsets;
List<BeatOffset> barlineOffsets = offsets.barlineOffsets;
// compute the spacings for the whole column, so that equal beats are aligned
ArrayList<List<ElementSpacing>> alignedMeasureElementsSpacingsByStaff = alist();
for (int iStaff : range(column)) {
Measure measure = column.get(iStaff);
// voice spacings
for (int iVoice : range(measure.getVoices())) alignedVoicesSpacer.compute(voiceSpacings.get(iStaff, iVoice), beatOffsets);
// measure elements, based on the aligned voice spacings
context.mp = atMeasure(iStaff, measureIndex);
alignedMeasureElementsSpacingsByStaff.add(measureElementsSpacer.compute(context, createLeading, voiceSpacings.getStaff(iStaff), notations));
}
// compute spacings for each staff
List<MeasureSpacing> measureSpacings = alist(column.size());
for (int iStaff : range(column)) {
// create leading spacing, if needed
LeadingSpacing leadingSpacing = null;
if (createLeading) {
context.mp = atBeat(iStaff, measureIndex, 0, Fraction.Companion.get_0());
leadingSpacing = leadingSpacer.compute(context, notations);
}
// create measure spacing
float interlineSpace = context.score.getInterlineSpace(iStaff);
measureSpacings.add(new MeasureSpacing(atMeasure(iStaff, measureIndex), interlineSpace, voiceSpacings.getStaff(iStaff), alignedMeasureElementsSpacingsByStaff.get(iStaff), leadingSpacing));
}
context.restoreMp();
return new ColumnSpacing(measureIndex, measureSpacings, beatOffsets, barlineOffsets);
}
use of com.xenoage.zong.musiclayout.spacing.ColumnSpacing in project Zong by Xenoage.
the class StretchMeasures method compute.
@Override
public void compute(SystemSpacing system, float usableWidthMm) {
// compute width of all voice spacings
// (leading spacings are not stretched)
float voicesWidthMm = 0;
float leadingsWidthMm = 0;
for (ColumnSpacing column : system.columns) {
voicesWidthMm += column.getVoicesWidthMm();
leadingsWidthMm += column.getLeadingWidthMm();
}
// compute the stretching factor for the voice spacings
if (voicesWidthMm == 0)
return;
float stretch = (usableWidthMm - leadingsWidthMm) / voicesWidthMm;
// measure columns
for (ColumnSpacing column : system.columns) {
// beat offsets
for (int i : range(column.beatOffsets)) {
BeatOffset bo = column.beatOffsets.get(i);
BeatOffset stretched = bo.withOffsetMm(bo.offsetMm * stretch);
column.beatOffsets.set(i, stretched);
}
for (int i : range(column.barlineOffsets)) {
BeatOffset bo = column.barlineOffsets.get(i);
BeatOffset stretched = bo.withOffsetMm(bo.offsetMm * stretch);
column.barlineOffsets.set(i, stretched);
}
// measures
for (MeasureSpacing measure : column.measures) {
// measure elements
for (ElementSpacing element : measure.elements) {
// stretch the offset
element.xIs *= stretch;
}
// voices
for (VoiceSpacing voice : measure.voices) {
// traverse elements in reverse order, so we can align grace elements correctly
// grace elements are not stretched, but the distance to their following full element
// stays the same
float lastElementOriginalOffsetIs = getLast(column.beatOffsets).offsetMm / voice.interlineSpace;
for (int i : rangeReverse(voice.elements)) {
ElementSpacing element = voice.elements.get(i);
if (element.isGrace()) {
// grace element: keep distance to following element
float oldDistance = lastElementOriginalOffsetIs - element.xIs;
lastElementOriginalOffsetIs = element.xIs;
element.xIs = voice.elements.get(i + 1).xIs - oldDistance;
} else {
// normal element: stretch the offset
lastElementOriginalOffsetIs = element.xIs;
element.xIs *= stretch;
}
}
}
}
}
// full system width
system.widthMm = usableWidthMm;
// columns have been changed
system.onColumnsWidthChange();
}
Aggregations