/** Notes with the same start times in different staffs should be * vertically aligned. The SymbolWidths class is used to help * vertically align symbols. * * First, each track should have a symbol for every starttime that * appears in the Midi File. If a track doesn't have a symbol for a * particular starttime, then add a "blank" symbol for that time. * * Next, make sure the symbols for each start time all have the same * width, across all tracks. The SymbolWidths class stores * - The symbol width for each starttime, for each track * - The maximum symbol width for a given starttime, across all tracks. * * The method SymbolWidths.GetExtraWidth() returns the extra width * needed for a track to match the maximum symbol width for a given * starttime. */ private void AlignSymbols(List<MusicSymbol>[] allsymbols, SymbolWidths widths) { for (int track = 0; track < allsymbols.Length; track++) { List<MusicSymbol> symbols = allsymbols[track]; List<MusicSymbol> result = new List<MusicSymbol>(); int i = 0; /* If a track doesn't have a symbol for a starttime, * add a blank symbol. */ foreach (int start in widths.StartTimes) { /* BarSymbols are not included in the SymbolWidths calculations */ while (i < symbols.Count && (symbols[i] is BarSymbol) && symbols[i].StartTime <= start) { result.Add(symbols[i]); i++; } if (i < symbols.Count && symbols[i].StartTime == start) { while (i < symbols.Count && symbols[i].StartTime == start) { result.Add(symbols[i]); i++; } } else { result.Add(new BlankSymbol(start, 0)); } } /* For each starttime, increase the symbol width by * SymbolWidths.GetExtraWidth(). */ i = 0; while (i < result.Count) { if (result[i] is BarSymbol) { i++; continue; } int start = result[i].StartTime; int extra = widths.GetExtraWidth(track, start); result[i].Width += extra; /* Skip all remaining symbols with the same starttime. */ while (i < result.Count && result[i].StartTime == start) { i++; } } allsymbols[track] = result; } }
/** 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); }
void AlignSymbols(List <MusicSymbol>[] allsymbols, SymbolWidths widths) { for (int track = 0; track < allsymbols.Length; track++) { List <MusicSymbol> symbols = allsymbols[track]; List <MusicSymbol> result = new List <MusicSymbol>(); int i = 0; /* If a track doesn't have a symbol for a starttime, * add a blank symbol. */ foreach (int start in widths.StartTimes) { /* BarSymbols are not included in the SymbolWidths calculations */ while (i < symbols.Count && (symbols[i] is BarSymbol) && symbols[i].StartTime <= start) { result.Add(symbols[i]); i++; } if (i < symbols.Count && symbols[i].StartTime == start) { while (i < symbols.Count && symbols[i].StartTime == start) { result.Add(symbols[i]); i++; } } else { result.Add(new BlankSymbol(start, 0)); } } /* For each starttime, increase the symbol width by * SymbolWidths.GetExtraWidth(). */ i = 0; while (i < result.Count) { if (result[i] is BarSymbol) { i++; continue; } int start = result[i].StartTime; int extra = widths.GetExtraWidth(track, start); result[i].Width += extra; /* Skip all remaining symbols with the same starttime. */ while (i < result.Count && result[i].StartTime == start) { i++; } } allsymbols[track] = result; } }
/** 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); }
public void TestStartTimes() { List<MusicSymbol>[] tracks = new List<MusicSymbol>[3]; for (int i = 0; i < 3; i++) { List<MusicSymbol> symbols = new List<MusicSymbol>(); for (int j = 0; j < 5; j++) { symbols.Add(new TestSymbol(i*10 + j, 10)); } tracks[i] = symbols; } SymbolWidths s = new SymbolWidths(tracks, null); int[] starttimes = s.StartTimes; int index = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { Assert.AreEqual(starttimes[index], i*10 + j); index++; } } }
public void TestGetExtraWidth() { List<MusicSymbol>[] tracks = new List<MusicSymbol>[3]; for (int i = 0; i < 3; i++) { List<MusicSymbol> symbols = new List<MusicSymbol>(); symbols.Add(new TestSymbol(100, i*4)); tracks[i] = symbols; } SymbolWidths s = new SymbolWidths(tracks, null); int extra = s.GetExtraWidth(0, 100); Assert.AreEqual(extra, 8); extra = s.GetExtraWidth(1, 100); Assert.AreEqual(extra, 4); extra = s.GetExtraWidth(2, 100); Assert.AreEqual(extra, 0); tracks[0].Add(new TestSymbol(200, 6)); s = new SymbolWidths(tracks, null); extra = s.GetExtraWidth(0, 200); Assert.AreEqual(extra, 0); extra = s.GetExtraWidth(1, 200); Assert.AreEqual(extra, 6); extra = s.GetExtraWidth(2, 200); Assert.AreEqual(extra, 6); }