Click here to Skip to main content
Click here to Skip to main content

PSAM Control Library

, 24 Jun 2010
Rate this:
Please Sign up or sign in to vote.
WinForms library containing the IncipitViewer control for drawing musical notes

Introduction

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:

psam.jpg

PSAM Control Library official website is available at http://www.archiwistykamuzyczna.pl/index.php?article=download&lang=en#psamcontrollibrary.

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 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:

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:

incipitviewerbeams.png

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

incipitviewerbeamssingle.png

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

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:

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:

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:

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:

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:

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, along with any associated source code and files, is licensed under The BSD License

About the Author

Ajcek84

Poland Poland
I graduated from Adam Mickiewicz University in Poznań where I completed a MA degree in computer science (MA thesis: Analysis of Sound of Viola da Gamba and Human Voice and an Attempt of Comparison of Their Timbres Using Various Techniques of Digital Signal Analysis) and a bachelor degree in musicology (BA thesis: Continuity and Transitions in European Music Theory Illustrated by the Example of 3rd part of Zarlino's Institutioni Harmoniche and Bernhard's Tractatus Compositionis Augmentatus). I also graduated from a solo singing class in Fryderyk Chopin Musical School in Poznań. I'm a self-taught composer and a member of informal international group Vox Saeculorum, gathering composers, which common goal is to revive the old (mainly baroque) styles and composing traditions in contemporary written music. I'm the annual participant of International Summer School of Early Music in Lidzbark Warmiński.

Comments and Discussions

 
QuestionMeaning of "bool print" argument? Pinmembersigmundurus22-Aug-13 23:04 
AnswerRe: Meaning of "bool print" argument? PinmemberAjcek8423-Aug-13 1:55 
GeneralMy vote of 5 Pinmemberwmjordan21-Apr-13 15:07 
Questionwhat font must install ? Pinmemberenochenoch2k29-Nov-11 15:55 
AnswerRe: what font must install ? PinmemberAjcek8429-Nov-11 21:14 
GeneralRe: what font must install ? Pinmemberenochenoch2k30-Nov-11 2:17 
QuestionWonderful Project ! ! ! Pinmemberadam71815-Jul-11 17:59 
AnswerRe: Wonderful Project ! ! ! PinmemberAjcek8415-Jul-11 20:15 
GeneralRe: Wonderful Project ! ! ! Pinmemberadam71816-Jul-11 21:53 
GeneralRe: Wonderful Project ! ! ! PinmemberAjcek8424-Jul-11 2:53 
GeneralRe: Wonderful Project ! ! ! Pinmemberadam71825-Jul-11 4:24 
GeneralRe: Wonderful Project ! ! ! PinmemberAjcek8425-Jul-11 4:35 
This code fragment was too small to determine your problem. Besides, it missed declarations of incipitViewer and e so it wouldn't compile.
GeneralExcellent control and some suggestions PinmemberYuval Naveh2-Dec-10 18:29 
GeneralRe: Excellent control and some suggestions PinmemberAjcek842-Dec-10 21:22 
GeneralRe: Excellent control and some suggestions PinmemberYuval Naveh3-Dec-10 1:54 
GeneralRe: Excellent control and some suggestions PinmemberAjcek843-Dec-10 2:34 
GeneralRe: Excellent control and some suggestions PinmemberYuval Naveh3-Dec-10 2:46 
GeneralRe: Excellent control and some suggestions PinmemberAjcek843-Dec-10 4:11 
GeneralRe: Excellent control and some suggestions PinmemberAjcek844-Dec-10 6:29 
GeneralRe: Excellent control and some suggestions Pinmemberedgarmaass5-Jan-11 7:39 
GeneralRe: Excellent control and some suggestions PinmemberAjcek845-Jan-11 21:59 
GeneralMy vote of 5 Pinmemberherman60227-Sep-10 4:17 
GeneralMy vote of 5 PinmemberAbhinav S9-Jul-10 7:48 
GeneralAwesome PinmemberSike Mullivan23-Jun-10 3:35 
GeneralWOW! and double WOW!! PinmemberKenJohnson17-Jun-10 9:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 24 Jun 2010
Article Copyright 2010 by Ajcek84
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid