Browse Source

Update

master
ocsnetworks 2 years ago
commit
e590d92278
  1. 231
      Classes/AccidSymbol.cs
  2. 108
      Classes/Adler.cs
  3. 82
      Classes/BarSymbol.cs
  4. 75
      Classes/BlankSymbol.cs
  5. 1041
      Classes/ChordSymbol.cs
  6. 104
      Classes/ClefMeasures.cs
  7. 145
      Classes/ClefSymbol.cs
  8. 268
      Classes/ConfigINI.cs
  9. 41
      Classes/ExampleSheetMusicDLL.cs
  10. 178
      Classes/InstrumentDialog.cs
  11. 661
      Classes/KeySignature.cs
  12. 69
      Classes/LyricSymbol.cs
  13. 81
      Classes/MidiEvent.cs
  14. 1766
      Classes/MidiFile.cs
  15. 22
      Classes/MidiFileException.cs
  16. 161
      Classes/MidiFileReader.cs
  17. 101
      Classes/MidiNote.cs
  18. 295
      Classes/MidiOptions.cs
  19. 722
      Classes/MidiPlayer.cs
  20. 47
      Classes/MidiSheetMusic.cs
  21. 145
      Classes/MidiTrack.cs
  22. 56
      Classes/MusicSymbol.cs
  23. 253
      Classes/NoteColorDialog.cs
  24. 363
      Classes/PDFWithImages.cs
  25. 545
      Classes/Piano.cs
  26. 146
      Classes/PlayMeasuresDialog.cs
  27. 169
      Classes/RestSymbol.cs
  28. 191
      Classes/SampleSongDialog.cs
  29. 1209
      Classes/SheetMusic.cs
  30. 1966
      Classes/SheetMusicWindow.cs
  31. 536
      Classes/Staff.cs
  32. 456
      Classes/Stem.cs
  33. 122
      Classes/SymbolWidths.cs
  34. 119
      Classes/TimeSigSymbol.cs
  35. 168
      Classes/TimeSignature.cs
  36. 2240
      Classes/UnitTest.cs
  37. 239
      Classes/Volume.cs
  38. 210
      Classes/WhiteNote.cs
  39. 341
      LICENSE.txt
  40. 207
      MidiSheetMusic.csproj
  41. 20
      MidiSheetMusic.sln
  42. BIN
      MidiSheetMusic.suo
  43. BIN
      Resources/Images/NotePair.ico
  44. BIN
      Resources/Images/NotePair.png
  45. BIN
      Resources/Images/SmallNotePair.png
  46. BIN
      Resources/Images/Thumbs.db
  47. BIN
      Resources/Images/bass.png
  48. BIN
      Resources/Images/eight.png
  49. BIN
      Resources/Images/fastforward.png
  50. BIN
      Resources/Images/four.png
  51. BIN
      Resources/Images/logo.png
  52. BIN
      Resources/Images/midi_header.png
  53. BIN
      Resources/Images/midi_player.png
  54. BIN
      Resources/Images/nine.png
  55. BIN
      Resources/Images/pause.png
  56. BIN
      Resources/Images/play.png
  57. BIN
      Resources/Images/rewind.png
  58. BIN
      Resources/Images/save_as.png
  59. BIN
      Resources/Images/six.png
  60. BIN
      Resources/Images/stop.png
  61. BIN
      Resources/Images/three.png
  62. BIN
      Resources/Images/treble.png
  63. BIN
      Resources/Images/twelve.png
  64. BIN
      Resources/Images/two.png
  65. BIN
      Resources/Images/volume.png
  66. 774
      Resources/Localization/Strings.Designer.cs
  67. 288
      Resources/Localization/Strings.en.resx
  68. BIN
      Resources/Localization/Strings.resources
  69. 288
      Resources/Localization/Strings.resx
  70. 33
      Resources/Strings/AssemblyInfo.cs
  71. 197
      Resources/help.rtf
  72. BIN
      Resources/~$help.rtf
  73. 86
      SheetMusicDLL.csproj
  74. 87
      UnitTestDLL.csproj
  75. BIN
      bin/Debug/MidiSheetMusic.exe
  76. BIN
      bin/Debug/MidiSheetMusic.pdb
  77. BIN
      bin/Debug/MidiSheetMusic.vshost.exe
  78. 11
      bin/Debug/MidiSheetMusic.vshost.exe.manifest
  79. BIN
      bin/Debug/en/MidiSheetMusic.resources.dll
  80. BIN
      docs/Thumbs.db
  81. BIN
      docs/WindowDiagram.png
  82. BIN
      docs/android_icon.png
  83. BIN
      docs/blue_background.png
  84. BIN
      docs/choose_instruments.png
  85. BIN
      docs/choose_tracks.png
  86. BIN
      docs/kindle_fire_logo.png
  87. BIN
      docs/linux_icon.png
  88. BIN
      docs/mac_icon.png
  89. BIN
      docs/main_screenshot.png
  90. BIN
      docs/midi_logo.png
  91. 125
      docs/midisheetmusic.css
  92. BIN
      docs/note_colors.png
  93. BIN
      docs/note_letters.png
  94. BIN
      docs/piano_highlight.png
  95. BIN
      docs/screenshot.png
  96. BIN
      docs/sheet_highlight.png
  97. BIN
      docs/split_track.png
  98. BIN
      docs/symbol_diagram.png
  99. BIN
      docs/white_background.png
  100. BIN
      docs/win_icon.png
  101. Some files were not shown because too many files have changed in this diff Show More

231
Classes/AccidSymbol.cs

@ -0,0 +1,231 @@ @@ -0,0 +1,231 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace MidiSheetMusic {
/** Accidentals */
public enum Accid {
None, Sharp, Flat, Natural
}
/** @class AccidSymbol
* An accidental (accid) symbol represents a sharp, flat, or natural
* accidental that is displayed at a specific position (note and clef).
*/
public class AccidSymbol : MusicSymbol {
private Accid accid; /** The accidental (sharp, flat, natural) */
private WhiteNote whitenote; /** The white note where the symbol occurs */
private Clef clef; /** Which clef the symbols is in */
private int width; /** Width of symbol */
/**
* Create a new AccidSymbol with the given accidental, that is
* displayed at the given note in the given clef.
*/
public AccidSymbol(Accid accid, WhiteNote note, Clef clef) {
this.accid = accid;
this.whitenote = note;
this.clef = clef;
width = MinWidth;
}
/** Return the white note this accidental is displayed at */
public WhiteNote Note {
get { return whitenote; }
}
/** Get the time (in pulses) this symbol occurs at.
* Not used. Instead, the StartTime of the ChordSymbol containing this
* AccidSymbol is used.
*/
public override int StartTime {
get { return -1; }
}
/** Get the minimum width (in pixels) needed to draw this symbol */
public override int MinWidth {
get { return 3*SheetMusic.NoteHeight/2; }
}
/** Get/Set the width (in pixels) of this symbol. The width is set
* in SheetMusic.AlignSymbols() to vertically align symbols.
*/
public override int Width {
get { return width; }
set { width = value; }
}
/** Get the number of pixels this symbol extends above the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int AboveStaff {
get { return GetAboveStaff(); }
}
int GetAboveStaff() {
int dist = WhiteNote.Top(clef).Dist(whitenote) *
SheetMusic.NoteHeight/2;
if (accid == Accid.Sharp || accid == Accid.Natural)
dist -= SheetMusic.NoteHeight;
else if (accid == Accid.Flat)
dist -= 3*SheetMusic.NoteHeight/2;
if (dist < 0)
return -dist;
else
return 0;
}
/** Get the number of pixels this symbol extends below the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int BelowStaff {
get { return GetBelowStaff(); }
}
private int GetBelowStaff() {
int dist = WhiteNote.Bottom(clef).Dist(whitenote) *
SheetMusic.NoteHeight/2 +
SheetMusic.NoteHeight;
if (accid == Accid.Sharp || accid == Accid.Natural)
dist += SheetMusic.NoteHeight;
if (dist > 0)
return dist;
else
return 0;
}
/** Draw the symbol.
* @param ytop The ylocation (in pixels) where the top of the staff starts.
*/
public override void Draw(Graphics g, Pen pen, int ytop) {
/* Align the symbol to the right */
g.TranslateTransform(Width - MinWidth, 0);
/* Store the y-pixel value of the top of the whitenote in ynote. */
int ynote = ytop + WhiteNote.Top(clef).Dist(whitenote) *
SheetMusic.NoteHeight/2;
if (accid == Accid.Sharp)
DrawSharp(g, pen, ynote);
else if (accid == Accid.Flat)
DrawFlat(g, pen, ynote);
else if (accid == Accid.Natural)
DrawNatural(g, pen, ynote);
g.TranslateTransform(-(Width - MinWidth), 0);
}
/** Draw a sharp symbol.
* @param ynote The pixel location of the top of the accidental's note.
*/
public void DrawSharp(Graphics g, Pen pen, int ynote) {
/* Draw the two vertical lines */
int ystart = ynote - SheetMusic.NoteHeight;
int yend = ynote + 2*SheetMusic.NoteHeight;
int x = SheetMusic.NoteHeight/2;
pen.Width = 1;
g.DrawLine(pen, x, ystart + 2, x, yend);
x += SheetMusic.NoteHeight/2;
g.DrawLine(pen, x, ystart, x, yend - 2);
/* Draw the slightly upwards horizontal lines */
int xstart = SheetMusic.NoteHeight/2 - SheetMusic.NoteHeight/4;
int xend = SheetMusic.NoteHeight + SheetMusic.NoteHeight/4;
ystart = ynote + SheetMusic.LineWidth;
yend = ystart - SheetMusic.LineWidth - SheetMusic.LineSpace/4;
pen.Width = SheetMusic.LineSpace/2;
g.DrawLine(pen, xstart, ystart, xend, yend);
ystart += SheetMusic.LineSpace;
yend += SheetMusic.LineSpace;
g.DrawLine(pen, xstart, ystart, xend, yend);
pen.Width = 1;
}
/** Draw a flat symbol.
* @param ynote The pixel location of the top of the accidental's note.
*/
public void DrawFlat(Graphics g, Pen pen, int ynote) {
int x = SheetMusic.LineSpace/4;
/* Draw the vertical line */
pen.Width = 1;
g.DrawLine(pen, x, ynote - SheetMusic.NoteHeight - SheetMusic.NoteHeight/2,
x, ynote + SheetMusic.NoteHeight);
/* Draw 3 bezier curves.
* All 3 curves start and stop at the same points.
* Each subsequent curve bulges more and more towards
* the topright corner, making the curve look thicker
* towards the top-right.
*/
g.DrawBezier(pen, x, ynote + SheetMusic.LineSpace/4,
x + SheetMusic.LineSpace/2, ynote - SheetMusic.LineSpace/2,
x + SheetMusic.LineSpace, ynote + SheetMusic.LineSpace/3,
x, ynote + SheetMusic.LineSpace + SheetMusic.LineWidth + 1);
g.DrawBezier(pen, x, ynote + SheetMusic.LineSpace/4,
x + SheetMusic.LineSpace/2, ynote - SheetMusic.LineSpace/2,
x + SheetMusic.LineSpace + SheetMusic.LineSpace/4,
ynote + SheetMusic.LineSpace/3 - SheetMusic.LineSpace/4,
x, ynote + SheetMusic.LineSpace + SheetMusic.LineWidth + 1);
g.DrawBezier(pen, x, ynote + SheetMusic.LineSpace/4,
x + SheetMusic.LineSpace/2, ynote - SheetMusic.LineSpace/2,
x + SheetMusic.LineSpace + SheetMusic.LineSpace/2,
ynote + SheetMusic.LineSpace/3 - SheetMusic.LineSpace/2,
x, ynote + SheetMusic.LineSpace + SheetMusic.LineWidth + 1);
}
/** Draw a natural symbol.
* @param ynote The pixel location of the top of the accidental's note.
*/
public void DrawNatural(Graphics g, Pen pen, int ynote) {
/* Draw the two vertical lines */
int ystart = ynote - SheetMusic.LineSpace - SheetMusic.LineWidth;
int yend = ynote + SheetMusic.LineSpace + SheetMusic.LineWidth;
int x = SheetMusic.LineSpace/2;
pen.Width = 1;
g.DrawLine(pen, x, ystart, x, yend);
x += SheetMusic.LineSpace - SheetMusic.LineSpace/4;
ystart = ynote - SheetMusic.LineSpace/4;
yend = ynote + 2*SheetMusic.LineSpace + SheetMusic.LineWidth -
SheetMusic.LineSpace/4;
g.DrawLine(pen, x, ystart, x, yend);
/* Draw the slightly upwards horizontal lines */
int xstart = SheetMusic.LineSpace/2;
int xend = xstart + SheetMusic.LineSpace - SheetMusic.LineSpace/4;
ystart = ynote + SheetMusic.LineWidth;
yend = ystart - SheetMusic.LineWidth - SheetMusic.LineSpace/4;
pen.Width = SheetMusic.LineSpace/2;
g.DrawLine(pen, xstart, ystart, xend, yend);
ystart += SheetMusic.LineSpace;
yend += SheetMusic.LineSpace;
g.DrawLine(pen, xstart, ystart, xend, yend);
pen.Width = 1;
}
public override string ToString() {
return string.Format(
"AccidSymbol accid={0} whitenote={1} clef={2} width={3}",
accid, whitenote, clef, width);
}
}
}

108
Classes/Adler.cs

@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
// -----------------------------------------------------------------------
//
// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
//
// The ZLIB software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Jean-loup Gailly jloup@gzip.org
// Mark Adler madler@alumni.caltech.edu
//
// -----------------------------------------------------------------------
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
using System;
namespace MidiSheetMusic {
public sealed class Adler
{
// largest prime smaller than 65536
private static readonly uint BASE = 65521;
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
private static readonly int NMAX = 5552;
public static uint Adler32(byte[] buf) {
uint result = Adler32(0, null, 0, 0);
result = Adler32(result, buf, 0, buf.Length);
return result;
}
public static uint Adler32(uint adler, byte[] buf, int index, int len)
{
if (buf == null)
return 1;
uint s1 = (uint) (adler & 0xffff);
uint s2 = (uint) ((adler >> 16) & 0xffff);
while (len > 0)
{
int k = len < NMAX ? len : NMAX;
len -= k;
while (k >= 16)
{
//s1 += (buf[index++] & 0xff); s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
k -= 16;
}
if (k != 0)
{
do
{
s1 += buf[index++];
s2 += s1;
}
while (--k != 0);
}
s1 %= BASE;
s2 %= BASE;
}
return (uint)((s2 << 16) | s1);
}
}
}

82
Classes/BarSymbol.cs

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace MidiSheetMusic {
/** @class BarSymbol
* The BarSymbol represents the vertical bars which delimit measures.
* The starttime of the symbol is the beginning of the new
* measure.
*/
public class BarSymbol : MusicSymbol {
private int starttime;
private int width;
/** Create a BarSymbol. The starttime should be the beginning of a measure. */
public BarSymbol(int starttime) {
this.starttime = starttime;
width = MinWidth;
}
/** Get the time (in pulses) this symbol occurs at.
* This is used to determine the measure this symbol belongs to.
*/
public override int StartTime {
get { return starttime; }
}
/** Get the minimum width (in pixels) needed to draw this symbol */
public override int MinWidth {
get { return 2 * SheetMusic.LineSpace; }
}
/** Get/Set the width (in pixels) of this symbol. The width is set
* in SheetMusic.AlignSymbols() to vertically align symbols.
*/
public override int Width {
get { return width; }
set { width = value; }
}
/** Get the number of pixels this symbol extends above the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int AboveStaff {
get { return 0; }
}
/** Get the number of pixels this symbol extends below the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int BelowStaff {
get { return 0; }
}
/** Draw a vertical bar.
* @param ytop The ylocation (in pixels) where the top of the staff starts.
*/
public override
void Draw(Graphics g, Pen pen, int ytop) {
int y = ytop;
int yend = y + SheetMusic.LineSpace*4 + SheetMusic.LineWidth*4;
pen.Width = 1;
g.DrawLine(pen, SheetMusic.NoteWidth/2, y,
SheetMusic.NoteWidth/2, yend);
}
public override string ToString() {
return string.Format("BarSymbol starttime={0} width={1}",
starttime, width);
}
}
}

75
Classes/BlankSymbol.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace MidiSheetMusic {
/** @class BlankSymbol
* The Blank symbol is a music symbol that doesn't draw anything. This
* symbol is used for alignment purposes, to align notes in different
* staffs which occur at the same time.
*/
public class BlankSymbol : MusicSymbol {
private int starttime;
private int width;
/** Create a new BlankSymbol with the given starttime and width */
public BlankSymbol(int starttime, int width) {
this.starttime = starttime;
this.width = width;
}
/** Get the time (in pulses) this symbol occurs at.
* This is used to determine the measure this symbol belongs to.
*/
public override int StartTime {
get { return starttime; }
}
/** Get the minimum width (in pixels) needed to draw this symbol */
public override int MinWidth {
get { return 0; }
}
/** Get/Set the width (in pixels) of this symbol. The width is set
* in SheetMusic.AlignSymbols() to vertically align symbols.
*/
public override int Width {
get { return width; }
set { width = value; }
}
/** Get the number of pixels this symbol extends above the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int AboveStaff {
get { return 0; }
}
/** Get the number of pixels this symbol extends below the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int BelowStaff {
get { return 0; }
}
/** Draw nothing.
* @param ytop The ylocation (in pixels) where the top of the staff starts.
*/
public override void Draw(Graphics g, Pen pen, int ytop) {}
public override string ToString() {
return string.Format("BlankSymbol starttime={0} width={1}",
starttime, width);
}
}
}

1041
Classes/ChordSymbol.cs

File diff suppressed because it is too large Load Diff

104
Classes/ClefMeasures.cs

@ -0,0 +1,104 @@ @@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
namespace MidiSheetMusic {
/** @class ClefMeasures
* The ClefMeasures class is used to report what Clef (Treble or Bass) a
* given measure uses.
*/
public class ClefMeasures {
private List<Clef> clefs; /** The clefs used for each measure (for a single track) */
private int measure; /** The length of a measure, in pulses */
/** Given the notes in a track, calculate the appropriate Clef to use
* for each measure. Store the result in the clefs list.
* @param notes The midi notes
* @param measurelen The length of a measure, in pulses
*/
public ClefMeasures(List<MidiNote> notes, int measurelen) {
measure = measurelen;
Clef mainclef = MainClef(notes);
int nextmeasure = measurelen;
int pos = 0;
Clef clef = mainclef;
clefs = new List<Clef>();
while (pos < notes.Count) {
/* Sum all the notes in the current measure */
int sumnotes = 0;
int notecount = 0;
while (pos < notes.Count && notes[pos].StartTime < nextmeasure) {
sumnotes += notes[pos].Number;
notecount++;
pos++;
}
if (notecount == 0)
notecount = 1;
/* Calculate the "average" note in the measure */
int avgnote = sumnotes / notecount;
if (avgnote == 0) {
/* This measure doesn't contain any notes.
* Keep the previous clef.
*/
}
else if (avgnote >= WhiteNote.BottomTreble.Number()) {
clef = Clef.Treble;
}
else if (avgnote <= WhiteNote.TopBass.Number()) {
clef = Clef.Bass;
}
else {
/* The average note is between G3 and F4. We can use either
* the treble or bass clef. Use the "main" clef, the clef
* that appears most for this track.
*/
clef = mainclef;
}
clefs.Add(clef);
nextmeasure += measurelen;
}
clefs.Add(clef);
}
/** Given a time (in pulses), return the clef used for that measure. */
public Clef GetClef(int starttime) {
/* If the time exceeds the last measure, return the last measure */
if (starttime / measure >= clefs.Count) {
return clefs[ clefs.Count-1 ];
}
else {
return clefs[ starttime / measure ];
}
}
/** Calculate the best clef to use for the given notes. If the
* average note is below Middle C, use a bass clef. Else, use a treble
* clef.
*/
private static Clef MainClef(List<MidiNote> notes) {
int middleC = WhiteNote.MiddleC.Number();
int total = 0;
foreach (MidiNote m in notes) {
total += m.Number;
}
if (notes.Count == 0) {
return Clef.Treble;
}
else if (total/notes.Count >= middleC) {
return Clef.Treble;
}
else {
return Clef.Bass;
}
}
}
}

145
Classes/ClefSymbol.cs

@ -0,0 +1,145 @@ @@ -0,0 +1,145 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace MidiSheetMusic {
/** The possible clefs, Treble or Bass */
public enum Clef { Treble, Bass };
/** @class ClefSymbol
* A ClefSymbol represents either a Treble or Bass Clef image.
* The clef can be either normal or small size. Normal size is
* used at the beginning of a new staff, on the left side. The
* small symbols are used to show clef changes within a staff.
*/
public class ClefSymbol : MusicSymbol {
private static Image treble; /** The treble clef image */
private static Image bass; /** The bass clef image */
private int starttime; /** Start time of the symbol */
private bool smallsize; /** True if this is a small clef, false otherwise */
private Clef clef; /** The clef, Treble or Bass */
private int width;
/** Create a new ClefSymbol, with the given clef, starttime, and size */
public ClefSymbol(Clef clef, int starttime, bool small) {
this.clef = clef;
this.starttime = starttime;
smallsize = small;
LoadImages();
width = MinWidth;
}
/** Load the Treble/Bass clef images into memory. */
private static void LoadImages() {
if (treble == null)
treble = new Bitmap(typeof(ClefSymbol), "Resources.Images.treble.png");
if (bass == null)
bass = new Bitmap(typeof(ClefSymbol), "Resources.Images.bass.png");
}
/** Get the time (in pulses) this symbol occurs at.
* This is used to determine the measure this symbol belongs to.
*/
public override int StartTime {
get { return starttime; }
}
/** Get the minimum width (in pixels) needed to draw this symbol */
public override int MinWidth {
get {
if (smallsize)
return SheetMusic.NoteWidth * 2;
else
return SheetMusic.NoteWidth * 3;
}
}
/** Get/Set the width (in pixels) of this symbol. The width is set
* in SheetMusic.AlignSymbols() to vertically align symbols.
*/
public override int Width {
get { return width; }
set { width = value; }
}
/** Get the number of pixels this symbol extends above the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int AboveStaff {
get {
if (clef == Clef.Treble && !smallsize)
return SheetMusic.NoteHeight * 2;
else
return 0;
}
}
/** Get the number of pixels this symbol extends below the staff. Used
* to determine the minimum height needed for the staff (Staff.FindBounds).
*/
public override int BelowStaff {
get {
if (clef == Clef.Treble && !smallsize)
return SheetMusic.NoteHeight * 2;
else if (clef == Clef.Treble && smallsize)
return SheetMusic.NoteHeight;
else
return 0;
}
}
/** Draw the symbol.
* @param ytop The ylocation (in pixels) where the top of the staff starts.
*/
public override
void Draw(Graphics g, Pen pen, int ytop) {
g.TranslateTransform(Width - MinWidth, 0);
int y = ytop;
Image image;
int height;
/* Get the image, height, and top y pixel, depending on the clef
* and the image size.
*/
if (clef == Clef.Treble) {
image = treble;
if (smallsize) {
height = SheetMusic.StaffHeight + SheetMusic.StaffHeight/4;
} else {
height = 3 * SheetMusic.StaffHeight/2 + SheetMusic.NoteHeight/2;
y = ytop - SheetMusic.NoteHeight;
}
}
else {
image = bass;
if (smallsize) {
height = SheetMusic.StaffHeight - 3*SheetMusic.NoteHeight/2;
} else {
height = SheetMusic.StaffHeight - SheetMusic.NoteHeight;
}
}
/* Scale the image width to match the height */
int imgwidth = image.Width * height / image.Height;
g.DrawImage(image, 0, y, imgwidth, height);
g.TranslateTransform(-(Width - MinWidth), 0);
}
public override string ToString() {
return string.Format("ClefSymbol clef={0} small={1} width={2}",
clef, smallsize, width);
}
}
}

268
Classes/ConfigINI.cs

@ -0,0 +1,268 @@ @@ -0,0 +1,268 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace MidiSheetMusic {
/** @class ConfigINI
*
* The ConfigINI class represents an INI configuration file.
* The file format is:
*
* [section name]
* name1=value1
* name2=value2
*
* [section2 name]
* name1=value1
* name2=value2
*
*/
public class SectionINI {
public string Section; /* The section title */
public Dictionary<string,string> Properties; /* The section name/value properties */
public SectionINI() {
Properties = new Dictionary<string,string>();
}
static Color ParseColor(string value) {
try {
string[] rgb = value.Split(new Char[] {' '} );
if (rgb != null && rgb.Length == 3) {
Color color = Color.FromArgb( Int32.Parse(rgb[0]), Int32.Parse(rgb[1]), Int32.Parse(rgb[2]) );
return color;
}
return Color.White;
}
catch (Exception e) {
return Color.White;
}
}
public string GetString(string key) {
if (Properties.ContainsKey(key)) {
return Properties[key];
}
else {
return null;
}
}
public bool GetBool(string key) {
try {
string value = Properties[key];
bool boolvalue = Boolean.Parse(value);
return boolvalue;
}
catch (Exception e) {
return false;
}
}
public int GetInt(string key) {
try {
string value = Properties[key];
int intvalue = Int32.Parse(value);
return intvalue;
}
catch (Exception e) {
return 0;
}
}
public Color GetColor(string key) {
try {
string value = Properties[key];
return ParseColor(value);
}
catch (Exception e) {
return Color.White;
}
}
public string[] GetArray(string key) {
try {
string value = Properties[key];
return value.Split(new Char[] {','} );
}
catch (Exception e) {
return null;
}
}
public bool[] GetBoolArray(string key) {
string[] strarray = GetArray(key);
if (strarray == null) {
return null;
}
bool[] result = new bool[strarray.Length];
for (int i = 0; i < result.Length; i++) {
try {
result[i] = Boolean.Parse(strarray[i]);
}
catch (Exception e) {}
}
return result;
}
public int[] GetIntArray(string key) {
string[] strarray = GetArray(key);
if (strarray == null) {
return null;
}
int[] result = new int[strarray.Length];
for (int i = 0; i < result.Length; i++) {
try {
result[i] = Int32.Parse(strarray[i]);
}
catch (Exception e) {}
}
return result;
}
public Color[] GetColorArray(string key) {
string[] strarray = GetArray(key);
if (strarray == null) {
return null;
}
Color[] result = new Color[strarray.Length];
for (int i = 0; i < result.Length; i++) {
Color c = ParseColor(strarray[i]);
if (c == Color.White) {
return null;
}
result[i] = c;
}
return result;
}
}
public class ConfigINI {
private string filename;
private List<SectionINI> sections;
public ConfigINI(string filename) {
this.filename = filename;
Load();
}
/* Load and parse the INI file into a dictionary mapping
* section titles to the name/value pairs under the section.
*/
void Load() {
sections = new List<SectionINI>();
try {
StreamReader stream = new StreamReader(filename);
string line = null;
SectionINI section = null;
while ( (line = stream.ReadLine()) != null) {
if (line == "" || line.StartsWith(";")) {
continue;
}
else if (line.StartsWith("[")) {
string title = line.Replace("[", "").Replace("]", "");
section = new SectionINI();
section.Section = title;
sections.Add(section);
}
else {
string[] pair = line.Split(new Char[] {'='} );
if (pair != null && pair.Length == 2 && section != null) {
string key = pair[0]; string value = pair[1];
section.Properties[key] = value;
}
}
}
stream.Close();
}
catch (Exception e) {
}
}
/* Save the most recent 20 sections */
public void Save() {
int maxsections = 20;
try {
StreamWriter stream = new StreamWriter(filename, false);
for (int i = 0; i < sections.Count; i++) {
if (i >= maxsections) {
break;
}
SectionINI section = sections[i];
stream.WriteLine("[" + section.Section + "]");
foreach (string key in section.Properties.Keys) {
stream.WriteLine(key + "=" + section.Properties[key]);
}
stream.WriteLine();
}
stream.Flush();
stream.Close();
}
catch (Exception e) {
}
}
/* Retrieve the section with the given title.
* If found, move that section to the front of the list.
*/
public SectionINI GetSection(string title) {
SectionINI match = null;
foreach (SectionINI section in sections) {
if (section.Section == title) {
match = section; break;
}
}
if (match != null) {
sections.Remove(match);
sections.Insert(0, match);
}
return match;
}
/* Return the first section */
public SectionINI FirstSection() {
if (sections.Count > 0) {
return sections[0];
}
else {
return null;
}
}
/* Add the given section to the Config INI, and save it to disk */
public void AddSection(SectionINI section) {
for (int i = 0; i < sections.Count; i++) {
if (sections[i].Section == section.Section) {
sections.RemoveAt(i);
i--;
}
}
sections.Insert(0, section);
}
/* Return a list of the first 10 filenames */
public List<string> GetRecentFilenames() {
List<string> result = new List<string>();
int total = 0;
foreach (SectionINI section in sections) {
if (section.GetString("filename") != null) {
result.Add(section.GetString("filename"));
total++;
}
if (total >= 10) {
break;
}
}
return result;
}
}
}

41
Classes/ExampleSheetMusicDLL.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* Copyright (c) 2007-2011 Madhav Vaidyanathan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/** An example of using just the SheetMusic.dll library.
* To compile run:
* # csc /target:exe ExampleSheetMusicDLL.cs /reference:SheetMusic.dll
* # ExampleSheetMusicDLL.exe sample.mid
*/
using System;
using System.Windows.Forms;
using System.Drawing;
using MidiSheetMusic;
public class ExampleSheetMusicDLL {
[STAThread]
public static void Main(string[] argv) {
if (argv.Length < 1) {
Console.WriteLine("Usage: ExampleSheetMusicDLL filename.mid");
return;
}
string filename = argv[0];
Form form = new Form();
SheetMusic sheet = new SheetMusic(filename, null);
sheet.Parent = form;
form.Size = new Size(600, 400);
form.AutoScroll = true;
Application.Run(form);
}
}

178
Classes/InstrumentDialog.cs

@ -0,0 +1,178 @@ @@ -0,0 +1,178 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using MidiSheetMusic.Resources.Localization;
namespace MidiSheetMusic {
/** @class InstrumentDialog
* The InstrumentDialog is used to select what instrument to use
* for each track, when playing the music.
*/
public class InstrumentDialog {
private ComboBox[] instrumentChoices; /** The instruments to use per track */
private Form dialog; /** The dialog box */
/** Create a new InstrumentDialog. Call the ShowDialog() method
* to display the dialog.
*/
public InstrumentDialog(MidiFile midifile) {
/* Create the dialog box */
dialog = new Form();
Font font = dialog.Font;
dialog.Font = new Font(font.FontFamily, font.Size * 1.4f);
int unit = dialog.Font.Height;
int xstart = unit * 2;
int ystart = unit * 2;
int labelheight = unit * 2;
int maxwidth = 0;
dialog.Text = Strings.chooseInstrumentsTitle;
dialog.MaximizeBox = false;
dialog.MinimizeBox = false;
dialog.ShowInTaskbar = false;
dialog.Icon = new Icon(GetType(), "Resources.Images.NotePair.ico");
dialog.AutoScroll = true;
List<MidiTrack> tracks = midifile.Tracks;
instrumentChoices = new ComboBox[tracks.Count];
/* For each midi track, create a label with the track number
* ("Track 2"), and a ComboBox containing all the possible
* midi instruments. Add the text "(default)" to the instrument
* specified in the midi file.
*/
for (int i = 0; i < tracks.Count; i++) {
int num = i+1;
Label label = new Label();
label.Parent = dialog;
label.Text = "Track " + num;
label.TextAlign = ContentAlignment.MiddleRight;
label.Location = new Point(xstart, ystart + i*labelheight);
label.AutoSize = true;
maxwidth = Math.Max(maxwidth, label.Width);
}
for (int i = 0; i < tracks.Count; i++) {
instrumentChoices[i] = new ComboBox();
instrumentChoices[i].DropDownStyle = ComboBoxStyle.DropDownList;
instrumentChoices[i].Parent = dialog;
instrumentChoices[i].Location = new Point(xstart + maxwidth * 3/2, ystart + i*labelheight);
instrumentChoices[i].Size = new Size(labelheight * 8, labelheight);
for (int instr = 0; instr < MidiFile.Instruments.Length; instr++) {
string name = MidiFile.Instruments[instr];
if (tracks[i].Instrument == instr) {
name += " (default)";
}
instrumentChoices[i].Items.Add(name);
}
instrumentChoices[i].SelectedIndex = tracks[i].Instrument;
}
/* Create the "Set All To Piano" button */
Button allPiano = new Button();
allPiano.Parent = dialog;
allPiano.Text = Strings.setAllPiano;
allPiano.Location = new Point(xstart + maxwidth * 3/2,
ystart + tracks.Count * labelheight);
allPiano.Click += new EventHandler(SetAllPiano);
allPiano.Size = new Size(labelheight * 5, labelheight);
/* Create the OK and Cancel buttons */
int ypos = ystart + (tracks.Count + 3) * labelheight;
Button ok = new Button();
ok.Parent = dialog;
ok.Text = Strings.okButton;
ok.Location = new Point(xstart, ypos);
ok.DialogResult = DialogResult.OK;
Button cancel = new Button();
cancel.Parent = dialog;
cancel.Text = Strings.cancelButton;
cancel.Location = new Point(ok.Location.X + ok.Width + labelheight/2, ypos);
cancel.DialogResult = DialogResult.Cancel;
dialog.Size = new Size(instrumentChoices[0].Location.X + instrumentChoices[0].Width + 50,
cancel.Location.Y + cancel.Size.Height + 50);
}
/** Display the InstrumentDialog.
* Return DialogResult.OK if "OK" was clicked.
* Return DialogResult.Cancel if "Cancel" was clicked.
*/
public DialogResult ShowDialog() {
int[] oldInstruments = this.GetInstruments();
DialogResult result = dialog.ShowDialog();
if (result == DialogResult.Cancel) {
/* If the user clicks 'Cancel', restore the old instruments */
for (int i = 0; i < instrumentChoices.Length; i++) {
instrumentChoices[i].SelectedIndex = oldInstruments[i];
}
}
return result;
}
/** Set all the instrument choices to "Acoustic Grand Piano",
* unless the instrument is Percussion (128).
*/
private void SetAllPiano(object sender, EventArgs args) {
for (int i = 0; i < instrumentChoices.Length; i++) {
if (instrumentChoices[i].SelectedIndex != 128) {
instrumentChoices[i].SelectedIndex = 0;
}
}
}
public void Dispose() {
dialog.Dispose();
}
/** Get the instruments currently selected */
public int[] Instruments {
get { return GetInstruments(); }
set { SetInstruments(value); }
}
int[] GetInstruments() {
int[] result = new int[ instrumentChoices.Length ];
for (int i = 0; i < instrumentChoices.Length; i++) {
if (instrumentChoices[i].SelectedIndex == -1) {
instrumentChoices[i].SelectedIndex = 0;
}
result[i] = instrumentChoices[i].SelectedIndex;
}
return result;
}
/** Set the selected instruments */
void SetInstruments(int[] values) {
if (values == null || values.Length != instrumentChoices.Length) {
return;
}
for (int i = 0; i < values.Length; i++) {
instrumentChoices[i].SelectedIndex = values[i];
}
}
/** Return true if all the default instruments are selected */
public bool isDefault() {
bool result = true;
for (int i = 0; i < instrumentChoices.Length; i++) {
if (instrumentChoices[i].SelectedIndex == -1) {
instrumentChoices[i].SelectedIndex = 0;
}
string name = (string) instrumentChoices[i].SelectedItem;
if (!name.Contains("default")) {
result = false;
}
}
return result;
}
}
}

661
Classes/KeySignature.cs

@ -0,0 +1,661 @@ @@ -0,0 +1,661 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace MidiSheetMusic {
/** @class KeySignature
* The KeySignature class represents a key signature, like G Major
* or B-flat Major. For sheet music, we only care about the number
* of sharps or flats in the key signature, not whether it is major
* or minor.
*
* The main operations of this class are:
* - Guessing the key signature, given the notes in a song.
* - Generating the accidental symbols for the key signature.
* - Determining whether a particular note requires an accidental
* or not.
*
*/
public class KeySignature {
/** The number of sharps in each key signature */
public const int C = 0;
public const int G = 1;
public const int D = 2;
public const int A = 3;
public const int E = 4;
public const int B = 5;
/** The number of flats in each key signature */
public const int F = 1;
public const int Bflat = 2;
public const int Eflat = 3;
public const int Aflat = 4;
public const int Dflat = 5;
public const int Gflat = 6;
/** The two arrays below are key maps. They take a major key
* (like G major, B-flat major) and a note in the scale, and
* return the Accidental required to display that note in the
* given key. In a nutshel, the map is
*
* map[Key][NoteScale] -> Accidental
*/
private static Accid[][] sharpkeys;
private static Accid[][] flatkeys;
private int num_flats; /** The number of sharps in the key, 0 thru 6 */
private int num_sharps; /** The number of flats in the key, 0 thru 6 */
/** The accidental symbols that denote this key, in a treble clef */
private AccidSymbol[] treble;
/** The accidental symbols that denote this key, in a bass clef */
private AccidSymbol[] bass;
/** The key map for this key signature:
* keymap[notenumber] -> Accidental
*/
private Accid[] keymap;
/** The measure used in the previous call to GetAccidental() */
private int prevmeasure;
/** Create new key signature, with the given number of
* sharps and flats. One of the two must be 0, you can't
* have both sharps and flats in the key signature.
*/
public KeySignature(int num_sharps, int num_flats) {
if (!(num_sharps == 0 || num_flats == 0)) {
throw new System.ArgumentException("Bad KeySigature args");
}
this.num_sharps = num_sharps;
this.num_flats = num_flats;
CreateAccidentalMaps();
keymap = new Accid[160];
ResetKeyMap();
CreateSymbols();
}
/** Create new key signature, with the given notescale. */
public KeySignature(int notescale) {
num_sharps = num_flats = 0;
switch (notescale) {
case NoteScale.A: num_sharps = 3; break;
case NoteScale.Bflat: num_flats = 2; break;
case NoteScale.B: num_sharps = 5; break;
case NoteScale.C: break;
case NoteScale.Dflat: num_flats = 5; break;
case NoteScale.D: num_sharps = 2; break;
case NoteScale.Eflat: num_flats = 3; break;
case NoteScale.E: num_sharps = 4; break;
case NoteScale.F: num_flats = 1; break;
case NoteScale.Gflat: num_flats = 6; break;
case NoteScale.G: num_sharps = 1; break;
case NoteScale.Aflat: num_flats = 4; break;
default: break;
}
CreateAccidentalMaps();
keymap = new Accid[160];
ResetKeyMap();
CreateSymbols();
}
/** Iniitalize the sharpkeys and flatkeys maps */
private static void CreateAccidentalMaps() {
if (sharpkeys != null)
return;
Accid[] map;
sharpkeys = new Accid[8][];
flatkeys = new Accid[8][];
for (int i = 0; i < 8; i++) {
sharpkeys[i] = new Accid[12];
flatkeys[i] = new Accid[12];
}
map = sharpkeys[C];
map[ NoteScale.A ] = Accid.None;
map[ NoteScale.Asharp ] = Accid.Flat;
map[ NoteScale.B ] = Accid.None;
map[ NoteScale.C ] = Accid.None;
map[ NoteScale.Csharp ] = Accid.Sharp;
map[ NoteScale.D ] = Accid.None;
map[ NoteScale.Dsharp ] = Accid.Sharp;
map[ NoteScale.E ] = Accid.None;
map[ NoteScale.F ] = Accid.None;
map[ NoteScale.Fsharp ] = Accid.Sharp;
map[ NoteScale.G ] = Accid.None;
map[ NoteScale.Gsharp ] = Accid.Sharp;
map = sharpkeys[G];
map[ NoteScale.A ] = Accid.None;
map[ NoteScale.Asharp ] = Accid.Flat;
map[ NoteScale.B ] = Accid.None;
map[ NoteScale.C ] = Accid.None;
map[ NoteScale.Csharp ] = Accid.Sharp;
map[ NoteScale.D ] = Accid.None;
map[ NoteScale.Dsharp ] = Accid.Sharp;
map[ NoteScale.E ] = Accid.None;
map[ NoteScale.F ] = Accid.Natural;
map[ NoteScale.Fsharp ] = Accid.None;
map[ NoteScale.G ] = Accid.None;
map[ NoteScale.Gsharp ] = Accid.Sharp;
map = sharpkeys[D];
map[ NoteScale.A ] = Accid.None;
map[ NoteScale.Asharp ] = Accid.Flat;
map[ NoteScale.B ] = Accid.None;
map[ NoteScale.C ] = Accid.Natural;
map[ NoteScale.Csharp ] = Accid.None;
map[ NoteScale.D ] = Accid.None;
map[ NoteScale.Dsharp ] = Accid.Sharp;
map[ NoteScale.E ] = Accid.None;
map[ NoteScale.F ] = Accid.Natural;
map[ NoteScale.Fsharp ] = Accid.None;
map[ NoteScale.G ] = Accid.None;
map[ NoteScale.Gsharp ] = Accid.Sharp;
map = sharpkeys[A];
map[ NoteScale.A ] = Accid.None;
map[ NoteScale.Asharp ] = Accid.Flat;
map[ NoteScale.B ] = Accid.None;
map[ NoteScale.C ] = Accid.Natural;
map[ NoteScale.Csharp ] = Accid.None;
map[ NoteScale.D ] = Accid.None;
map[ NoteScale.Dsharp ] = Accid.Sharp;
map[ NoteScale.E ] = Accid.None;
map[ NoteScale.F ] = Accid.Natural;
map[ NoteScale.