Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

PSAM Control Library

0.00/5 (No votes)
19 Jul 2018 16  
WinForms library containing the IncipitViewer control for drawing musical notes

Introduction

UPDATE: This article describes an old .NET project which eventually evolved into bigger open source framework Manufaktura.Controls. You can read about it here: https://www.codeproject.com/Articles/1252423/Music-Notation-in-NET 

PSAM Control Library is a WinForms library containing the IncipitViewer control for drawing musical notes which can be read from MusicXml file or added programmatically. The library was initially a component of larger software Polish System for Archivising Music (http://www.archiwistykamuzyczna.pl/?lang=en) but I thought it could be useful for other software developers, so I decided to distribute it under BSD licence. PSAM Control Library is written in C# under Microsoft Visual Studio Express.

The following screen illustrates the use of many IncipitViewer controls in a manuscript database application:

psamcontrollibrary/psam.jpg

PSAM Control Library official website is available at http://musicengravingcontrols.com/.

Using the Code

IncipitViewer control requires a special font to draw notes and other musical symbols. You can create your own font or use the included font Polihymnia which is based on Ben Laenen's Euterpe font and distributed under Sil Open Font Licence. Of course you have to install the font in your fonts directory to display notes properly.

The simplest way to add IncipitViewer control to your project is to drag and drop the PSAMControlLibrary.dll file to your Toolbox and then drag and drop the IncipitViewer control to your form. You can also create an IncipitViewer control programmatically, for example:

IncipitViewer viewer = new IncipitViewer();
viewer.Dock = DockStyle.Fill;
Controls.Add(viewer);  

Remember to add using <code>PSAMControlLibrary; directive to your code.

To read music from MusicXml file use LoadFromXmlFile(string fileName) method and as an argument, type the path of the XML file that you wish to open. Remember that only the first stave is supported - other staves will be skipped.

viewer.LoadFromXmlFile("example.xml"); 

The effect of the above code should look like that:

psamcontrollibrary/incipitviewerxml.png

To clear the staff, use the ClearMusicalIncipit() method:

viewer.ClearMusicalIncipit(); 

We can also add notes and musical symbols programmatically. First we will add the G clef on line 2:

Clef c = new Clef(ClefType.GClef, 2);
viewer.AddMusicalSymbol(c); 

Then we will add a new quarter note G:

Note n = new Note("G", 0, 4, MusicalSymbolDuration.Quarter,
  NoteStemDirection.Up, NoteTieType.None,
  new List<NoteBeamType>() {NoteBeamType.Single});
viewer.AddMusicalSymbol(n);

The first argument of Note constructor is a string representing one of the following names of steps: A, B, C, D, E, F, G. The second argument is number of sharps (positive number) or flats (negative number) where 0 means no alteration. The third argument is the number of an octave. The next arguments are: duration of the note, stem direction and type of tie (NoteTieType.None if the note is not tied). The last argument is a list of beams. If the note doesn't have any beams, it must still have that list with just one element NoteBeamType.Single (even if duration of the note is greater than eighth). To make it clear how beamlists work, let's try to add a group of two beamed sixteenths and eighth:

Note s1 = new Note("A", 0, 4, MusicalSymbolDuration.Sixteenth, 
		NoteStemDirection.Down, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.Start, NoteBeamType.Start});
Note s2 = new Note("C", 1, 5, MusicalSymbolDuration.Sixteenth, 
		NoteStemDirection.Down, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.Continue, NoteBeamType.End });
Note e = new Note("D", 0, 5, MusicalSymbolDuration.Eighth, 
		NoteStemDirection.Down, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.End });
viewer.AddMusicalSymbol(s1);
viewer.AddMusicalSymbol(s2);
viewer.AddMusicalSymbol(e); 

The results should look like this:

psamcontrollibrary/incipitviewerbeams.png

And this is how the above example looks when all beams are set to NoteBeamType.Single:

psamcontrollibrary/incipitviewerbeamssingle.png

You can draw colored notes and musical symbols simply by changing their MusicalCharacterColor property:

psamcontrollibrary/colourfulnotes.png

Although IncipitViewer does not support multiple staves, it supports chords because they are part of many monophonic instruments' idiom. If IsChordElement property of a note is set to true, a note is treated as a chord element of the preceding note:

Note n1 = new Note("C", 0, 4, MusicalSymbolDuration.Half, 
		NoteStemDirection.Up, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.Single });
Note n2 = new Note("E", 0, 4, MusicalSymbolDuration.Half, 
		NoteStemDirection.Up, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.Single });
Note n3 = new Note("G", 0, 4, MusicalSymbolDuration.Half, 
		NoteStemDirection.Up, NoteTieType.None,
                	new List<NoteBeamType>() { NoteBeamType.Single });
n2.IsChordElement = true;
n3.IsChordElement = true;

viewer.AddMusicalSymbol(n1);
viewer.AddMusicalSymbol(n2);
viewer.AddMusicalSymbol(n3); 

Result:

psamcontrollibrary/examplechords.png

The following example shows how to insert dots, rests and barlines:

Note n4 = new Note("A", 0, 4, MusicalSymbolDuration.Half,
   NoteStemDirection.Up, NoteTieType.None,
               new List<NoteBeamType>() { NoteBeamType.Single });
           n4.NumberOfDots = 1;

           Rest r = new Rest(MusicalSymbolDuration.Quarter);
           Barline b = new Barline();

           viewer.AddMusicalSymbol(n4);
           viewer.AddMusicalSymbol(r);
           viewer.AddMusicalSymbol(b);

Result:

psamcontrollibrary/exampledotrestbarline.png

When the mouse is over the control, two buttons appear in the upper right corner: the first saves the MusicXml file associated with the control and the second invokes OnPlayExternalMidiPlayer event handler. You can subscribe PlayExternalMidiPlayer event:

viewer.PlayExternalMidiPlayer += 
	new IncipitViewer.PlayExternalMidiPlayerDelegate(viewer_PlayExternalMidiPlayer);

Create the following function for handling the event:

void viewer_PlayExternalMidiPlayer(IncipitViewer sender)
{
    //Place your code here
} 

In the above function, you can place a code to read notes from the control and use your own functions or another library to play them. To access the desired musical symbol from the control, use IncipitViewer.IncipitElement(int i) method where i is the index of the element. To convert a note to midi pitch, you can use a MusicalSymbol.ToMidiPitch (string step, int alter, int octave) method.

To print the content of IncipitViewer control, create a PrintDocument object and subscribe its PrintPage event:

private void printDocument1_PrintPage(object sender, 
	System.Drawing.Printing.PrintPageEventArgs e)
{
    Graphics g = e.Graphics;
    viewer.DrawViewer(g, true);
} 

Then print the document using the Print() method:

PrintDialog dlg = new PrintDialog();
dlg.Document = printDocument1;
if (dlg.ShowDialog() == DialogResult.OK)
{
     printDocument1.Print();
} 

Sample printout:

psamcontrollibrary/sample_print.png

Points of Interest

A curious thing connected with graphic layout of the score is the problem of determining the proper length of stems under beams. In 17th and 18th century printed music stems of equal length were very often in use which consequence was "breaking" of beams. Scores looked something like that:

psamcontrollibrary/gibbons.png

In contemporary music engraving however, beams must be straight. Unfortunately straight beams lead to variable length of stems and the proper length of stems must be determined programmatically. The following image demonstrates all values which we need to accomplish this:

psamcontrollibrary/stem_example.png

To determine the location of stem ending, we must find out the length of segment y1, which is a vertical distance between the stem ending of the last note in group and the stem ending of the note which interests us. Because:

tg alpha = y<sub>1</sub>/x<sub>1</sub>

then:

y<sub>1</sub> = x<sub>1</sub> * tg alpha  

Value of tg alpha is the ratio of the vertical distance between the stem endings of the first and last note in group and the horizontal distance between the stem endings of the first and last note in group (we assume that we know both values):

tg alpha = y / x

So:

y<sub>1</sub> = x<sub>1</sub> * (y / x) 

y1 is the vertical coordinate of the point of stem ending of the note that interests us.

History

In version 2.1.0.2, I added colored notes and made some changes in IncipitViewer class in order to allow porting this library to WPF. A WPF version of this library is available HERE.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here