Using Silverlight to Build a Guitar Chord Calculator

Silverlight is so versatile that it is easy to move beyond conventional browser-based applications and even write games. John Papa celebrates the launch of his new book by bringing you a simple Silverlight guitar Chord Calculator to demonstrate features of Silverlight such as Data binding, Media elements, Resources, Transforms, Visual states and Dynamically generated controls. He has placed the complete source on Codeplex, so that you can enhance it if you feel the urge.

One of the advantages of using Silverlight is that it can be used to build any type of application, including  games. As well as spending a lot of time building varying types of business applications and writing a book that focuses on building data driven applications, I’ve also spent time building less traditional and more fun programs with Silverlight. Regardless of the type of application and its requirements, there are some key aspects of Silverlight development that apply. This article explains how to apply some common and widely-used aspects of Silverlight to build a guitar chord finder.

The program allows the user to choose from an assortment of chords and then display on a fret board how the user could places their fingers to play the chord. The application can display and play the main major and minor chords, however it can be modified to also include other chords including suspended, 7ths, and others. (The source code for the application is posted on CodePlex at the following link. I encourage the community to grab the code and contribute to it. )

Source: http://silverlightchordcalc.codeplex.com
Demo: http://johnpapa.net/demos/chordcalc/demo.html

The sample application uses mathematical calculations to determine how to play each chord. As any guitar player knows, there are many ways to play each chord and using the mathematical calculations may not yield the most comfortable nor common finger positioning for the chord. I added some adjustments to the calculations to try to mediate this, but of course nothing is as good as purely pre-determining the finger positions for each chord.

 In a future version of this tool I will forgo the calculations and display multiple chord variations for all of the chords. But for the purpose of this article, it was more fun to show that the calculations can be used.

The application uses a CoolMenu control found on CodePlex in the Silverlight Contrib project (which is a great set of community contributions). The sample application also takes advantages of several key ingredients in a Silverlight application including the following, amongst others:

  • Data binding
  • Media elements
  • Style resources
  • Control Templates
  • File resources
  • Transformations
  • Visual states
  • Dynamically generated controls

Demo Time

I’ll start by demonstrating the application pointing out what it does and how it can be interacted with by a user. Along the way I’ll make a reference to the different elements used to create the application, which will be explained following the demo.

Fret Board

670-image002.jpg

Figure 1 – Guitar Chord Calculator

The sample application is shown in Figure 1 displaying the G major chord. The sample has a fret board on the top that displays the chord fingering. The blue circles indicate where a finger should hold a string. The note that will be played is noted inside of the blue circle. If the blue circle is shown on the nut at the far left, this indicates that the string is open.

Visual Aspects and Dynamic Creation

The blue circles on the fret board are actually button controls whose control templates have been replaced. Instead of displaying a standard button, the control templates contain an ellipse with a gradient background and text content. The buttons are created in .NET code and a style resource is applied to each button before being placed on the appropriate spot on the fret board. Each button also has a visual state where the button grows slightly during a mouseover event and shrinks slightly when the button is clicked. Every audio file is added as a resource to the project. Some transformations are used to skew the viewing angle of the fret board.

CoolMenu and Data Binding

Below the fret board, a list of the notes is displayed in a CoolMenu control from the Silverlight Contrib library on CodePlex (similar to a fish eye control). There is also a list of the types of chords (in this case Major or Minor) displayed in another CoolMenu control.  Each of these controls is data bound to a List of notes and of chord types, respectively. The user can select the note and the chord type using the 2 CoolMenu controls. When the selection has been made, data binding is used to display the name of the chord at the bottom of the screen and the chord calculation logic executes to build the appropriate chord on the fret board. Data binding is also used to bind the appropriate chord’s audio file to a media element so the chord can be played.

Audio

There is an accompanying audio file for all 6 strings and for each fret and an open string for a total of 36 individual notes. If the user clicks a blue circle button on the fret board, the note will be played for that specific string and fret through a MediaElement control.

When the user selects a note and chord type, chord’s corresponding audio file is data bound to a MediaElement control. When the user clicks the musical note button, the audio file is played. There is an audio file for each of the notes and chord type combinations, for a total of 24 additional audio files.

When added together, the combined size of the audio files can become large. This is increases the size of the Silverlight XAP file and can cause the load time of the Silverlight application to slow down. One way to combat this is to use a tool to compress the audio files. The files in this sample project are compressed, however keep in mind that this compression often causes quality loss in the audio file.

Transforms and User Controls

As you can see, there are many aspects that work in concert to make the application. Now that I’ve shown what that application does and pointed out its parts, I’ll dive into how each part works within the application. The fret board is a Grid panel (named fretBoardGrid) with 6 rows and 5 columns. The fretBoardGrid is skewed slightly to give it a bit more visual perspective using the following transformation. This is most easily set by selecting the Grid in Expression Blend and setting the SkewTransform property’s X angle to -5, as shown in Figure 2.

670-image004.jpg

Figure 2 – Skew Transform for the Fret Board

The guitar strings are represented by a user control named GuitarString and the fret bars are represented by a user control named Fret. Both of these user controls are contained in the controls folder in the Silverlight project. User controls are ideal for situations where you want to re-use the same control. This works well for the guitar string and fret bars since they are each used multiple times. The GuitarString control uses a Path to create the appearance of a guitar string. The Path has a stroke thickness of 5 and is colored, as shown below.

An instance of the GuitarString control is placed in each of the rows of the fretBoardGrid. Each string is the same width, but on a guitar each string gets progressively smaller from the low E to the high E string. One way to make the strings gets smaller is to use a scale transform on each string. For example, the following code shows a ScaleTransform that changes the scale of the Y for the guitar string to 10% of its initial state. The other strings all use slightly less of a scale to create the appearance of the strings.

The fret bars are represented by the Fret user control. The Fret control contains a vertical gray rectangle, represented by a path. (A Rectangle control could also have been used, if desired. Either control is fine in this case.)

The same principles that are used to display the GuitarString controls are also applied to the Fret controls. The first column of the fretBoardGrid needs to show 2 Fret control. The first fret will be a little thicker than the others as it will represent the nut of the guitar. The thickness is adjusted using a ScaleTransform to double its size (see the code sample below). The second Fret control will be aligned to the far right of the column to represent the first fret on the guitar. The subsequent Fret controls are placed in the rest of the columns, 1 per column and aligned to the right.

Example 1 – Laying the frets on the neck of the guitarr

All of this and the coloring and shading helps make the fret board give the appearance of a guitar fret board, as shown in Figure 3.

670-image006.jpg

Figure 3 – Final appearance of the fret board

Data Bound Menus

Two CoolMenu controls are displayed below the fret board to allow the user to select the chord to display and play. The CoolMenu is a control included as part of the Silverlight Contrib on CodePlex. It is based on the ItemsControl, which is ideal for binding and displaying a list of items. The XAML for the first CoolMenu (named noteMenu) is shown in Example 2. This control must be downloaded from CodePlex and referenced by the Silverlight project before it can be added to a user control. This will add the namespace reference in the UserControl tag in the XAML, as follows:

670-image008.jpg

Figure 4 – The Note and Chord menuss

The noteMenu CoolMenu is simple to set up. The code shown in Example 2 shows some basic layout settings for the menu and that the ItemsSource property is set to use the data binding via the DataContext. Since this control inherits from the ItemsControl, it can also use a DataTemplate to define the items in the CoolMenu. In this case each item is represented simply by an Image, which gets its source form data binding.

Example 2 – Designing the CoolMenu controls

The noteMenu is bound to a List<Note> classes. The Note class represents the aspects of a single note and includes the name of the note and the image file associated with the note. The NoteData class (shown in Example 3) stores a List<Note>: 1 for each of the 12 notes.  Each note image is stored in an images folder in the Silverlight project and has its Build Action set to Resource, as shown in Figure 5. Once the NoteData class is created it can be bound to the noteMenu as shown below:

This list of data is static so there is no need to use the INotifyPropertyChanged interface nor the INotifyCollectionChanged interface. These interfaces are ideal when the contents of a list or the properties of an object might change, and the changes need to be displayed in the UI. For the noteMenu and the chordTypeMenu, this is not required since these lists do not change.

Example 3 – Defining the List<Note> to bind to the noteMenu

670-Guitar1.jpg

Figure 5 – Making the image file a resource

The chordTypeMenu follows the same design and pattern as the noteMenu. It uses a CoolMenu control and binds to a List<ChordType> through the ChordTypeData class. You can refer to the full source code for the exact implementation, as this is set up the same way the noteMenu is set up.

Chord Bindings

When a user selects a note or a chord type, a corresponding event handler fires for each of the CoolMenu controls respectively (as shown in Example 4). The selected item (note or chord type) is retrieved from menu and set to the field _currentChord, which is an instance of the ChordAudio class. The _currentChord contains a property for the Note, the ChordType and the audio file location for the currently selected chord. The ChordAudio class implements the INotifyPropertyChanged interface and fires the ProeprtyChanged event whenever any of the properties are updated. This tells the UI to get fresh values from the class instance whenever the audio file, note or chord type changes. The ShowChord method performs the calculations that determine what notes should be played to achieve the chord.

Example 4 – Setting the Chord’s Binding in Event Handlers

The _currentChord field is bound to the SelectedChord StackPanel which displays the selected chord’s name and binds the audio file to the chordPlayer MediaElement. Using data binding allows the UI to update itself and be prepared to play the currently selected chord immediately after the user selects a different note or chord type.

Example 5 – Binding the Selected Chord

Audio Media Elements

The chordPlayer MediaElement shown in Example 5 is a control with no visible interface. It will play the audio file based on its binding, which in this case is one of the mp3’s associated with each of the chords. Each audio file is stored in the Silverlight project in the sounds folder. Like the note images, the audio files also have their Build Action set to Resource, so they can be used as a resource in the project. The chordPlayer has its Volume property set to 1 (but of course this can be adjusted by the user by perhaps a slider control). The Source of the chordPlayer is set to use data binding to get the audio file’s location. The AutoPlay property is set to an initial state of False, so the audio file will not play automatically when the audio file is bound to the MediaElement. The application should not play the chord automatically, instead it should only play when the user clicks the btnPlayChord button (the square blue musical note).

The event handler for the btnPlayChord first checks if the audio file is set. Then it turns on AutoPlay, sets the position of the audio file to the beginning so it will play from the beginning, and the it plays the audio. The AutoPlay property is then set to false again, so when the bindings change later the audio file will not automatically play. The code for this is shown below.

Chord Calculations

The last aspect of the sample demonstrates how to dynamically generate the button controls on the fret board to show the user where to put their fingers to create a specific chord. The logic for displaying the chord is controlled by the ShowChord method. First the logic must determine where to put the “finger spots” (the places the user must put their fingers).

As mentioned before, this sample calculates the finger spots instead of using pre determined locations. The logic for this calculation can be seen in the source code and is based on standard musical theory, which is outside the scope of this article.

The ShowChord method fills a chart (_scaleInfoChart) containing the list of notes in a scale starting with the note for the chord. For example, if the G major chord is selected, the note chart would start with G and continue with the rest of the scale like this: G G# A A# B C C# D D# E F F#.

­Once the scale chart has been created, the GetChordNotes method determines which notes are needed to create the selected chord. It uses static data based on the scale to determine which notes in the scale are needed (again based on music theory)­­­. The notes for the chord are returned to a list. Then in the FillNoteMappingList method (shown in Example 6), the strings and frets of the guitar are then searched to find the notes required to produce the chord.

Example 6 – Mapping the Notes to the Fret Board

First, the FillNoteMappingList method loops through each string of the guitar. It grabs the information about each guitar string such as string number and the notes for that string when played open and when played on all of the frets. This information will be used to see if the notes on that string match any of the notes we are looking for in the chord. The method then loops through each fret (starting with the open string) in search of the matching notes. When a match is found, an instance of the NoteMapping class is created and it’s the string number, fret number, the note and the audio file for that note are stored in the NoteMapping instance. This process continues for each string on the guitar.

I added a few additional methods after this process that eliminate some of these mappings based on logic to make them more reasonable to play (for example, I limit the chords to requiring 4 fingers). This logic is imperfect, and can certainly be expanded.

Dynamically Generating Controls

Once the note mappings have been determined, the buttons must be placed on the fret board. The DisplayNoteMapping method handles this job. It loops through the mappings and creates a new Button control (shown in Example 7). The new Button is created using the style resource (FingerButtonStyle) that uses the control template that replaces the standard button with a blue circle. The button does not have a Row property but it does get an attached property for this since it is contained within a Grid. The code must set the Grid.Row property for the button to make the button show up on the proper string. The attached property is set using the SetValue method and passing in the property and the value.

Example 7 – Generating and Display the Chord Buttons

Now that the string has been set (via the row) the fret must be set (via the column). If the string is not played open, then the code sets the attached Grid.Column property using the SetValue. If the string is played open, the button is shifted to the left a bit to make it appear centered on the nut of the guitar. Once the button is created, it is added to the Grid’s Children collection. This is necessary to make it display within the Grid.

When the new button is clicked, it should play the audio file that plays the individual note. This requires that an event handler must be assigned to the Click event for each new button. The handler calls the PlayNote method which accepts the name of the audio file to play. The DisplayNoteMapping method uses a lambda expression to set the handler.

Summary

This application demonstrates several aspects of creating visual effects, transforms, style resources, file resources, media elements, overriding control templates, data binding, and dynamically generating and displaying controls in code. When all of these features are combined the result can be a compelling application using Silverlight through Expression Blend and Visual Studio.

Tags: , , , ,

  • 21561 views

  • Rate
    [Total: 28    Average: 4.3/5]
  • Anonymous

    Error
    Failed to load the application. It was built with an obsolete version of Silverlight.

  • John Papa

    Silverlight 2
    RE: Anonymous Error … The application uses the release bits of Silverlight 2. If you had a problem loading it, please feel free to contact me.

  • Anonymous

    hg
    think you

  • Anonymous

    Wierd
    It loaded fine for me in Firefox but not in IE. Sort of interesting!

  • John Papa

    loading
    RE: “Wierd”

    If you have problems loading it, please email me ( you can reach me through my web site’s contact page ).

    The Silverlight team is great at looking into issues so they can make it a better experience. I can relay any problems to them, if I can not solve them.

  • cliffeby

    Nice Job
    Great to see some real Silverlight that isn’t a Northwind or AdventureWorks Customer grid. Thanks for the contribution.