Click here to Skip to main content
15,886,137 members
Articles / Desktop Programming / Windows Forms
Article

LED vu Meter User Control

Rate me:
Please Sign up or sign in to vote.
4.40/5 (15 votes)
18 Jan 20054 min read 162.1K   8.6K   72   11
An LED vu Meter Windows User Control in C#.

Four vuMeters in freeze-frame action...

Introduction

While researching a small project to develop round 3D buttons, I came across the very excellent Bob Powell site. Here, I learned all about the PathGradientBrush. After a considerable amount of brain-wringing, I managed to get to grips with the basics of Matrix and Transform. Having thought about writing my own TrackBar control, but discovering that someone else had already done it, I decided to use my new-found knowledge and try to create an LED vu Meter, such as is found in PC and Mac music recording systems. As is often the case, it was easier than I had first thought. It doesn't do anything at all with Digital Signal Processing, so apologies to anyone who was hoping it would, but I think it looks really nice, so it became the subject of my first submission to The Code Project.

The Code

The control inherits from System.Windows.Forms.UserControl, and overrides the OnPaint method. In short, we size each LED so that fifteen will fit nicely within the size of the control, build a 3D border round them, and light them with a PathGradientBrush according to the Volume property.

There are fifteen LEDs, each of which uses three colors. Color 1 is the Surround Color for the "unlit" state, Color 2 is the Centre Color for the "unlit" state AND the Surround Color for the "lit" state, and Color 3 is the Centre Color for the "lit" state. I set these colors up in the ledColours array.

C#
// Array of LED colours  Unlit surround      Lit surround    Lit centre
//                                           Unlit centre
Color[] ledColours = 
           new Color[] {Color.DarkRed,       Color.Red,      Color.White,
                        Color.DarkRed,       Color.Red,      Color.White,
                        Color.DarkRed,       Color.Red,      Color.White,
                        Color.DarkGoldenrod, Color.Orange,   Color.White,
                        Color.DarkGoldenrod, Color.Orange,   Color.White,
                        Color.DarkGoldenrod, Color.Orange,   Color.White,
                        Color.DarkGoldenrod, Color.Orange,   Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White,
                        Color.DarkGreen,     Color.Green,    Color.White};

This may not be the most elegant implementation, but it works, and makes changing the colors simple, if a little tedious. The more observant reader will no doubt notice that the "Lit Centre" is always white, and I could have reduced the size of the array and simply referred to Color.White in the code, but this way, it makes it possible for someone to change the "lit" centre color, if white doesn't work for their chosen surround colors.

The DrawLeds method first calculates the size of each LED, depending on the size of the control. The height is calculated so that fifteen LEDs will fit, with a two-pixel gap between each one.

C#
// Rectangle values for each individual LED - fit them nicely inside the border
int ledLeft = this.ClientRectangle.Left + 3;
int ledTop = this.ClientRectangle.Top + 3;
int ledWidth = this.ClientRectangle.Width - 6;
int ledHeight = this.ClientRectangle.Height / ledCount -2 ;

// Create the LED rectangle
Rectangle ledRect = new Rectangle(ledLeft, ledTop, ledWidth, ledHeight);

Next, we create our GraphicsPath, add our ledRect rectangle to it, and create a PathGradientBrush to use with it.

C#
GraphicsPath gp = new GraphicsPath();               // Create Graphics Path
gp.AddRectangle(ledRect);                           // Add the rectangle
PathGradientBrush pgb = new PathGradientBrush(gp);  // Nice brush for shiny LEDs

We then loop through each LED. The loop has both ascending and descending indices, as explained in the code comments. For each LED, we determine if it's lit or not by comparing the value of j with the value of ledVal (set by the "Volume" property). If our LED is less than or equal to the volume, we light it. (We also light it if it is equal to the peakVal variable, more of which later.) Once we know if we're lighting this LED or not, we select the "Unlit surround" and "Unlit Centre", or "Lit Surround" and "Lit Centre" colors from the ledColours array. This is achieved by simple calculation based on the value of i.

C#
// Light the LED if it's under current value, or if it's the peak value.
if ((j <= ledVal) | (j == peakVal))
{
    pgb.CenterColor=ledColours[i*3+2];
    pgb.SurroundColors=new Color[]{ledColours[i*3+1]};
}
// Otherwise, do not light it
else
{
    pgb.CenterColor=ledColours[i*3+1];
    pgb.SurroundColors=new Color[]{ledColours[i*3]};
}

// Light LED fom the centre.
pgb.CenterPoint=new PointF(ledRect.X + ledRect.Width/2, 
                         ledRect.Y + ledRect.Height/2);

Now for the groovy part. We create a Matrix and use its Translate method to effectively change the value of ledRect.X depending on the value of i. The Transform property of our Graphics instance is then set to our Matrix, mx, to move the current LED down the screen. I worked out how to do this with help from Mahesh Shand here. We then fill the LED in with our trusty PathGradientBrush.

C#
// Use a matrix to move the LED graphics down according to the value of i
Matrix mx = new Matrix();
mx.Translate(0, i * (ledHeight + 2));
g.Transform=mx;
g.FillRectangle(pgb, ledRect);

Once we've drawn all our LEDs, we have to reset the Graphics instance to its original offset, so we can draw the border in the right place.

C#
// Translate back to original position to draw the border
Matrix mx1 = new Matrix();
mx1.Translate(0, 0);
g.Transform = mx1;

The best bit, I thought, was implementing a Peak Level Indicator. This means that the LED at the highest level reached stays lit for a certain amount of time. This is achieved as follows.

First of all, this piece of code in the Volume property determines if the latest value is higher than the previously saved peak value. If so, it saves it in peakVal. Also, the timer is started.

C#
// New peak value
if (ledVal > peakVal)
{
    peakVal = ledVal;
    timer1.Enabled = true;        // Tell the peak indicator to stay
}

The peak value will stay set either until it is exceeded, or until the timer interval elapses, at which point it will be reset to zero, and the LED will go out.

C#
private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Enabled = false;       // Tell the peak indicator to go
    peakVal = 0;                  //
    this.Invalidate();
}

Using the code

It's pretty simple to use - the sample application shows how. If you include vuMeterLED.dll in your project, you should be able to drag the control onto your form. If you download the source, note that I've only included the vuMeterLED.cs, Form1.cs and AssemblyInfo.cs files. This is because I developed the code using SharpDevelop, and I don't know if the project files would be readable by VS.

That's about it then! Thanks for reading this far, and I hope it's useful or educational to someone.

What's next?

Well, the control could do with a scale, which shouldn't be too difficult to draw. More of a challenge would be developing an analog style meter with a moving needle. I'm thinking about it...

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


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionFlickering Pin
BruceN30-Jun-16 7:46
BruceN30-Jun-16 7:46 
QuestionThank you ! Pin
bNobo347-Mar-14 2:49
bNobo347-Mar-14 2:49 
GeneralTerm of Use, Pin
elektro847-Mar-11 22:11
elektro847-Mar-11 22:11 
Generalvb.net and sound Pin
zanspace19-Apr-07 20:33
zanspace19-Apr-07 20:33 
GeneralRe: vb.net and sound Pin
Ibrahim Dwaikat2-Nov-07 4:35
Ibrahim Dwaikat2-Nov-07 4:35 
GeneralPutting this into my C++ program Pin
aquawicket10-Oct-06 14:28
aquawicket10-Oct-06 14:28 
QuestionUsing LED vuMeter in VS2005 project Pin
tohox13-Feb-06 17:35
tohox13-Feb-06 17:35 
JokeSharpDevelop can export VS project... Pin
ThaNerd23-Jan-06 12:47
ThaNerd23-Jan-06 12:47 
GeneralGood Work! Pin
papahabla24-May-05 19:21
papahabla24-May-05 19:21 
Generalhi Pin
chronicsys2-Mar-05 6:23
chronicsys2-Mar-05 6:23 
totally cool little project . . . but can i get something straight? the led just randomly bounce up and down? or it actually comminucates with pc's soundcard ?

thanks for publishing, chronicsys
GeneralRe: hi Pin
Gary Perkin3-Mar-05 0:16
Gary Perkin3-Mar-05 0:16 

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

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