commit
e590d92278
178 changed files with 17807 additions and 0 deletions
@ -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); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
|
@ -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); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -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); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -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); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
@ -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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -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); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -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; |
||||
} |
||||
} |
||||
|
||||
} |
@ -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); |
||||
} |
||||
} |
||||
|
||||
|
@ -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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
@ -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. |