use of com.xenoage.zong.core.music.chord.Chord in project Zong by Xenoage.
the class ChordStamper method stampCore.
/**
* Draws the given chord, including noteheads, stem, flags, accidentals, dots,
* articulations and leger lines.
*/
public ChordStampings stampCore(ChordNotation chord, float chordXMm, StamperContext context) {
val staff = context.getCurrentStaffStamping();
Chord element = chord.element;
boolean grace = element.isGrace();
LayoutSettings settings = context.getSettings();
float scaling = (grace ? settings.scalingGrace : 1);
ChordWidths chordWidths = (grace ? settings.graceChordWidths : settings.chordWidths);
float leftNoteXMm = getLeftNoteXMm(chordXMm, chord.notes, staff.is);
// stem
StemStamping stem = stampStem(chord, leftNoteXMm, context);
// type of notehead
CommonSymbol noteheadSymbol = CommonSymbol.NoteWhole;
Duration.Type symbolType = Duration.INSTANCE.getNoteheadSymbolType(element.getDisplayedDuration());
if (symbolType == Duration.INSTANCE.Type.Half)
noteheadSymbol = CommonSymbol.NoteHalf;
else if (symbolType == Duration.INSTANCE.Type.Quarter)
noteheadSymbol = CommonSymbol.NoteQuarter;
// noteheads
NotesNotation notes = chord.notes;
NoteheadStamping[] noteheads = new NoteheadStamping[notes.getNotesCount()];
for (int iNote : range(noteheads)) {
NoteDisplacement note = notes.getNote(iNote);
Symbol noteSymbol = context.getSymbol(noteheadSymbol);
float noteXMm = getNoteheadXMm(leftNoteXMm + note.xIs * staff.is, scaling, staff, noteSymbol);
NoteheadStamping noteSt = new NoteheadStamping(chord, iNote, noteSymbol, Color.Companion.getBlack(), staff, sp(noteXMm, note.lp), scaling);
noteheads[iNote] = noteSt;
}
// flags (only drawn if there is no beam)
int flagsCount = Duration.INSTANCE.getFlagsCount(element.getDisplayedDuration());
Beam beam = element.getBeam();
StemDirection stemDir = chord.stemDirection;
FlagsStamping flags = null;
if (beam == null && flagsCount > 0 && chord.stem != null) /* can happen when no stem is used */
{
FlagsStamping.FlagsDirection flag = (stemDir == StemDirection.Up ? FlagsStamping.FlagsDirection.Down : FlagsStamping.FlagsDirection.Up);
Symbol flagSymbol = context.getSymbol(CommonSymbol.NoteFlag);
flags = new FlagsStamping(chord, staff, flag, flagsCount, flagSymbol, scaling, sp(leftNoteXMm + notes.stemOffsetIs * staff.is, chord.stem.endSlp.lp));
}
// accidentals
AccidentalsNotation accs = chord.accidentals;
AccidentalStamping[] accsSt = new AccidentalStamping[0];
if (accs != null) {
accsSt = new AccidentalStamping[accs.accidentals.length];
for (int iAcc : range(accsSt)) {
AccidentalDisplacement acc = accs.accidentals[iAcc];
AccidentalStamping accSt = new AccidentalStamping(chord, iAcc, staff, sp(chordXMm + (acc.xIs - chord.width.frontGap + 0.5f) * staff.is, acc.yLp), 1, context.getSymbol(CommonSymbol.getAccidental(acc.accidental)));
accsSt[iAcc] = accSt;
}
}
// dots
int[] dotPositions = notes.dotsLp;
int dotsPerNote = notes.getDotsPerNoteCount();
ProlongationDotStamping[] dots = new ProlongationDotStamping[dotPositions.length * dotsPerNote];
Symbol dotSymbol = context.getSymbol(CommonSymbol.NoteDot);
for (int iNote : range(dotPositions)) {
for (int iDot : range(dotsPerNote)) {
ProlongationDotStamping dotSt = new ProlongationDotStamping(chord, staff, dotSymbol, sp(leftNoteXMm + notes.getDotsOffsetIs(iDot) * staff.is, dotPositions[iNote]));
dots[iNote * dotsPerNote + iDot] = dotSt;
}
}
// articulations
ArticulationsNotation arts = chord.articulations;
ArticulationStamping[] artsSt = new ArticulationStamping[0];
if (arts != null) {
artsSt = new ArticulationStamping[arts.articulations.length];
float noteheadWidth = chordWidths.get(element.getDuration());
for (int iArt : range(artsSt)) {
ArticulationDisplacement art = arts.articulations[iArt];
ArticulationStamping artSt = new ArticulationStamping(chord, iArt, staff, sp(leftNoteXMm + (art.xIs + (noteheadWidth / 2)) * staff.is, art.yLp), 1, context.getSymbol(CommonSymbol.getArticulation(art.articulation)));
artsSt[iArt] = artSt;
}
}
// leger lines
LegerLineStamping[] legerLines = legerLinesStamper.stamp(chord, chordXMm, staff);
return new ChordStampings(element, chordXMm, staff, noteheads, dots, accsSt, legerLines, artsSt, flags, stem);
}
use of com.xenoage.zong.core.music.chord.Chord in project Zong by Xenoage.
the class DirectionStamper method stampForChord.
/**
* Creates the {@link StaffTextStamping}s for the {@link Direction}s of
* the given {@link ChordStampings}.
*/
public List<StaffTextStamping> stampForChord(ChordStampings chordStampings, SymbolPool symbolPool) {
Chord chord = chordStampings.chord;
int directionsCount = chord.getDirections().size();
if (directionsCount == 0)
return emptyList();
List<StaffTextStamping> ret = alist();
for (Direction direction : chord.getDirections()) {
if (direction instanceof Dynamic) {
ret.add(createDynamics((Dynamic) direction, chord, chordStampings, symbolPool));
}
// TODO: support more directions
}
return ret;
}
use of com.xenoage.zong.core.music.chord.Chord in project Zong by Xenoage.
the class MidiConverter method writeVoice.
/**
* Writes the given voice into the MIDI sequence.
* @param voiceMp the staff, measure and voice index
* @param repetition the index of the current {@link Repetition}
*/
private void writeVoice(MP voiceMp, int repetition) {
val voice = score.getVoice(voiceMp);
for (VoiceElement element : voice.getElements()) {
// ignore rests. only chords are played
if (false == MusicElementType.Chord.is(element))
continue;
val chord = (Chord) element;
// grace chords are not supported yet - TODO: ZONG-104: Play grace chords
if (chord.isGrace())
continue;
// start beat of the element
Fraction duration = chord.getDuration();
val startBeat = voice.getBeat(chord);
val rep = repetitions.get(repetition);
if (false == rep.contains(Companion.time(voiceMp.measure, startBeat)))
// start beat out of range: ignore element
continue;
// MIDI ticks
val startMidiTime = timeMap.getByRepTime(repetition, Companion.time(voiceMp.measure, startBeat));
long startTick = startMidiTime.tick;
long endTick = startTick + durationToTick(duration, resolution);
long stopTick = endTick;
if (false == options.midiSettings.durationFactor.equals(Companion.get_1())) {
// custom duration factor
stopTick = startTick + round((endTick - startTick) * options.midiSettings.durationFactor.toFloat());
}
// play note
if (startTick < stopTick) {
float volume = dynamics.getVolumeAt(voiceMp.withBeat(startBeat), repetition);
int midiVelocity = round(midiMaxValue * volume);
for (Note note : chord.getNotes()) {
addNoteToTrack(note.getPitch(), voiceMp.staff, startTick, stopTick, midiVelocity, 0);
}
}
// TODO Timidity doesn't like the following midi events
/*MetaMessage m = null;
if (musicelement instanceof Clef)
{
Clef c = (Clef) musicelement;
m = createMidiEvent(c, tracknumber);
}
else if (musicelement instanceof NormalTime)
{
NormalTime t = (NormalTime) musicelement;
m = createMidiEvent(t, resolution, tracknumber);
}
else if (musicelement instanceof Key)
{
Key k = (Key) musicelement;
m = createMidiEvent(k, tracknumber);
}
else if (musicelement instanceof Tempo)
{
Tempo tempo = (Tempo)musicelement;
m = MidiTempoConverter.createMetaMessage(tempo);
}
if (m != null)
{
MidiEvent event = new MidiEvent(m, starttick);
track.add(event);
}*-/
currenttickinvoice = endtick;
}*/
}
}
use of com.xenoage.zong.core.music.chord.Chord in project Zong by Xenoage.
the class VoiceStamper method stampVoice.
public List<Stamping> stampVoice(VoiceSpacing voice, float voiceXMm, StaffStampings staffStampings, boolean stampLeadingRests, StamperContext context, // TODO:
FormattedTextStyle defaultLyricStyle, Map<Beam, BeamSpacing> beams, OpenSlursCache openCurvedLinesCache, OpenLyricsCache openLyricsCache, LastLyrics lastLyrics, OpenTupletsCache openTupletsCache) {
List<Stamping> ret = alist();
// create the voice elements
boolean onlyRestsSoFar = true;
for (ElementSpacing spacingElement : voice.elements) {
MusicElement element = spacingElement.getElement();
if (element != null) /* TODO && (stampRests || !(element instanceof Rest)) */
{
Notation notation = context.getNotation(element);
float xMm = voiceXMm + spacingElement.xIs * voice.interlineSpace;
if (element instanceof Chord) {
// chord
onlyRestsSoFar = false;
Chord chord = (Chord) element;
BeamSpacing beam = beams.get(chord.getBeam());
ret.addAll(chordStamper.stampAll((ChordNotation) spacingElement.getNotation(), xMm, beam, staffStampings, context, defaultLyricStyle, openCurvedLinesCache, openLyricsCache, lastLyrics, openTupletsCache));
} else if (spacingElement instanceof RestSpacing) {
// rest
if (false == onlyRestsSoFar || stampLeadingRests) {
// not a leading rest, or a leading rest which should be stamped
ret.add(elementStamper.createRestStamping((RestSpacing) spacingElement, xMm, context));
}
} else {
throw new IllegalArgumentException("Notation not supported: " + notation);
}
}
}
return ret;
}
use of com.xenoage.zong.core.music.chord.Chord in project Zong by Xenoage.
the class VoiceElementWriteTest method createTestScoreEighths.
/**
* Creates a score with a single staff, a single measure,
* two voices with each 8 quarter notes which are beamed.
*/
private Score createTestScoreEighths() {
Score score = ScoreFactory.create1Staff();
new VoiceAdd(score.getMeasure(atMeasure(0, 0)), 1).execute();
for (int iVoice : range(2)) {
Voice voice = score.getVoice(atVoice(0, 0, iVoice));
List<Chord> beamChords = new ArrayList<>();
for (int i = 0; i < 8; i++) {
Chord chord = new Chord(new Note(Companion.pi(0, 0, 4)), Companion.fr(1, 8));
// add elements by hand, since the corresonding command is tested itself in this class
chord.setParent(voice);
voice.getElements().add(chord);
beamChords.add(chord);
}
// create beam
Companion.beamFromChords(beamChords);
}
// ensure that assert method works correctly. if not, fail now
assertTestScoreEighthsOriginalState(score);
return score;
}
Aggregations