public void TestNotesOverlap() { SheetMusic.SetNoteSize(false); KeySignature key = new KeySignature(0, 0); int quarter = 400; TimeSignature time = new TimeSignature(4, 4, quarter, 60000); int num1 = WhiteNote.BottomTreble.Number(); int num2 = num1 + 1; MidiNote note1 = new MidiNote(0, 0, num1, quarter); MidiNote note2 = new MidiNote(0, 0, num2, quarter); List<MidiNote> notes = new List<MidiNote>(2); notes.Add(note1); notes.Add(note2); ChordSymbol chord = new ChordSymbol(notes, key, time, Clef.Treble, null); Assert.AreEqual(chord.ToString(), "ChordSymbol clef=Treble start=0 end=400 width=25 hastwostems=False AccidSymbol accid=Sharp whitenote=F4 clef=Treble width=9 Note whitenote=F4 duration=Quarter leftside=True Note whitenote=F4 duration=Quarter leftside=True Stem duration=Quarter direction=1 top=F4 bottom=F4 end=E5 overlap=False side=2 width_to_pair=0 receiver_in_pair=False "); }
private int ytop; /** The y pixel of the top of the staff */ #endregion Fields #region Constructors /** Create a new staff with the given list of music symbols, * and the given key signature. The clef is determined by * the clef of the first chord symbol. The track number is used * to determine whether to join this left/right vertical sides * with the staffs above and below. The SheetMusicOptions are used * to check whether to display measure numbers or not. */ public Staff(List<MusicSymbol> symbols, KeySignature key, MidiOptions options, int tracknum, int totaltracks) { keysigWidth = SheetMusic.KeySignatureWidth(key); this.tracknum = tracknum; this.totaltracks = totaltracks; showMeasures = (options.showMeasures && tracknum == 0); measureLength = options.time.Measure; Clef clef = FindClef(symbols); clefsym = new ClefSymbol(clef, 0, false); keys = key.GetSymbols(clef); this.symbols = symbols; CalculateWidth(options.scrollVert); CalculateHeight(); CalculateStartEndTime(); FullJustify(); }
private int measureLength; /** The time (in pulses) of a measure */ /** Create a new staff with the given list of music symbols, * and the given key signature. The clef is determined by * the clef of the first chord symbol. The track number is used * to determine whether to join this left/right vertical sides * with the staffs above and below. The SheetMusicOptions are used * to check whether to display measure numbers or not. */ public Staff(List <MusicSymbol> symbols, KeySignature key, MidiOptions options, int tracknum, int totaltracks) { keysigWidth = SheetMusic.KeySignatureWidth(key); this.tracknum = tracknum; this.totaltracks = totaltracks; showMeasures = (options.showMeasures && tracknum == 0); measureLength = options.time.Measure; Clef clef = FindClef(symbols); clefsym = new ClefSymbol(clef, 0, false); keys = key.GetSymbols(clef); this.symbols = symbols; CalculateWidth(options.scrollVert); CalculateHeight(); CalculateStartEndTime(); FullJustify(); }
CreateNoteData(List <MidiNote> midinotes, KeySignature key, TimeSignature time) { int len = midinotes.Count; NoteData[] notedata = new NoteData[len]; for (int i = 0; i < len; i++) { MidiNote midi = midinotes[i]; notedata[i] = new NoteData(); notedata[i].number = midi.Number; notedata[i].leftside = true; notedata[i].whitenote = key.GetWhiteNote(midi.Number); notedata[i].duration = time.GetNoteDuration(midi.EndTime - midi.StartTime); notedata[i].accid = key.GetAccidental(midi.Number, midi.StartTime / time.Measure); if (i > 0 && (notedata[i].whitenote.Dist(notedata[i - 1].whitenote) == 1)) { /* This note (notedata[i]) overlaps with the previous note. * Change the side of this note. */ if (notedata[i - 1].leftside) { notedata[i].leftside = false; } else { notedata[i].leftside = true; } } else { notedata[i].leftside = true; } } return(notedata); }
List <ChordSymbol> CreateChords(List <MidiNote> midinotes, KeySignature key, TimeSignature time, ClefMeasures clefs) { int i = 0; List <ChordSymbol> chords = new List <ChordSymbol>(); List <MidiNote> notegroup = new List <MidiNote>(12); int len = midinotes.Count; while (i < len) { int starttime = midinotes[i].StartTime; Clef clef = clefs.GetClef(starttime); /* Group all the midi notes with the same start time * into the notes list. */ notegroup.Clear(); notegroup.Add(midinotes[i]); i++; while (i < len && midinotes[i].StartTime == starttime) { notegroup.Add(midinotes[i]); i++; } /* Create a single chord from the group of midi notes with * the same start time. */ ChordSymbol chord = new ChordSymbol(notegroup, key, time, clef, this); chords.Add(chord); } return(chords); }
/** Given the raw midi notes (the note number and duration in pulses), * calculate the following note data: * - The white key * - The accidental (if any) * - The note duration (half, quarter, eighth, etc) * - The side it should be drawn (left or side) * By default, notes are drawn on the left side. However, if two notes * overlap (like A and B) you cannot draw the next note directly above it. * Instead you must shift one of the notes to the right. * * The KeySignature is used to determine the white key and accidental. * The TimeSignature is used to determine the duration. */ private static NoteData[] CreateNoteData(List<MidiNote> midinotes, KeySignature key, TimeSignature time) { int len = midinotes.Count; NoteData[] notedata = new NoteData[len]; for (int i = 0; i < len; i++) { MidiNote midi = midinotes[i]; notedata[i] = new NoteData(); notedata[i].number = midi.Number; notedata[i].leftside = true; notedata[i].whitenote = key.GetWhiteNote(midi.Number); notedata[i].duration = time.GetNoteDuration(midi.EndTime - midi.StartTime); notedata[i].accid = key.GetAccidental(midi.Number, midi.StartTime / time.Measure); if (i > 0 && (notedata[i].whitenote.Dist(notedata[i-1].whitenote) == 1)) { /* This note (notedata[i]) overlaps with the previous note. * Change the side of this note. */ if (notedata[i-1].leftside) { notedata[i].leftside = false; } else { notedata[i].leftside = true; } } else { notedata[i].leftside = true; } } return notedata; }
private int width; /** The width of the chord */ #endregion Fields #region Constructors /** Create a new Chord Symbol from the given list of midi notes. * All the midi notes will have the same start time. Use the * key signature to get the white key and accidental symbol for * each note. Use the time signature to calculate the duration * of the notes. Use the clef when drawing the chord. */ public ChordSymbol(List<MidiNote> midinotes, KeySignature key, TimeSignature time, Clef c, SheetMusic sheet) { int len = midinotes.Count; int i; hastwostems = false; clef = c; sheetmusic = sheet; starttime = midinotes[0].StartTime; endtime = midinotes[0].EndTime; for (i = 0; i < midinotes.Count; i++) { if (i > 1) { if (midinotes[i].Number < midinotes[i-1].Number) { throw new System.ArgumentException("Chord notes not in increasing order by number"); } } endtime = Math.Max(endtime, midinotes[i].EndTime); } notedata = CreateNoteData(midinotes, key, time); accidsymbols = CreateAccidSymbols(notedata, clef); /* Find out how many stems we need (1 or 2) */ NoteDuration dur1 = notedata[0].duration; NoteDuration dur2 = dur1; int change = -1; for (i = 0; i < notedata.Length; i++) { dur2 = notedata[i].duration; if (dur1 != dur2) { change = i; break; } } if (dur1 != dur2) { /* We have notes with different durations. So we will need * two stems. The first stem points down, and contains the * bottom note up to the note with the different duration. * * The second stem points up, and contains the note with the * different duration up to the top note. */ hastwostems = true; stem1 = new Stem(notedata[0].whitenote, notedata[change-1].whitenote, dur1, Stem.Down, NotesOverlap(notedata, 0, change) ); stem2 = new Stem(notedata[change].whitenote, notedata[notedata.Length-1].whitenote, dur2, Stem.Up, NotesOverlap(notedata, change, notedata.Length) ); } else { /* All notes have the same duration, so we only need one stem. */ int direction = StemDirection(notedata[0].whitenote, notedata[notedata.Length-1].whitenote, clef); stem1 = new Stem(notedata[0].whitenote, notedata[notedata.Length-1].whitenote, dur1, direction, NotesOverlap(notedata, 0, notedata.Length) ); stem2 = null; } /* For whole notes, no stem is drawn. */ if (dur1 == NoteDuration.Whole) stem1 = null; if (dur2 == NoteDuration.Whole) stem2 = null; width = MinWidth; }
CreateStaffsForTrack(List <MusicSymbol> symbols, int measurelen, KeySignature key, MidiOptions options, int track, int totaltracks) { int keysigWidth = KeySignatureWidth(key); int startindex = 0; List <Staff> thestaffs = new List <Staff>(symbols.Count / 50); while (startindex < symbols.Count) { /* startindex is the index of the first symbol in the staff. * endindex is the index of the last symbol in the staff. */ int endindex = startindex; int width = keysigWidth; int maxwidth; /* If we're scrolling vertically, the maximum width is PageWidth. */ if (scrollVert) { maxwidth = SheetMusic.PageWidth; } else { maxwidth = 2000000; } while (endindex < symbols.Count && width + symbols[endindex].Width < maxwidth) { width += symbols[endindex].Width; endindex++; } endindex--; /* There's 3 possibilities at this point: * 1. We have all the symbols in the track. * The endindex stays the same. * * 2. We have symbols for less than one measure. * The endindex stays the same. * * 3. We have symbols for 1 or more measures. * Since measures cannot span multiple staffs, we must * make sure endindex does not occur in the middle of a * measure. We count backwards until we come to the end * of a measure. */ if (endindex == symbols.Count - 1) { /* endindex stays the same */ } else if (symbols[startindex].StartTime / measurelen == symbols[endindex].StartTime / measurelen) { /* endindex stays the same */ } else { int endmeasure = symbols[endindex + 1].StartTime / measurelen; while (symbols[endindex].StartTime / measurelen == endmeasure) { endindex--; } } int range = endindex + 1 - startindex; if (scrollVert) { width = SheetMusic.PageWidth; } Staff staff = new Staff(symbols.GetRange(startindex, range), key, options, track, totaltracks); thestaffs.Add(staff); startindex = endindex + 1; } return(thestaffs); }
/** Create the chord symbols for a single track. * @param midinotes The Midinotes in the track. * @param key The Key Signature, for determining sharps/flats. * @param time The Time Signature, for determining the measures. * @param clefs The clefs to use for each measure. * @ret An array of ChordSymbols */ private List<ChordSymbol> CreateChords(List<MidiNote> midinotes, KeySignature key, TimeSignature time, ClefMeasures clefs) { int i = 0; List<ChordSymbol> chords = new List<ChordSymbol>(); List<MidiNote> notegroup = new List<MidiNote>(12); int len = midinotes.Count; while (i < len) { int starttime = midinotes[i].StartTime; Clef clef = clefs.GetClef(starttime); /* Group all the midi notes with the same start time * into the notes list. */ notegroup.Clear(); notegroup.Add(midinotes[i]); i++; while (i < len && midinotes[i].StartTime == starttime) { notegroup.Add(midinotes[i]); i++; } /* Create a single chord from the group of midi notes with * the same start time. */ ChordSymbol chord = new ChordSymbol(notegroup, key, time, clef, this); chords.Add(chord); } return chords; }
/** Return true if this key signature is equal to key signature k */ public bool Equals(KeySignature k) { if (k.num_sharps == num_sharps && k.num_flats == num_flats) return true; else return false; }
private SheetMusic sheetmusic; /** Used to get colors and other options */ /** Create a new Chord Symbol from the given list of midi notes. * All the midi notes will have the same start time. Use the * key signature to get the white key and accidental symbol for * each note. Use the time signature to calculate the duration * of the notes. Use the clef when drawing the chord. */ public ChordSymbol(List <MidiNote> midinotes, KeySignature key, TimeSignature time, Clef c, SheetMusic sheet) { int len = midinotes.Count; int i; hastwostems = false; clef = c; sheetmusic = sheet; starttime = midinotes[0].StartTime; endtime = midinotes[0].EndTime; for (i = 0; i < midinotes.Count; i++) { if (i > 1) { if (midinotes[i].Number < midinotes[i - 1].Number) { throw new System.ArgumentException("Chord notes not in increasing order by number"); } } endtime = Math.Max(endtime, midinotes[i].EndTime); } notedata = CreateNoteData(midinotes, key, time); accidsymbols = CreateAccidSymbols(notedata, clef); /* Find out how many stems we need (1 or 2) */ NoteDuration dur1 = notedata[0].duration; NoteDuration dur2 = dur1; int change = -1; for (i = 0; i < notedata.Length; i++) { dur2 = notedata[i].duration; if (dur1 != dur2) { change = i; break; } } if (dur1 != dur2) { /* We have notes with different durations. So we will need * two stems. The first stem points down, and contains the * bottom note up to the note with the different duration. * * The second stem points up, and contains the note with the * different duration up to the top note. */ hastwostems = true; stem1 = new Stem(notedata[0].whitenote, notedata[change - 1].whitenote, dur1, Stem.Down, NotesOverlap(notedata, 0, change) ); stem2 = new Stem(notedata[change].whitenote, notedata[notedata.Length - 1].whitenote, dur2, Stem.Up, NotesOverlap(notedata, change, notedata.Length) ); } else { /* All notes have the same duration, so we only need one stem. */ int direction = StemDirection(notedata[0].whitenote, notedata[notedata.Length - 1].whitenote, clef); stem1 = new Stem(notedata[0].whitenote, notedata[notedata.Length - 1].whitenote, dur1, direction, NotesOverlap(notedata, 0, notedata.Length) ); stem2 = null; } /* For whole notes, no stem is drawn. */ if (dur1 == NoteDuration.Whole) { stem1 = null; } if (dur2 == NoteDuration.Whole) { stem2 = null; } width = MinWidth; }
/** Get the width (in pixels) needed to display the key signature */ public static int KeySignatureWidth(KeySignature key) { ClefSymbol clefsym = new ClefSymbol(Clef.Treble, 0, false); int result = clefsym.MinWidth; AccidSymbol[] keys = key.GetSymbols(Clef.Treble); foreach (AccidSymbol symbol in keys) { result += symbol.MinWidth; } return result + SheetMusic.LeftMargin + 5; }
public void TestGetAccidentalSameMeasure() { KeySignature k; /* G Major, F# */ k = new KeySignature(1, 0); int note = NoteScale.ToNumber(NoteScale.C, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.C); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.C); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Fsharp, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.F, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Natural); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Fsharp, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Sharp); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Bflat, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Flat); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.A, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.A); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.B, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Natural); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Bflat, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Flat); /* F Major, Bflat */ k = new KeySignature(0, 1); note = NoteScale.ToNumber(NoteScale.G, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.G); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.G); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Bflat, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.B, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Natural); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Bflat, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Flat); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.B); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Fsharp, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Sharp); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.G, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.G); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.F, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Natural); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.None); note = NoteScale.ToNumber(NoteScale.Fsharp, 1); Assert.AreEqual(k.GetWhiteNote(note).Letter, WhiteNote.F); Assert.AreEqual(k.GetAccidental(note, 1), Accid.Sharp); }
public void TestGetAccidental() { int measure = 1; KeySignature k; Accid[] expected = new Accid[12]; for (int i = 0; i < 12; i++) { expected[i] = Accid.None; } expected[NoteScale.Bflat] = Accid.Flat; expected[NoteScale.Csharp] = Accid.Sharp; expected[NoteScale.Dsharp] = Accid.Sharp; expected[NoteScale.Fsharp] = Accid.Sharp; expected[NoteScale.Gsharp] = Accid.Sharp; /* Test C Major */ k = new KeySignature(0, 0); measure = 1; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test G major, F# */ k = new KeySignature(1, 0); measure = 1; expected[NoteScale.Fsharp] = Accid.None; expected[NoteScale.F] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test D major, F#, C# */ k = new KeySignature(2, 0); measure = 1; expected[NoteScale.Csharp] = Accid.None; expected[NoteScale.C] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test A major, F#, C#, G# */ k = new KeySignature(3, 0); measure = 1; expected[NoteScale.Gsharp] = Accid.None; expected[NoteScale.G] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test E major, F#, C#, G#, D# */ k = new KeySignature(4, 0); measure = 1; expected[NoteScale.Dsharp] = Accid.None; expected[NoteScale.D] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test B major, F#, C#, G#, D#, A# */ k = new KeySignature(5, 0); measure = 1; expected[NoteScale.Asharp] = Accid.None; expected[NoteScale.A] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } for (int i = 0; i < 12; i++) { expected[i] = Accid.None; } expected[NoteScale.Aflat] = Accid.Flat; expected[NoteScale.Bflat] = Accid.Flat; expected[NoteScale.Csharp] = Accid.Sharp; expected[NoteScale.Eflat] = Accid.Flat; expected[NoteScale.Fsharp] = Accid.Sharp; /* Test F major, Bflat */ k = new KeySignature(0, 1); measure = 1; expected[NoteScale.Bflat] = Accid.None; expected[NoteScale.B] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test Bflat major, Bflat, Eflat */ k = new KeySignature(0, 2); measure = 1; expected[NoteScale.Eflat] = Accid.None; expected[NoteScale.E] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test Eflat major, Bflat, Eflat, Afat */ k = new KeySignature(0, 3); measure = 1; expected[NoteScale.Aflat] = Accid.None; expected[NoteScale.A] = Accid.Natural; expected[NoteScale.Dflat] = Accid.Flat; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test Aflat major, Bflat, Eflat, Aflat, Dflat */ k = new KeySignature(0, 4); measure = 1; expected[NoteScale.Dflat] = Accid.None; expected[NoteScale.D] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } /* Test Dflat major, Bflat, Eflat, Aflat, Dflat, Gflat */ k = new KeySignature(0, 5); measure = 1; expected[NoteScale.Gflat] = Accid.None; expected[NoteScale.G] = Accid.Natural; for (int note = 1; note < 128; note++) { int notescale = NoteScale.FromNumber(note); Assert.AreEqual(expected[notescale], k.GetAccidental(note, measure)); measure++; } }
public void TestWholeDuration() { SheetMusic.SetNoteSize(false); KeySignature key = new KeySignature(0, 0); int quarter = 400; TimeSignature time = new TimeSignature(4, 4, quarter, 60000); int num1 = WhiteNote.BottomTreble.Number(); MidiNote note1 = new MidiNote(0, 0, num1, quarter*4); List<MidiNote> notes = new List<MidiNote>(2); notes.Add(note1); ChordSymbol chord = new ChordSymbol(notes, key, time, Clef.Treble, null); Assert.AreEqual(chord.ToString(), "ChordSymbol clef=Treble start=0 end=1600 width=16 hastwostems=False Note whitenote=F4 duration=Whole leftside=True "); }
public void TestStemUpBass() { SheetMusic.SetNoteSize(false); KeySignature key = new KeySignature(0, 0); int quarter = 400; TimeSignature time = new TimeSignature(4, 4, quarter, 60000); int num1 = WhiteNote.BottomBass.Number(); int num2 = num1 + 2; MidiNote note1 = new MidiNote(0, 0, num1, quarter); MidiNote note2 = new MidiNote(0, 0, num2, quarter); List<MidiNote> notes = new List<MidiNote>(2); notes.Add(note1); notes.Add(note2); ChordSymbol chord = new ChordSymbol(notes, key, time, Clef.Bass, null); Assert.AreEqual(chord.ToString(), "ChordSymbol clef=Bass start=0 end=400 width=16 hastwostems=False Note whitenote=A3 duration=Quarter leftside=True Note whitenote=B3 duration=Quarter leftside=False Stem duration=Quarter direction=1 top=B3 bottom=A3 end=A4 overlap=True side=2 width_to_pair=0 receiver_in_pair=False "); }
public void TestSixteenthDuration() { SheetMusic.SetNoteSize(false); KeySignature key = new KeySignature(0, 0); int quarter = 400; TimeSignature time = new TimeSignature(4, 4, quarter, 60000); int num1 = WhiteNote.BottomTreble.Number(); MidiNote note1 = new MidiNote(0, 0, num1, quarter/4); List<MidiNote> notes = new List<MidiNote>(2); notes.Add(note1); ChordSymbol chord = new ChordSymbol(notes, key, time, Clef.Treble, null); Assert.AreEqual(chord.ToString(), "ChordSymbol clef=Treble start=0 end=100 width=16 hastwostems=False Note whitenote=F4 duration=Sixteenth leftside=True Stem duration=Sixteenth direction=1 top=F4 bottom=F4 end=G5 overlap=False side=2 width_to_pair=0 receiver_in_pair=False "); Assert.AreEqual(chord.AboveStaff, SheetMusic.NoteHeight); }
/** Given MusicSymbols for a track, create the staffs for that track. * Each Staff has a maxmimum width of PageWidth (800 pixels). * Also, measures should not span multiple Staffs. */ private List<Staff> CreateStaffsForTrack(List<MusicSymbol> symbols, int measurelen, KeySignature key, MidiOptions options, int track, int totaltracks) { int keysigWidth = KeySignatureWidth(key); int startindex = 0; List<Staff> thestaffs = new List<Staff>(symbols.Count / 50); while (startindex < symbols.Count) { /* startindex is the index of the first symbol in the staff. * endindex is the index of the last symbol in the staff. */ int endindex = startindex; int width = keysigWidth; int maxwidth; /* If we're scrolling vertically, the maximum width is PageWidth. */ if (scrollVert) { maxwidth = SheetMusic.PageWidth; } else { maxwidth = 2000000; } while (endindex < symbols.Count && width + symbols[endindex].Width < maxwidth) { width += symbols[endindex].Width; endindex++; } endindex--; /* There's 3 possibilities at this point: * 1. We have all the symbols in the track. * The endindex stays the same. * * 2. We have symbols for less than one measure. * The endindex stays the same. * * 3. We have symbols for 1 or more measures. * Since measures cannot span multiple staffs, we must * make sure endindex does not occur in the middle of a * measure. We count backwards until we come to the end * of a measure. */ if (endindex == symbols.Count - 1) { /* endindex stays the same */ } else if (symbols[startindex].StartTime / measurelen == symbols[endindex].StartTime / measurelen) { /* endindex stays the same */ } else { int endmeasure = symbols[endindex+1].StartTime/measurelen; while (symbols[endindex].StartTime / measurelen == endmeasure) { endindex--; } } int range = endindex + 1 - startindex; if (scrollVert) { width = SheetMusic.PageWidth; } Staff staff = new Staff(symbols.GetRange(startindex, range), key, options, track, totaltracks); thestaffs.Add(staff); startindex = endindex + 1; } return thestaffs; }
public void TestGetSymbols() { KeySignature k; AccidSymbol[] symbols1, symbols2; k = new KeySignature(0, 0); symbols1 = k.GetSymbols(Clef.Treble); symbols2 = k.GetSymbols(Clef.Bass); Assert.AreEqual(symbols1.Length, 0); Assert.AreEqual(symbols2.Length, 0); int[] sharps = new int[] { WhiteNote.F, WhiteNote.C, WhiteNote.G, WhiteNote.D, WhiteNote.A, WhiteNote.E }; for (int sharp = 1; sharp < 7; sharp++) { k = new KeySignature(sharp, 0); symbols1 = k.GetSymbols(Clef.Treble); symbols2 = k.GetSymbols(Clef.Bass); for (int i = 0; i < sharp; i++) { Assert.AreEqual(symbols1[i].Note.Letter, sharps[i]); Assert.AreEqual(symbols2[i].Note.Letter, sharps[i]); } } int[] flats = new int[] { WhiteNote.B, WhiteNote.E, WhiteNote.A, WhiteNote.D, WhiteNote.G }; for (int flat = 1; flat < 6; flat++) { k = new KeySignature(0, flat); symbols1 = k.GetSymbols(Clef.Treble); symbols2 = k.GetSymbols(Clef.Bass); for (int i = 0; i < flat; i++) { Assert.AreEqual(symbols1[i].Note.Letter, flats[i]); Assert.AreEqual(symbols2[i].Note.Letter, flats[i]); } } }
/** Create a new SheetMusic control, using the given midi filename. * The options can be null. */ //public SheetMusic(string filename, MidiOptions options) { // MidiFile file = new MidiFile(filename); // init(file, options); //} /** Create a new SheetMusic control, using the given raw midi byte[] data. * The options can be null. */ //public SheetMusic(byte[] data, string title, MidiOptions options) { // MidiFile file = new MidiFile(data, title); // init(file, options); // } /** Create a new SheetMusic control. * MidiFile is the parsed midi file to display. * SheetMusic Options are the menu options that were selected. * * - Apply all the Menu Options to the MidiFile tracks. * - Calculate the key signature * - For each track, create a list of MusicSymbols (notes, rests, bars, etc) * - Vertically align the music symbols in all the tracks * - Partition the music notes into horizontal staffs */ public void Load(MidiFile file, MidiOptions options) { if (options == null) { options = new MidiOptions(file); } zoom = 1.0f; filename = file.FileName; SetColors(options.colors, options.shadeColor, options.shade2Color); pen = new Pen(Color.Black, 1); List<MidiTrack> tracks = file.ChangeMidiNotes(options); SetNoteSize(options.largeNoteSize); scrollVert = options.scrollVert; showNoteLetters= options.showNoteLetters; TimeSignature time = file.Time; if (options.time != null) { time = options.time; } if (options.key == -1) { mainkey = GetKeySignature(tracks); } else { mainkey = new KeySignature(options.key); } numtracks = tracks.Count; int lastStart = file.EndTime() + options.shifttime; /* Create all the music symbols (notes, rests, vertical bars, and * clef changes). The symbols variable contains a list of music * symbols for each track. The list does not include the left-side * Clef and key signature symbols. Those can only be calculated * when we create the staffs. */ List<MusicSymbol>[] symbols = new List<MusicSymbol> [ numtracks ]; for (int tracknum = 0; tracknum < numtracks; tracknum++) { MidiTrack track = tracks[tracknum]; ClefMeasures clefs = new ClefMeasures(track.Notes, time.Measure); List<ChordSymbol> chords = CreateChords(track.Notes, mainkey, time, clefs); symbols[tracknum] = CreateSymbols(chords, clefs, time, lastStart); } List<LyricSymbol>[] lyrics = null; if (options.showLyrics) { lyrics = GetLyrics(tracks); } /* Vertically align the music symbols */ SymbolWidths widths = new SymbolWidths(symbols, lyrics); // SymbolWidths widths = new SymbolWidths(symbols); AlignSymbols(symbols, widths); staffs = CreateStaffs(symbols, mainkey, options, time.Measure); CreateAllBeamedChords(symbols, time); if (lyrics != null) { AddLyricsToStaffs(staffs, lyrics); } /* After making chord pairs, the stem directions can change, * which affects the staff height. Re-calculate the staff height. */ foreach (Staff staff in staffs) { staff.CalculateHeight(); } braces = CreateBraceSymbols(staffs); BackColor = Color.White; SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); // ��ֹ��������. SetStyle(ControlStyles.DoubleBuffer, true); }
/** Create a new SheetMusic control. * MidiFile is the parsed midi file to display. * SheetMusic Options are the menu options that were selected. * * - Apply all the Menu Options to the MidiFile tracks. * - Calculate the key signature * - For each track, create a list of MusicSymbols (notes, rests, bars, etc) * - Vertically align the music symbols in all the tracks * - Partition the music notes into horizontal staffs */ public void init(MidiFile file, MidiOptions options) { if (options == null) { options = new MidiOptions(file); } zoom = 1.0f; filename = file.FileName; SetColors(options.colors, options.shadeColor, options.shade2Color); pen = new Pen(Color.Black, 1); List <MidiTrack> tracks = file.ChangeMidiNotes(options); SetNoteSize(options.largeNoteSize); scrollVert = options.scrollVert; showNoteLetters = options.showNoteLetters; TimeSignature time = file.Time; if (options.time != null) { time = options.time; } if (options.key == -1) { mainkey = GetKeySignature(tracks); } else { mainkey = new KeySignature(options.key); } numtracks = tracks.Count; int lastStart = file.EndTime() + options.shifttime; /* Create all the music symbols (notes, rests, vertical bars, and * clef changes). The symbols variable contains a list of music * symbols for each track. The list does not include the left-side * Clef and key signature symbols. Those can only be calculated * when we create the staffs. */ List <MusicSymbol>[] symbols = new List <MusicSymbol> [numtracks]; for (int tracknum = 0; tracknum < numtracks; tracknum++) { MidiTrack track = tracks[tracknum]; ClefMeasures clefs = new ClefMeasures(track.Notes, time.Measure); List <ChordSymbol> chords = CreateChords(track.Notes, mainkey, time, clefs); symbols[tracknum] = CreateSymbols(chords, clefs, time, lastStart); } List <LyricSymbol>[] lyrics = null; if (options.showLyrics) { lyrics = GetLyrics(tracks); } /* Vertically align the music symbols */ SymbolWidths widths = new SymbolWidths(symbols, lyrics); // SymbolWidths widths = new SymbolWidths(symbols); AlignSymbols(symbols, widths); staffs = CreateStaffs(symbols, mainkey, options, time.Measure); CreateAllBeamedChords(symbols, time); if (lyrics != null) { AddLyricsToStaffs(staffs, lyrics); } /* After making chord pairs, the stem directions can change, * which affects the staff height. Re-calculate the staff height. */ foreach (Staff staff in staffs) { staff.CalculateHeight(); } BackColor = Color.White; SetZoom(1.0f); }
/** Given all the MusicSymbols for every track, create the staffs * for the sheet music. There are two parts to this: * * - Get the list of staffs for each track. * The staffs will be stored in trackstaffs as: * * trackstaffs[0] = { Staff0, Staff1, Staff2, ... } for track 0 * trackstaffs[1] = { Staff0, Staff1, Staff2, ... } for track 1 * trackstaffs[2] = { Staff0, Staff1, Staff2, ... } for track 2 * * - Store the Staffs in the staffs list, but interleave the * tracks as follows: * * staffs = { Staff0 for track 0, Staff0 for track1, Staff0 for track2, * Staff1 for track 0, Staff1 for track1, Staff1 for track2, * Staff2 for track 0, Staff2 for track1, Staff2 for track2, * ... } */ private List<Staff> CreateStaffs(List<MusicSymbol>[] allsymbols, KeySignature key, MidiOptions options, int measurelen) { List<Staff>[] trackstaffs = new List<Staff>[ allsymbols.Length ]; int totaltracks = trackstaffs.Length; for (int track = 0; track < totaltracks; track++) { List<MusicSymbol> symbols = allsymbols[ track ]; trackstaffs[track] = CreateStaffsForTrack(symbols, measurelen, key, options, track, totaltracks); } /* Update the EndTime of each Staff. EndTime is used for playback */ foreach (List<Staff> list in trackstaffs) { for (int i = 0; i < list.Count-1; i++) { list[i].EndTime = list[i+1].StartTime; } } /* Interleave the staffs of each track into the result array. */ int maxstaffs = 0; for (int i = 0; i < trackstaffs.Length; i++) { if (maxstaffs < trackstaffs[i].Count) { maxstaffs = trackstaffs[i].Count; } } List<Staff> result = new List<Staff>(maxstaffs * trackstaffs.Length); for (int i = 0; i < maxstaffs; i++) { foreach (List<Staff> list in trackstaffs) { if (i < list.Count) { result.Add(list[i]); } } } return result; }
/** Create the "Key Signature" sub-menu. * Create the sub-menus for changing the key signature. * The Menu.Tag contains the number of sharps (if positive) * or the number of flats (if negative) in the key. */ void CreateKeySignatureMenu() { MenuItem menu; KeySignature key; changeKeyMenu = new MenuItem("&Key Signature"); /* Add the default key signature */ menu = new MenuItem("Default", new EventHandler(ChangeKeySignature)); menu.Checked = true; menu.RadioCheck = true; menu.Tag = 0; changeKeyMenu.MenuItems.Add(menu); /* Add the sharp key signatures */ for (int sharps = 0; sharps <=5; sharps++) { key = new KeySignature (sharps, 0); menu = new MenuItem(key.ToString(), new EventHandler(ChangeKeySignature)); menu.Checked = false; menu.RadioCheck = true; menu.Tag = sharps; changeKeyMenu.MenuItems.Add(menu); } /* Add the flat key signatures */ for (int flats = 1; flats <=6; flats++) { key = new KeySignature (0, flats); menu = new MenuItem(key.ToString(), new EventHandler(ChangeKeySignature)); menu.Checked = false; menu.RadioCheck = true; menu.Tag = -flats; changeKeyMenu.MenuItems.Add(menu); } notesMenu.MenuItems.Add(changeKeyMenu); }