(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Silverlight Metronome

(16 votes)
Martin Mihaylov
>
Martin Mihaylov
Joined Oct 29, 2007
Articles:   50
Comments:   70
More Articles
15 comments   /   posted on Feb 09, 2009
Categories:   General , Design

This article is compatible with the latest version of Silverlight.


Introduction

In this article I will present the Silverlight application I was busy with recently - the Silverlight Metronome. It's a classical metronome (a measurement tool for tempo, mostly used by musicians) that is based on a pendulum with a moveable mass, which modifies its period. The project was very challenging as it needed some simple physics and a beautiful design to be implemented. In my opinion I have accomplished it or at least I have done it according to the physics; the design has always been a very subjective topic. Anyway, you can see the live demo here and download the source code here, but I'm sure that you would like from us to make a fast dissection of the application and see how it works.

The pendulum

I am not using images in this application, which means that our main tool will be the templating of the Silverlight controls. First of all we need a pendulum that will be used for the main functionality of the metronome. We need a control that will give us the possibility to control and change its value - obviously the Slider control suits our needs perfectly.

Besides changing the template of the Slider I need to set some additional properties:

  • Orientation to Vertical
  • IsDirectionReversed to true (this is because by default the vertical slider has it's direction set from the bottom to the top and for those who don't know the metronome scale – it has its smallest value at the top and its greatest at the bottom)
  • Minimum and Maximum to 40 and 208 (by some kind of convention these are the minimal and the maximal tempos for metronomes)
  • Small- and LargeChange - it's a good practice these two to be set according to the values that the slider displays. For example, the tempos will be integers with a difference between them 1, so obviously our SmallChange proeprty is set to 1. In order to be more comfortable and to move faster through the tempos I set the LargeChange to 10.

Note: I will not discuss the template here, because it's a really big amount of code. You can see it in the source code.

I also implement the INotifyPropertyChanged interface which raises a PropertyChanged event when the value of the slider is changed: 

private void PendulumSlider_ValueChanged( object sender, RoutedPropertyChangedEventArgs<double> e )
{
    if ( this.PropertyChanged != null )
    {
        this.PropertyChanged( this, new PropertyChangedEventArgs( "Tempo" ) );
    }
}

and add a public method called SetAngle that later will be used to rotate the pendulum using a RotateTransform:

public void SetAngle( double angle )
{
    this.PendulumRotatateTransofrm.Angle = angle;
}

Here is how the Slider looks like after we have finished with our modifications:

metronome-1

The metronome

The next step is to create a body for our metronome that hosts the pendulum. This control also implements the main logic around the movement of the pendulum. Let's start with creating the body. To accomplish this task I use Visual Studio in combination with Expression Blend:

  • In the Visual Studio I create the outlines of the body using Polyline controls and setting their points manually.
  • In the Expression Blend I choose the colors and fill the outlines using gradients and solid color brushes.

Here is the final result:

Now let's take a look at the functionality around the pendulum. If you have already read the article of Gozzo Smith about the Custom Animations in Silverlight you should be familiar with the physics around the mathematical pendulum and the method of Runge-Kutta that is used to solve the differential equation for the pendulum's motion. I use the same custom animation here, namely by handling the CompositionTarget.Rendering event. The difference here is that I have an additional parameter in my case - the tempo. When the tempo is changed the only parameter in the common case that changes is the length, so we have to find some dependence between the tempo and the length:

metronome-3

In the last equation only the period T is unknown, but we can calculate it on the base of the tempo:

metronome-4

  • 60 is the number of seconds in one minute (the tempo is also known as beats per minute)
  • 1.935  - in one period we have two beats, so in the beginning I used 2 instead of 1.935 but after a few tests and a few calculations I found out that it should be 1.935, don't make me explain it please.

So now we have the length and everything that we need to implement the Runge-Kutta method. In the handler for the Rendering event of the CompositionTarget we write the following:

private void CompositionTarget_Rendering( object sender, EventArgs e )
{
    TimeSpan now = DateTime.Now.TimeOfDay;
 
    TimeSpan diff = now - this.date;
    this.dt = ( double )diff.Milliseconds / 1000;
    this.date = now;
 
    ODESolver.Function[] f = new ODESolver.Function[ 2 ] { this.F1, this.F2 };
    double[] result = ODESolver.RungeKutta4( f, this.xx, this.time, this.dt );
 
    this.Pendulum.SetAngle( 180 * result[ 0 ] / Math.PI );
 
    if ( ( this.thetaN > 0 && result[ 0 ] < 0 ) || ( this.thetaN < 0 && result[ 0 ] > 0 ) )
    {
        this.TickPlayer.Position = TimeSpan.FromTicks( 0 );
        this.TickPlayer.Play();
    }
 
    this.thetaN = result[ 0 ];
    this.xx = result;
    this.time += this.dt;
    this.time = Math.Round( this.time, 3 );
}

The result from the equation is an angle. We convert it in degrees and pass it as argument to the SetAngle method of the Pendulum control. Our animation is ready, but that’s not all. As you know, the metronome should play a tick sound every time he passes through the point in which the angle is null. So we check when the angle from the previous calculation and the angle from the present one are positive and negative (this means that the pendulum has passed the null point) and play a tick sound using a MediaElement.

Note: When the browser window that displays the application is not active, the metronome may behave strangely when the window gets active again. The reason for this is that when inactive the CompositionTarget.Rendering event doesn't fire. The same applies also when the Silverlight application gets scrolled out from the visible area.

The other goodies

There are some other things that we should create in order to make the user comfortable when using our metronome. For example, this could be graphic improvements like reflections or other controls that improve the user experience such as play and stop buttons, volume control, indicator for the tempo value.

Reflection

The reflection effect can be accomplished fairly easy using OpacityMask and ScaleTransform. Here is an example:

<Grid x:Name="MetronomeReflection" RenderTransformOrigin="0.5,1" Opacity="0.6">
    <Grid.RenderTransform>
        <TransformGroup>
            <ScaleTransform ScaleY="-1" />
        </TransformGroup>
    </Grid.RenderTransform>
    <Grid.OpacityMask>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1" >
            <GradientStop Color="#FF000000" Offset="1"/>
            <GradientStop Color="#00000000" Offset="0.8"/>
        </LinearGradientBrush>
    </Grid.OpacityMask>
    ...
</Grid>

In the OpacityMask's brush we use two colors - black with 100% opacity (the things under the black color are visible) and black with 0% opacity (the things under the transparent color aren't visible). I use GradientBrush to make the effect smoother.

Using a ScaleTransformation with ScaleY set to -1 we transform our control to a mirror image of itself (in the case at the bottom).

The other controls

The other controls implement a pretty simple functionality so I won't explain them here; you can easily take a look at them in the sources. The interesting about them is the PropertyChanged event that is used to sync them with the Metronome control.

Conclusion

That's it! This is a really cool Silverlight control that I'm very pleased with, because it looks fairly nice, it provides the needed functionality and I had a great fun while developing it. I'd like to explain all the things in details but this will emerge into a one big, boring article, full of technical explanations and physical formulas. My goal was to provide you with the main idea of the application, the main steps in creating it and leave a little mystery around it, so everyone can find out the answer of their question by playing with the source or just asking me. Enjoy it! ;)


Subscribe

Comments

  • -_-

    RE: Silverlight Metronome


    posted by Michael Washington on Feb 11, 2009 21:57

    Wow. Very Good.

  • -_-

    RE: Silverlight Metronome


    posted by Dheeraj on Feb 12, 2009 00:11

     Cool

  • -_-

    RE: Silverlight Metronome


    posted by Perry on Feb 13, 2009 16:31

    Great work.  I'm a musician and a programmer...I've been wanting to learn SilverLight / WPF and this is one of the applications I had in mind to do it.  Thanks for posting!

  • -_-

    RE: Silverlight Metronome


    posted by Perry on Feb 13, 2009 16:40

    The source code seems to be missing some components....still kool though! 

  • -_-

    RE: Silverlight Metronome


    posted by Dave on 18:46

     I ran this using VS2008 - everything fine except audio file does not load.

    Here is the code in Metronom.xaml

    <

    Setter Property="Source" Value="http://localhost:53474/Tick.wma" />

    How can I include Tick.wma without using localhost?

  • Enrai

    RE: Silverlight Metronome


    posted by Enrai on Feb 17, 2009 05:30

    @Perry tell me please what is missing so I can add it! :)

    @Dave for some reason I couldn't use the audio file while placed in the xap, so I placed it  int the web application and set the absolute path to it as source of the media element. See if you run the web application on the same port, if not change the url. If I find a way to use an audio file from inside the xap I will share it! :)

     

    P.S. Thanks for the good words, I'm glad you like it! :)

  • -_-

    RE: Silverlight Metronome


    posted by Dave on Feb 17, 2009 14:23

    I changed:  Value="Tick.wma"

    I changed BuildAction for "Tick.wma" file properties to: Content.

    I pasted "Tick.wma" into same file as xap

    I rebuilt.

    I have audio!

    Tkanks!

     

     

  • -_-

    RE: Silverlight Metronome


    posted by Dave on Feb 17, 2009 19:41

    To clarify:

    "Tick.wma" was 'added'  to the SilverlightMetronome VS2008 project.

    "Tick.wma" file was also added to the same directory as the xap.

  • -_-

    RE: Silverlight Metronome


    posted by Musikero11 on Mar 02, 2009 07:07

    Being a musician gives me an advantage with regards to tempo.

    Being a programmer gives me an interest in learning about silverlight.

  • -_-

    RE: Silverlight Metronome


    posted by Dan on Jul 20, 2009 19:03
    Works great on Vista but no sound on XP with service pack 2 running I.E. 6. Or if there is sound it is sporadic. Seems to be an silverlight plugin problem with XP but I haven't found any info on a solution
  • -_-

    RE: Silverlight Metronome


    posted by Ian Gray on Feb 17, 2010 11:33

    Hi Martin

    I love this metronome and would like to add it to my production music teaching web site. Is that OK with you? I'll happily post an acknowledgement to you.

    Ian

    IanGray@oz.net

  • -_-

    RE: Silverlight Metronome


    posted by James on Mar 08, 2010 10:33
    I wanted to learn Silverlight / WPF and this is one of the applications I had in mind to do it.
    Thank you for posting!
  • -_-

    RE: Silverlight Metronome


    posted by Doug on Mar 24, 2010 23:25

    Been trying to build a windows metrenome using WPF/XAML. Came across yours, demo'd it, and thought i may have found a solution to the probelm i've been having wiht timers and multimedia timers.

    When i tied your ideas of checking the difference in time, it worked, but still having issues.

    The probelm I am having is when something else occurs on the processor, the click lags or skews from being anywhere near precise. I ran your your version again and tried loading windows and other tabs in IE, and got some lag and skewing but no where near what I an getting wiht the windows version.

    Did i miss anything in your code that gives the media element or events are given more priority on the processor?

  • -_-

    RE: Silverlight Metronome


    posted by Billy on Apr 17, 2010 11:45
    What is the license for this metronome
  • Enrai

    RE: Silverlight Metronome


    posted by Enrai on Apr 20, 2010 10:42

    You can use it and embed it freely, as long as you mention the original source.

    Thanks for your interest!

Add Comment

Login to comment:
  *      *