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

PSAM WPF Control Library

By , 24 Jun 2010
 

Introduction

PSAM WPF Control Library is a WPF version of PSAM Control Library containing the IncipitViewer control for drawing musical notes which can be read from MusicXml file or added programmatically. PSAM WPF Control Library requires PSAM Control Library to run because it uses some of PSAM Control Library's classes. PSAM WPF Control Library is written in C# and XAML under Microsoft Visual Studio Express.

Using the Code

IncipitViewerWPF control requires 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.

You can load a MusicXml file or add notes programmatically the same way as it is done in PSAM Control Library. Read the article about PSAM Control Library for details.

The control looks like that:

example1.png

Because it's a WPF control, you can apply fancy effects like these:

example2.png

example3.png

Printing is even simpler than in PSAM Control Library. You just have to write the following code:

PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
     dialog.PrintVisual(viewer, "Test");
} 

where viewer is a IncipitViewerWPF control. Sample printout:

example4.png

Points of Interest

Porting PSAM Control Library to WPF was quite simple. I made some changes to PSAM Control Library, namely I added a new interface IIncipitViewer which represents IncipitViewer's methods and properties and then I implemented this interface in IncipitViewerWPF class. I also moved ParseXml method from IncipitViewer to a new class called XmlParser so I didn't have to rewrite this method in IncipitViewerWPF class. To draw notes and musical symbols, I use an overridden OnRender method and a DrawingContext object.

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

Ajcek84
Poland Poland
Member
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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionRefactoring & Silverlight portingmemberKvanttt26 Jun '11 - 22:09 
Ajcek84, thank you for this great project.
But there is not a very good code in project. It is need refactoring.
I ported this project on silverlight and used it for my musical notation recognition and score following diploma project.
If anybody need silverlight library, I can share it here soon.
GeneralRe: Refactoring & Silverlight portingmemberAjcek8426 Jun '11 - 22:24 
Thanks. Smile | :)
Yes, I know that my code is a mess. Especially the drawing method needs to be refactored.
It's great that you ported my library to Silverlight and I'm looking forward to seeing it. Are you going to share it on BSD license or similar?
GeneralRe: Refactoring & Silverlight portingmemberKvanttt26 Jun '11 - 22:45 
Ajcek84 wrote:
Are you going to share it on BSD license or similar?

Yes of course.
GeneralRe: Refactoring & Silverlight portingmemberAjcek8424 Jul '11 - 2:54 
I'm still looking forward to seeing your Silverlight library. Can you post it on CodeProject? Thank you in advance. Smile | :)
GeneralRe: Refactoring & Silverlight portingmembermcraig1555 Aug '11 - 4:28 
Kvanttt, I'm excited to see the port to silverlight. When do you plan on posting it CodeProject?
 
Thanks in advance
NewsRe: Refactoring & Silverlight portingmemberKvanttt14 Aug '11 - 2:01 
Sorry for delay, but it's not enough time for this project. I can upload silvelight version now, but there are many bugs and bad code.
I'am planned to complete it at the end of september or later.
If anybody post this library on codeproject or other code hosting service and help me, it would be great.
There is my project if anybody need it now despite bugs.
 
http://dl.dropbox.com/u/26130928/MusicNotationSilvelightSample.7z
GeneralRe: Refactoring & Silverlight portingmembermcraig1553 Oct '11 - 5:20 
Thank you for posting this. If we make any significant progress we will be sure to share. If you could let me know if you've made any more progress i would greatly appreciate it.
GeneralVery good work! Question about multiple stavesmembermcraig15520 May '11 - 7:48 
I read on the main page of PSAM that only the first stave will be displayed. Does it still only display the first stave? What is the limiting factor in displaying multiple staves? Would this be a significant amount of work to support display multiple staves or have you not supported it because you did not have a need to display more than one?
GeneralRe: Very good work! Question about multiple stavesmemberAjcek8421 May '11 - 0:17 
IncipitViewer displays only one staff because only one staff is required in international standard of describing musical sources specified by RISM (http://www.rism.info/[^]).
Adding new staves is relatively simple: a staff is a List of MusicalSymbol objects. Currently there is only one list - you can add more lists or add a list of lists to support infinite number of staves. Then you have to modify some graphical operations in DrawViewer to draw barlines across all staves, etc. The problem might be with proper spacing of notes which should be the same in all staves but I think you'll be able to deal with it eventually.
GeneralRe: Very good work! Question about multiple stavesmembermcraig15521 May '11 - 1:41 
Thank you very much for your quick response. I understand completely and this is very helpful. Good to know that adding additional staffs will be relatively straight forward.
 
Thanks again, great work!
GeneralExcellent! Vote of 5, and two questions:memberGuenter Prossliner29 Mar '11 - 3:22 
Hello,
 
thank you very much for this incredible usefull work! I'm currently writing a MIDI Note Monitor, and as you can imagine your work greatly simplyfies my task!
 
Two questions are left:
 
1. Naturals:
============
 
I've managed to insert Signature into the Tab, but it seems to be that now sharps are "naturlized" internaly.
If I have the following Code:
 
ctrl.ClearMusicalIncipit();
ctrl.AddMusicalSymbol(new Clef(ClefType.GClef, 2));
ctrl.AddMusicalSymbol(new Key(2));   // D Major

ctr.AddMusicalSymbol(new Note("F", 1, 4, whole, up, none, single));
ctr.AddMusicalSymbol(new Note("F", 0, 4, whole, up, none, single));
 
The first Note is actually an "F#", which is displayed correclty, because the Sharp-Sign is in the Signature.
For the second Note I'll expect that a "neuralize" sign is displayed in front of the Note, but it's the same as the first one.
 
If you'll swap the Notes, the first has no sign, and the second has a Sharp-Sign.
Do I understand something wrong here? Or is this a Bug?
 
2. Scaling
==========
 
I want to draw the whole Thing in a very large Region. How can I scale it up? e.g. Font-Size 48 for the Polihymnia.
 

Thank you again very very much!
Günter
GeneralRe: Excellent! Vote of 5, and two questions:memberAjcek8429 Mar '11 - 4:06 
Ad. 1) I think it's not a bug, but an inconvenience in design. You have to set HasNatural property of a note to true in order to display "neutralize" sign properly. When you import notes from MusicXml it is set automatically, but when you add a note programmatically you have to set it manually.
Ad. 2) There is no internal scaling ability, but I suppose that WPF provides a way to do so. I'm not good at WPF, so I can't provide a solution at the moment.
GeneralRe: Excellent! Vote of 5, and two questions:memberGuenter Prossliner30 Mar '11 - 0:06 
Hello again,
 
ad 1) Thank you for this clarification. I managed to get it done with the "IsNaturalSignNeeded" method, and it seems to work well (at leasted in fifths from -4 to +3, more on this later)
 
ad 2) Scaling works very very easy in WPF, I justed used a DockPanel with Scale-Transformation as shown in [UI Scaling (UI Zooming) with WPF]
 
One more thing:
I'm using the "CreateNoteFromMidiPitch" method, but it seems to mix Sharps and Flats. e.g. in an C# minor scale, I would expect an '#A', not an 'bH' to be displayed.
 
The "CreateNoteFromMidiPitch" method doesn't care about the current Key, it generally uses Sharps in all cases but "B-" and "E-".
 
I've implemented by own "CreateNoteFromMidiPitch" function based on your implementation which takes a "Key" instance as a parameter, and performs proper substitution:
 
        public static Note CreateNoteFromMidiPitch(int midiPitch, PSAMControlLibrary.Key key) {
 

            // your code start int midiPitchInLowestOctave = midiPitch;
            ... // all lines unmodified from your version until 
            // else if (midiPitch < 120) octave = 8;

            if (key != null) {
                if (key.Fifths > 0 && alter == -1) {
                    switch (step) {
                        case "C": step = "H"; break;
                        case "D": step = "C"; break;
                        case "E": step = "D"; break;
                        case "F": step = "E"; break;
                        case "G": step = "F"; break;
                        case "A": step = "G"; break;
                        case "H": step = "A"; break;
                    }
                    alter = 1;
                }
 
                if (key.Fifths < 0 && alter == 1) {
                    switch (step) {
                        case "C": step = "D"; break;
                        case "D": step = "E"; break;
                        case "E": step = "F"; break;
                        case "F": step = "G"; break;
                        case "G": step = "A"; break;
                        case "A": step = "H"; break;
                        case "H": step = "C"; break;
                    }
                    alter = -1;
                }
            }
 
            // this is your code again
            return new Note(step, alter, octave, MusicalSymbolDuration.Unknown, NoteStemDirection.Up,
                NoteTieType.None,
                new List<NoteBeamType>());
 

        }
 
It seems to work well, as you may test it with:
        int[] majorSteps = { 0, 2, 4, 5, 7, 9, 11 };
 
        int[] fifthBases = new[] { 60, 67, 62, 69, 64, 71, 66, 61, 68, 63, 70, 65 };
 
        void DrawScale(int fifths) {
 
            int baseNote;
            if (fifths == 0)
                baseNote = fifthBases[0];
            else if (fifths > 0)
                baseNote = fifthBases[fifths];
            else
                baseNote = fifthBases[fifthBases.Length + fifths];
 
            ctrl.ClearMusicalIncipit();
            ctrl.AddMusicalSymbol(new Clef(ClefType.GClef, 2));
 
            var key = new PSAMControlLibrary.Key(fifths);
            ctrl.AddMusicalSymbol(key);
 
            for (int i = 0; i < majorSteps.Length; i++) {
                var pitch = baseNote + majorSteps[i];
                var note = CreateNoteFromMidiPitch(pitch, key);
                note = new Note(note.Step, note.Alter, note.Octave, MusicalSymbolDuration.Eighth, NoteStemDirection.Down, NoteTieType.None, new List<NoteBeamType>());
                note.HasNatural = ctrl.IsNaturalSignNeeded(note, key);
                ctrl.AddMusicalSymbol(note);
            }
        }
 
 
It shows good results in range -5 to +4, but in e.g. in +5 (H Major), there is an unneeded Sharp on the last Note, and in -6 there is a Note "naturalized" which is wrong.
 
PS: In Combination with the C# MIDI Toolkit[^], I've managed to implement my Midi Note Monitor in less than half an day! If it's done I may publish it here on Code-Project too! Thank you once more!
GeneralRe: Excellent! Vote of 5, and two questions:memberAjcek8431 Mar '11 - 0:13 
CreateNoteFromMidiPitch method was designed for the needs of query-by-humming functionality in PSAM: user hums or plays a few notes of the melody and application notates them. Because only a few notes are entered, it's not possible to determine the key - instead the most common sharps and flats in XVII-XVIII century music are used and this is the cause why it mixes sharps and flats.
GeneralRe: Excellent! Vote of 5, and two questions:memberGuenter Prossliner31 Mar '11 - 22:45 
Hello Ajcek,
 
thank you for your response! It's not about determinating the Key, I just want to make sure that sharps and flats are not mixed. In my "NoteFinder" Tool the User can select the Key, and then Notes and Chords are displayed in Realtime. The Notes on Screen should match the notes printed. If the Users selectes e.g. "c# mol", and plays an D#, I would just expect a 'D' to be drawn, because there is the Sharp in the Key-Signature anyway. My extended implementation of "CreateNoteFromMidiPitch" from my last message does this.
 
Günter
GeneralRe: Excellent! Vote of 5, and two questions:memberAjcek841 Apr '11 - 0:53 
Yes, I understand the assumptions. I only wanted to explain why sharps and flats are mixed in my approach. Thank you for alternative implementation.
 
Jacek
GeneralRe: Excellent! Vote of 5, and two questions:memberdavidorn25 Jul '11 - 19:10 
Guenter -- if you decide to share your code, it would be appreciated. I'm just thinking now about trying to throw together (as a personal project) an app to help with sight reading. Between the MIDI Toolkit and this control it seems like it wouldn't be too hard. But your post here reminds me that I'll probably also need to be able to generate notes for this control from a MIDI stream, so some of the code you're talking about (e.g., deciding sharps and flats based on key) sound useful. I'm not sure quite what a "Midi Note Monitor" is (that you mention), but it might give a further head start...
GeneralMy vote of 5memberKenJohnson9 Jul '10 - 20:48 
Thanks, It is very rare that such a request gets answered.
 
Ken
GeneralNice!memberJammer4 Jul '10 - 22:16 
I'm going to have a play around with this library! Nice work.

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 25 Jun 2010
Article Copyright 2010 by Ajcek84
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid