use of com.xenoage.zong.core.Score in project Zong by Xenoage.
the class MusicXmlFileReader method produce.
@Override
public void produce(final AsyncResult<List<Score>> callback) {
final List<Score> ret = alist();
// open stream
BufferedInputStream bis = new BufferedInputStream(in);
try {
bis.mark();
// file type
FileType fileType = FileTypeReader.getFileType(bis);
bis.reset();
bis.unmark();
// open file
if (fileType == FileType.XMLScorePartwise) {
Score score = new MusicXmlScoreFileInput().read(bis, path);
ret.add(score);
callback.onSuccess(ret);
} else if (fileType == FileType.XMLOpus) {
// opus
if (path == null) {
// no path is given. we can not read the linked files.
callback.onSuccess(ret);
} else {
// read files
final String directory = FileUtils.getDirectoryName(path);
OpusFileInput opusInput = new OpusFileInput();
Opus opus = opusInput.readOpusFile(bis);
new OpusLinkResolver(opus, null, directory).produce(new AsyncResult<Opus>() {
@Override
public void onSuccess(Opus opus) {
try {
List<String> filePaths = scoreFileFilter.filter(opus.getScoreFilenames());
processNextScore(directory, filePaths, scoreFileFilter, ret, callback);
} catch (IOException ex) {
callback.onFailure(ex);
}
}
@Override
public void onFailure(Exception ex) {
callback.onFailure(ex);
}
});
}
} else if (fileType == FileType.Compressed) {
CompressedFileInput zip = new CompressedFileInput(bis);
List<String> filePaths = scoreFileFilter.filter(zip.getScoreFilenames());
for (String filePath : filePaths) {
Score score = zip.loadScore(filePath);
ret.add(score);
}
zip.close();
callback.onSuccess(ret);
} else {
callback.onFailure(new IOException("Unknown file type"));
}
} catch (IOException ex) {
// try to close input stream
bis.close();
// return failure
callback.onFailure(ex);
}
}
use of com.xenoage.zong.core.Score 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.Score in project Zong by Xenoage.
the class ScoreFrameLayouter method computeScoreFrameLayout.
/**
* Creates a {@link ScoreFrameLayout} from the given {@link FrameSpacing}.
*
* @param unclosedElements unclosed elements from the last frame, like slurs
* spanning over more than one frame
*/
public ScoreFrameLayout computeScoreFrameLayout(FrameSpacing frame, int frameIndex, Notations notations, List<ContinuedElement> unclosedElements, Context layouterContext, Map<Beam, BeamSpacing> beamsSpacing) {
layouterContext.saveMp();
Score score = layouterContext.score;
SymbolPool symbols = layouterContext.symbols;
StamperContext context = new StamperContext();
context.layouter = layouterContext;
context.notations = notations;
ScoreHeader header = score.getHeader();
int stavesCount = score.getStavesCount();
StavesList stavesList = score.getStavesList();
ArrayList<StaffStamping> staffStampsPool = alist();
ArrayList<Stamping> otherStampsPool = alist();
// default lyric style
FormattedTextStyle defaultLyricStyle = new FormattedTextStyle(score.getFormat().getLyricFont());
// caches
OpenSlursCache openCurvedLinesCache = new OpenSlursCache();
OpenWedges openWedges = new OpenWedges();
OpenLyricsCache openLyricsCache = new OpenLyricsCache();
LastLyrics lastLyrics = new LastLyrics();
OpenTupletsCache openTupletsCache = new OpenTupletsCache();
OpenVolta openVolta = new OpenVolta();
// add continued elements
for (ContinuedElement ce : unclosedElements) {
if (ce instanceof ContinuedSlur) {
openCurvedLinesCache.add(SlurCache.createContinued((ContinuedSlur) ce));
} else if (ce instanceof ContinuedVolta) {
openVolta.volta = (ContinuedVolta) ce;
} else if (ce instanceof ContinuedWedge) {
openWedges.wedges.add((ContinuedWedge) ce);
}
}
// create staff stampings
StaffStampings staffStampings = staffStamper.createStaffStampings(score, frame);
staffStampings.addAllTo(staffStampsPool);
context.staffStampings = staffStampings;
// go through the systems
for (int iSystem : range(frame.getSystems())) {
context.systemIndex = iSystem;
SystemSpacing system = frame.getSystems().get(iSystem);
List<StaffStamping> systemStaves = staffStampings.getAllOfSystem(iSystem);
StaffStamping systemFirstStaff = getFirst(systemStaves);
// add the part names (first system) or part abbreviations (other systems)
int iStaffInPart = 0;
for (Part part : stavesList.getParts()) {
PartNameStamper.Style style = (frameIndex == 0 && iSystem == 0 ? PartNameStamper.Style.Full : PartNameStamper.Style.Abbreviated);
addNotNull(otherStampsPool, partNameStamper.stamp(part, iStaffInPart, systemStaves, style));
iStaffInPart += part.getStavesCount();
}
// create the brackets at the beginning of the system
for (BracketGroup bracketGroup : stavesList.getBracketGroups()) {
StavesRange r = bracketGroup.getStaves();
otherStampsPool.add(new BracketStamping(systemStaves.get(r.getStart()), systemStaves.get(r.getStop()), system.getMarginLeftMm() - 1.4f, bracketGroup.getStyle()));
}
// create the barlines and measure numbers
otherStampsPool.addAll(barlinesStamper.stamp(system, systemStaves, score));
// fill the staves
for (int iStaff : range(stavesCount)) {
layouterContext.mp = layouterContext.mp.withStaff(iStaff);
context.staffIndex = iStaff;
float xMm = context.getCurrentStaffStamping().positionMm.x;
for (int iMeasure : range(system.columns)) {
int globalMeasureIndex = system.getStartMeasure() + iMeasure;
layouterContext.mp = layouterContext.mp.withMeasure(globalMeasureIndex);
context.measureIndex = globalMeasureIndex;
ColumnSpacing measureColumnSpacing = system.columns.get(iMeasure);
MeasureSpacing measure = measureColumnSpacing.getMeasures().get(iStaff);
// add leading spacing elements, if available
otherStampsPool.addAll(measureStamper.stampLeading(measure, xMm, context));
// add directions
otherStampsPool.addAll(directionStamper.stamp(context));
// add measure elements within this measure
float voicesXMm = xMm + measureColumnSpacing.getLeadingWidthMm();
otherStampsPool.addAll(measureStamper.stampMeasure(measure, voicesXMm, context));
// add voice elements within this measure
otherStampsPool.addAll(voiceStamper.stampVoices(measure, voicesXMm, staffStampings, context, defaultLyricStyle, beamsSpacing, openCurvedLinesCache, openLyricsCache, lastLyrics, openTupletsCache));
xMm += measureColumnSpacing.getWidthMm();
}
}
// create all voltas in this system, including open voltas from the last system
otherStampsPool.addAll(voltaStamper.stampSystem(systemFirstStaff, openVolta, header, defaultLyricStyle));
// create all wedges in this system
otherStampsPool.addAll(wedgeStamper.stampSystem(system, score, staffStampings, openWedges));
}
// create the collected ties and slurs
otherStampsPool.addAll(createTiesAndSlurs(openCurvedLinesCache, staffStampings, frame.getSystems().size()));
// create the open lyric underscore lines
for (Tuple3<StaffTextStamping, NoteheadStamping, Integer> openUnderscore : openLyricsCache.getUnderscores()) {
// TODO: fetch style efficiently
FormattedTextStyle style = defaultLyricStyle;
FormattedTextElement firstElement = openUnderscore.get1().getText().getFirstParagraph().getElements().getFirst();
if (firstElement instanceof FormattedTextString) {
style = ((FormattedTextString) firstElement).getStyle();
}
otherStampsPool.addAll(lyricStamper.createUnderscoreStampings(openUnderscore.get1(), openUnderscore.get2(), style, staffStampings.getAllOfStaff(openUnderscore.get3())));
}
// create tuplet brackets/numbers
for (Tuplet tuplet : openTupletsCache) {
otherStampsPool.add(tupletStamper.createTupletStamping(tuplet, openTupletsCache, symbols));
}
// collect elements that have to be continued on the next frame
ArrayList<ContinuedElement> continuedElements = alist();
for (SlurCache clc : openCurvedLinesCache) {
continuedElements.add(clc.getContinuedCurvedLine());
}
if (openVolta.volta != null)
continuedElements.add(openVolta.volta);
continuedElements.addAll(openWedges.wedges);
layouterContext.restoreMp();
return new ScoreFrameLayout(frame, staffStampsPool, otherStampsPool, continuedElements);
}
use of com.xenoage.zong.core.Score in project Zong by Xenoage.
the class ChordNotator method compute.
public ChordNotation compute(Chord chord, Context context, @MaybeNull Notations notations) {
Score score = context.score;
float interlineSpace = score.getInterlineSpace(context.mp);
FontInfo lyricsFont = score.getFormat().getLyricFont();
MusicContext mc = score.getMusicContext(context.mp, BeforeOrAt, Before);
// grace or normal chord?
boolean grace = chord.isGrace();
ChordWidths chordWidths = (grace ? context.settings.graceChordWidths : context.settings.chordWidths);
ChordSpacings spacings = (grace ? context.settings.spacings.graceChordSpacings : context.settings.spacings.normalChordSpacings);
// use or compute stem direction
StemDirection stemDirection = chord.getStem().getDirection();
if (stemDirection == StemDirection.Default) {
// if stem direction was not computed yet, compute it now
if (notations != null)
stemDirection = notations.getChord(chord).stemDirection;
if (stemDirection == StemDirection.Default) {
Map<Chord, StemDirection> computedStems = stemDirector.compute(chord);
stemDirection = computedStems.get(chord);
// also remember the other computed stems
if (notations != null)
for (Chord computedChord : computedStems.keySet()) notations.getChord(computedChord).stemDirection = computedStems.get(computedChord);
}
}
// notes displacement
NotesNotation notes = notesNotator.compute(chord, stemDirection, chordWidths, mc);
float leftSuspendedWidth = (notes.leftSuspended ? notes.noteheadWidthIs : 0);
// accidentals
AccidentalsNotation accs = accidentalsNotator.compute(chord, notes, chordWidths, mc);
// symbol's width: width of the noteheads and dots
float symbolWidth = notes.widthIs - leftSuspendedWidth;
float frontGap = accs.widthIs + leftSuspendedWidth;
// rear gap: empty duration-dependent space behind the chord minus the symbol's width
float rearGap = spacings.getWidth(chord.getDisplayedDuration()) - symbolWidth;
// lyric width
float lyricWidth = 0;
TextMeasurer textMeasurer = platformUtils().getTextMeasurer();
for (Lyric lyric : chord.getLyrics()) {
if (lyric != null && lyric.getText() != null) {
// width of lyric in interline spaces
FormattedText lyricText = styleText(lyric.getText(), new FormattedTextStyle(lyricsFont));
float l = lyricText.getWidth() / interlineSpace;
// for start and end syllable, request "-" more space, for middle syllables "--"
// TODO: unsymmetric - start needs space on the right, end on the left, ...
SyllableType lyricType = lyric.getSyllableType();
if (lyricType == SyllableType.Begin || lyricType == SyllableType.End) {
l += textMeasurer.measure(lyricsFont, "-").getWidth() / interlineSpace;
} else if (lyricType == SyllableType.Middle) {
l += textMeasurer.measure(lyricsFont, "--").getWidth() / interlineSpace;
}
// save width of the widest lyric
lyricWidth = Math.max(lyricWidth, l);
}
}
// compute length of the stem (if any)
float scaling = grace ? context.settings.scalingGrace : 1;
StemNotation stem = stemNotator.compute(chord.getStem(), notes.getLps(), stemDirection, context.mp.getStaff(), Companion.staffLines(mc.getLinesCount()), scaling);
// compute articulations
ArticulationsNotation arts = articulationsNotator.compute(chord, stemDirection, notes, mc.getLinesCount());
return new ChordNotation(chord, chord.getMP(), new ElementWidth(frontGap, symbolWidth, rearGap, lyricWidth), context.mp.getStaff(), notes, stemDirection, stem, accs, arts);
}
use of com.xenoage.zong.core.Score in project Zong by Xenoage.
the class FileToMidiConvert method execute.
@Override
public void execute() {
FileChooser fileChooser = new FileChooser();
// use last document directory
File initDir = FileSettings.getLastDir();
if (initDir != null)
fileChooser.setInitialDirectory(initDir);
// add filters
SupportedFormats<?> supportedFormats = app().getSupportedFormats();
for (FileFormat<?> fileFormat : supportedFormats.getReadFormats()) {
addFilter(fileChooser, fileFormat);
}
// show the dialog
File file = fileChooser.showOpenDialog(ownerWindow);
if (file != null) {
INSTANCE.log(Companion.remark("Dialog closed (OK), converting file \"" + file.getName() + "\""));
// save document directory
FileSettings.rememberDir(file);
// convert - TODO: show progress
String lastPath = file.getAbsolutePath();
List<Score> scores = pApp().loadMxlScores(lastPath, new AllFilter<>());
boolean useNumber = scores.size() > 1;
It<Score> scoresIt = new It<>(scores);
for (Score score : scoresIt) {
Sequence seq = MidiConverter.convertToSequence(score, optionsForFileExport, new JseMidiSequenceWriter()).getSequence();
String newPath = lastPath;
String number = (useNumber ? ("-" + (scoresIt.getIndex() + 1)) : "");
if (// TIDY: share code: FilenameUtils.numberFiles
newPath.toLowerCase().endsWith(".xml") || newPath.toLowerCase().endsWith(".mxl")) {
newPath = newPath.substring(0, newPath.length() - 4);
}
newPath += (number + ".mid");
try {
MidiSystem.write(seq, 1, new File(newPath));
} catch (Exception ex) {
handle(warning(Voc.ErrorSavingFile));
}
}
} else {
INSTANCE.log(Companion.remark("Dialog closed (Cancel)"));
}
}
Aggregations