package com.xenoage.zong.core; import com.xenoage.utils.kernel.Tuple3; import com.xenoage.zong.commands.core.music.*; import com.xenoage.zong.core.music.*; import com.xenoage.zong.core.music.clef.Clef; import com.xenoage.zong.core.music.clef.ClefType; import com.xenoage.zong.core.music.key.Key; import com.xenoage.zong.core.music.key.TraditionalKey; import com.xenoage.zong.core.music.key.TraditionalKey.Mode; import com.xenoage.zong.core.music.rest.Rest; import com.xenoage.zong.core.music.time.TimeSignature; import com.xenoage.zong.core.music.time.TimeType; import com.xenoage.zong.core.position.MP; import org.junit.Assert; import org.junit.Test; import java.util.List; import java.util.Map; import static com.xenoage.utils.collections.CollectionUtils.alist; import static com.xenoage.utils.kernel.Tuple3.t3; import static com.xenoage.utils.math.Fraction._0; import static com.xenoage.utils.math.Fraction.fr; import static com.xenoage.zong.core.music.Pitch.pi; import static com.xenoage.zong.core.music.chord.ChordFactory.chord; import static com.xenoage.zong.core.music.util.Interval.Before; import static com.xenoage.zong.core.music.util.Interval.BeforeOrAt; import static com.xenoage.zong.core.position.MP.*; import static org.junit.Assert.*; /** * Tests for {@link Score}. * * @author Andreas Wenger */ public class ScoreTest { @Test public void getMeasureBeatsTest() { Score score = ScoreFactory.create1Staff4Measures(); //first measure: no time, 1/4 used score.getVoice(atVoice(0, 0, 0)).addElement(new Rest(fr(1, 4))); //second measure: 3/4 time, 2/4 used score.getColumnHeader(1).setTime(new TimeSignature(TimeType.time_3_4)); score.getVoice(atVoice(0, 1, 0)).addElement(new Rest(fr(1, 4))); score.getVoice(atVoice(0, 1, 0)).addElement(new Rest(fr(1, 4))); //third measure: still 3/4 time, 1/4 used score.getVoice(atVoice(0, 2, 0)).addElement(new Rest(fr(1, 4))); //check assertEquals(fr(1, 4), score.getMeasureBeats(0)); assertEquals(fr(3, 4), score.getMeasureBeats(1)); assertEquals(fr(3, 4), score.getMeasureBeats(2)); } @Test public void getMeasureFilledBeatsTest() { //create a little test score, where the first measure only //uses 2/4, the second 4/4, the third 0/4, the fourth 3/4. Score score = ScoreFactory.create1Staff4Measures(); score.getVoice(atVoice(0, 0, 0)).addElement(new Rest(fr(1, 4))); score.getVoice(atVoice(0, 0, 0)).addElement(new Rest(fr(1, 4))); score.getVoice(atVoice(0, 1, 0)).addElement(new Rest(fr(2, 4))); score.getVoice(atVoice(0, 1, 0)).addElement(new Rest(fr(2, 4))); score.getVoice(atVoice(0, 3, 0)).addElement(new Rest(fr(3, 4))); //test method assertEquals(fr(2, 4), score.getMeasureFilledBeats(0)); assertEquals(fr(4, 4), score.getMeasureFilledBeats(1)); assertEquals(fr(0, 4), score.getMeasureFilledBeats(2)); assertEquals(fr(3, 4), score.getMeasureFilledBeats(3)); } @Test public void getKeyTest() { Tuple3<Score, List<ClefType>, List<Key>> testData = createTestScoreClefsKeys(); Score score = testData.get1(); List<Key> keys = testData.get3(); assertTrue(keys.get(0) != score.getKey(atBeat(0, 0, 0, fr(0, 4)), Before).element); assertTrue(keys.get(0) == score.getKey(atBeat(0, 0, 0, fr(0, 4)), BeforeOrAt).element); assertTrue(keys.get(0) == score.getKey(atBeat(0, 0, 0, fr(1, 4)), Before).element); assertTrue(keys.get(0) == score.getKey(atBeat(0, 0, 0, fr(1, 4)), BeforeOrAt).element); assertTrue(keys.get(0) == score.getKey(atBeat(0, 0, 0, fr(2, 4)), Before).element); assertTrue(keys.get(1) == score.getKey(atBeat(0, 0, 0, fr(2, 4)), BeforeOrAt).element); assertTrue(keys.get(1) == score.getKey(atBeat(0, 0, 0, fr(3, 4)), Before).element); assertTrue(keys.get(1) == score.getKey(atBeat(0, 1, 0, fr(0, 4)), BeforeOrAt).element); assertTrue(keys.get(1) == score.getKey(atBeat(0, 1, 0, fr(1, 4)), Before).element); assertTrue(keys.get(2) == score.getKey(atBeat(0, 1, 0, fr(1, 4)), BeforeOrAt).element); assertTrue(keys.get(2) == score.getKey(atBeat(0, 1, 0, fr(2, 4)), Before).element); } /** * Creates a score with a single staff, two measures, * and a number of clefs, keys and chords. * The score, the list of clefs and the list of keys is returned. */ private Tuple3<Score, List<ClefType>, List<Key>> createTestScoreClefsKeys() { //create two measures: //clef-g, key-Gmaj, C#1/4, clef-f, Db1/4, clef-g, key-Fmaj, Cnat1/4 | //C#1/4, key-Cmaj, clef-f, C2/4. Score score = ScoreFactory.create1Staff(); new MeasureAdd(score, 1).execute(); List<ClefType> clefs = alist(); List<Key> keys = alist(); ClefType c; Key k; //measure 0 Measure measure = score.getMeasure(atMeasure(0, 0)); new Clef(ClefType.clefTreble); clefs.add(c = ClefType.clefTreble); new MeasureElementWrite(new Clef(c), measure, fr(0, 4)).execute(); keys.add(k = new TraditionalKey(1, Mode.Major)); new MeasureElementWrite(k, measure, fr(0, 4)).execute(); new VoiceElementWrite(measure.getVoice(0), atElement(0, 0, 0, 0), chord(pi(0, 1, 4), fr(1, 4)), null).execute(); clefs.add(c = ClefType.clefBass); new MeasureElementWrite(new Clef(c), measure, fr(1, 4)).execute(); new VoiceElementWrite(measure.getVoice(0), atElement(0, 0, 0, 1), chord(pi(1, -1, 4), fr(1, 4)), null).execute(); clefs.add(c = ClefType.clefTreble); new MeasureElementWrite(new Clef(c), measure, fr(2, 4)).execute(); keys.add(k = new TraditionalKey(-1, Mode.Major)); new MeasureElementWrite(k, measure, fr(2, 4)).execute(); new VoiceElementWrite(measure.getVoice(0), atElement(0, 0, 0, 2), chord(pi(0, 0, 4), fr(1, 4)), null).execute(); //measure 1 measure = score.getMeasure(atMeasure(0, 1)); new VoiceElementWrite(measure.getVoice(0), atElement(0, 1, 0, 0), chord(pi(0, 1, 4), fr(1, 4)), null).execute(); keys.add(k = new TraditionalKey(0, Mode.Major)); new MeasureElementWrite(k, measure, fr(1, 4)).execute(); clefs.add(c = ClefType.clefBass); new MeasureElementWrite(new Clef(c), measure, fr(1, 4)).execute(); new VoiceElementWrite(measure.getVoice(0), atElement(0, 1, 0, 1), chord(pi(0, 0, 4), fr(2, 4)), null).execute(); return t3(score, clefs, keys); } @Test public void getAccidentalsTest() { Score score = createTestScoreAccidentals(); Map<Pitch, Integer> acc; //measure 0 acc = score.getAccidentals(atBeat(0, 0, 0, fr(0, 4)), Before); assertEquals(0, acc.size()); acc = score.getAccidentals(atBeat(0, 0, 0, fr(0, 4)), BeforeOrAt); assertEquals(1, acc.size()); assertEquals((Integer) 0, acc.get(pi(3, 0, 4))); acc = score.getAccidentals(atBeat(0, 0, 0, fr(1, 4)), Before); assertEquals(1, acc.size()); acc = score.getAccidentals(atBeat(0, 0, 0, fr(1, 4)), BeforeOrAt); assertEquals(1, acc.size()); //measure 1 acc = score.getAccidentals(atBeat(0, 1, 0, fr(0, 4)), Before); assertEquals(0, acc.size()); acc = score.getAccidentals(atBeat(0, 1, 0, fr(0, 4)), BeforeOrAt); assertEquals(1, acc.size()); assertEquals((Integer) 1, acc.get(pi(3, 0, 4))); acc = score.getAccidentals(atBeat(0, 1, 0, fr(1, 4)), Before); assertEquals(0, acc.size()); //0, because key changed acc = score.getAccidentals(atBeat(0, 1, 0, fr(1, 4)), BeforeOrAt); assertEquals(2, acc.size()); assertEquals((Integer) 1, acc.get(pi(3, 0, 4))); assertEquals((Integer) (-1), acc.get(pi(6, 0, 4))); } /** * Creates a score with a single staff, two measures with each two voices, * with key changes and chords with accidentals. */ private Score createTestScoreAccidentals() { //create two measures with two voices: // measure 0 | measure 1 //beat: 0 1 | 0 1 //key: Gmaj | *Fmaj Cmaj //voice 0: C4 | F#4 Bb4 Bb4 //voice 1: Fnat4 | Bb4 F#4 F#4 //(*) is a private key (not in measure column) Score score = ScoreFactory.create1Staff(); new MeasureAdd(score, 1).execute(); new VoiceAdd(score.getMeasure(atMeasure(0, 0)), 1).execute(); new VoiceAdd(score.getMeasure(atMeasure(0, 1)), 1).execute(); //keys new ColumnElementWrite(new TraditionalKey(1, Mode.Major), score.getColumnHeader(0), fr(0, 4), null).execute(); new MeasureElementWrite(new TraditionalKey(-1, Mode.Major), score.getMeasure(atMeasure(0, 1)), fr(0, 4)).execute(); new ColumnElementWrite(new TraditionalKey(0, Mode.Major), score.getColumnHeader(1), fr(1, 4), null).execute(); //measure 0, voice 0 Voice voice = score.getVoice(MP.atVoice(0, 0, 0)); voice.addElement(chord(pi(0, 0, 4), fr(2, 4))); //measure 1, voice 0 voice = score.getVoice(MP.atVoice(0, 1, 0)); voice.addElement(chord(pi(3, 1, 4), fr(1, 4))); voice.addElement(chord(pi(6, -1, 4), fr(1, 8))); voice.addElement(chord(pi(6, -1, 4), fr(1, 8))); //measure 0, voice 1 voice = score.getVoice(MP.atVoice(0, 0, 1)); voice.addElement(chord(pi(3, 0, 4), fr(2, 4))); //measure 1, voice 1 voice = score.getVoice(MP.atVoice(0, 1, 1)); voice.addElement(chord(pi(6, -1, 4), fr(1, 4))); voice.addElement(chord(pi(3, 1, 4), fr(1, 8))); voice.addElement(chord(pi(3, 1, 4), fr(1, 8))); return score; } @Test public void getClefTest() { Tuple3<Score, List<ClefType>, List<Key>> testData = createTestScoreClefsKeys(); Score score = testData.get1(); List<ClefType> clefs = testData.get2(); assertTrue(clefs.get(0) == score.getClef(atBeat(0, 0, 0, fr(0, 4)), BeforeOrAt)); assertTrue(clefs.get(0) == score.getClef(atBeat(0, 0, 0, fr(1, 4)), Before)); assertTrue(clefs.get(1) == score.getClef(atBeat(0, 0, 0, fr(1, 4)), BeforeOrAt)); assertTrue(clefs.get(1) == score.getClef(atBeat(0, 0, 0, fr(2, 4)), Before)); assertTrue(clefs.get(2) == score.getClef(atBeat(0, 0, 0, fr(2, 4)), BeforeOrAt)); assertTrue(clefs.get(2) == score.getClef(atBeat(0, 0, 0, fr(3, 4)), Before)); assertTrue(clefs.get(2) == score.getClef(atBeat(0, 1, 0, fr(0, 4)), BeforeOrAt)); assertTrue(clefs.get(2) == score.getClef(atBeat(0, 1, 0, fr(1, 4)), Before)); assertTrue(clefs.get(3) == score.getClef(atBeat(0, 1, 0, fr(1, 4)), BeforeOrAt)); assertTrue(clefs.get(3) == score.getClef(atBeat(0, 1, 0, fr(2, 4)), Before)); } @Test public void getMusicContextTest() { Tuple3<Score, List<ClefType>, List<Key>> testData = createTestScoreClefsKeys(); Score score = testData.get1(); List<ClefType> clefs = testData.get2(); List<Key> keys = testData.get3(); //measure 1: before 0/4: no accidentals MusicContext musicContext = score.getMusicContext(atBeat(0, 1, 0, fr(0, 4)), BeforeOrAt, Before); assertEquals(0, musicContext.getAccidentals().size()); //measure 1: at 1/8: G clef, F key and C#4 accidental musicContext = score.getMusicContext(atBeat(0, 1, 0, fr(1, 8)), BeforeOrAt, Before); Assert.assertEquals(clefs.get(2), musicContext.getClef()); Assert.assertEquals(keys.get(1), musicContext.getKey()); assertEquals(1, musicContext.getAccidentals().size()); assertEquals(1, (int) musicContext.getAccidentals().get(pi(0, 0, 4))); //measure 1: at 1/4: F clef, C key and no accidentals musicContext = score.getMusicContext(atBeat(0, 1, 0, fr(1, 4)), BeforeOrAt, Before); Assert.assertEquals(clefs.get(3), musicContext.getClef()); Assert.assertEquals(keys.get(2), musicContext.getKey()); assertEquals(0, musicContext.getAccidentals().size()); } @Test public void getGapBetweenTest() { Score score = ScoreFactory.create1Staff4Measures(); VoiceElement[] e = new VoiceElement[6]; //4/4 measure score.getColumnHeader(0).setTime(new TimeSignature(TimeType.time_4_4)); //first measure (filled only with 7/8) // voice 0: 1/4, 1/4, 1/4 (1/4 is missing) // voice 1: 3/4, 1/8 (1/8 is missing) score.getVoice(atVoice(0, 0, 0)).addElement(e[0] = new Rest(fr(1, 4))); score.getVoice(atVoice(0, 0, 0)).addElement(e[1] = new Rest(fr(1, 4))); score.getVoice(atVoice(0, 0, 0)).addElement(e[2] = new Rest(fr(1, 4))); new VoiceAdd(score.getMeasure(atMeasure(0, 0)), 1).execute(); score.getVoice(atVoice(0, 0, 1)).addElement(new Rest(fr(3, 4))); score.getVoice(atVoice(0, 0, 1)).addElement(new Rest(fr(1, 8))); //second measure: 1/4, 3/4 score.getVoice(atVoice(0, 1, 0)).addElement(e[3] = new Rest(fr(1, 4))); score.getVoice(atVoice(0, 1, 0)).addElement(e[4] = new Rest(fr(3, 4))); //third measure: 4/4 score.getVoice(atVoice(0, 1, 0)).addElement(e[5] = new Rest(fr(4, 4))); //test gaps between adjacent elements assertEquals(_0, score.getGapBetween(e[0], e[1])); assertEquals(_0, score.getGapBetween(e[1], e[2])); assertEquals(fr(1, 8), score.getGapBetween(e[2], e[3])); //1/8 from second voice assertEquals(_0, score.getGapBetween(e[3], e[4])); assertEquals(_0, score.getGapBetween(e[4], e[5])); //test some gaps between non-adjacent elements assertEquals(fr(1, 4), score.getGapBetween(e[0], e[2])); assertEquals(fr(3, 8), score.getGapBetween(e[1], e[3])); //includes 1/8 from second voice assertEquals(fr(3, 8), score.getGapBetween(e[2], e[4])); //includes 1/8 from second voice assertEquals(fr(5, 8).add(fr(4, 4)), score.getGapBetween(e[0], e[5])); //includes 1/8 from second voice assertEquals(fr(3, 8).add(fr(4, 4)), score.getGapBetween(e[1], e[5])); //includes 1/8 from second voice //test in reverse direction assertEquals(fr(-2, 4), score.getGapBetween(e[1], e[0])); assertEquals(fr(-2, 4), score.getGapBetween(e[2], e[1])); assertEquals(fr(-5, 8), score.getGapBetween(e[3], e[2])); //includes 1/8 from second voice assertEquals(fr(-23, 8), score.getGapBetween(e[5], e[0])); //includes 1/8 from second voice assertEquals(fr(-21, 8), score.getGapBetween(e[5], e[1])); //includes 1/8 from second voice } }