|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article

Introduction
A while back, I released the .NET version of the Peak Meter control but one thing I quickly discovered is that many developers would not know how to use it in their own application. This is the reason for this update. I will present the various components that are involved in order to show audio meter in real-time.
Description
Real-time Peak Meter processing is composed of three blocks.
- The source: source of audio data, this can be a microphone, a digital sound file (CD audio) or even a video if you consider grabbing the audio part of it. Whatever your source the principle is the same, you will have to convert the data to a format that is suitable for Signal Processing.
- DSP Processing: what I'm calling DSP processing block here is the component that is responsible to convert the audio data to peak amplitude format.
- Peak Meter rendering: this is basically the rendering control (just like the Peak Meter control of this article). The rendering engine doesn't have to be all fancy like this control. A progress control can be used to show Peak audio. In fact if you look around Windows control panel, this is exactly what is being used.
Audio Source
The microphone is the most basic audio source that you can think of. Basically the previous figure illustrates how your computer receives digital samples of the sound that is produced from the microphone. The way the whole process works is that you specify the format that you wish to receive the data, mostly PCM data (Pulse Code Modulation) and the audio capture device will collect the samples based on sampling frequency. PCM data and WAVE chunks are common terms to describe the data that is obtained from the ADC (Analog to Digital Converter). For example to digitize audio samples from a microphone at 22050 Hz single channel audio (mono) and 16 bits resolution; and let's say you want to receive samples every 100 ms, you will have to provide a buffer of 4410 bytes (22050*(16/8)*0.1). I mentioned previously about file source. A file source is simply an audio data storage that gives you quick access to your samples. Audio formats like: MP3, WMA and Ogg Vorbis; all they do is compressing the data while trying to maintain the audio quality.
DSP Processing
DSP processing is very interesting subject to learn and work with. This block receives digital samples from the source. It approximates the original waveform and finds its peak magnitudes. Since I would not be able to go in details about how FFT (Fast Fourier Transform) works in this article, I recommend the interested reader to visit some of the links in the reference section to increase his/her knowledge about this process. FFT plays an important role in signal processing and is probably one of the most written subjects in software engineering. When dealing with digital system, the ADC (Analog to Digital Converter) gives us a set of digital audio samples (discrete signal). The theory behind it tells us that when we perform a DFT (Discrete Fourier Transform) on a discrete signal, we find its composant frequencies including their phase and amplitude. I would like to direct the advanced reader that I'm not talking only about pure sine wave where only the fundamental is visible but performing a DFT (or FFT) on audio signal generally produce some amplitudes on nearby bin frequencies. Now all we have left to do is finding the range of frequencies for our analysis. According to the sampling theorem we can approximate the maximum audio frequency in our signal. The Nyquist theorem states that the baseband Fs > 2B, which means the sampling frequency (digital) must be at least twice than any frequency in the range of B frequencies (analog) in order to reconstruct the original signal and prevent aliasing. Aliasing is the effect that causes different signal to be indistinguishable (or aliases of one another) when sampled. Thus, if we sample at 44.1KHz (audio CD quality), we could capture the entire range of sound (roughly 20KHz). Note that the sampling frequency needs to be at least twice our max frequency, using 44.1KHz to digitize a 20KHz sine waves improves our spectrum analysis by getting a few more samples than necessary. 
Peak Meter Rendering
Peak Meter is just a "piece of cake" since the DSP block takes all the burden of what has to be done. What we do next, we select a group of frequencies and display the amplitude of their closest bin frequencies. Peak Meter control can be as simple as using a progress control. But I guess we like to be fancy from time to time! The PeakMeter control presented here does just that. It is best to choose frequencies in the range below because they are typically found in normal conversation and music.
Using PeakMeter in .NET
You can use .NET version of this control in WinForms applications. Just add it to your toolbox and drag and drop it to your WinForm canvas. Here's a summary of the properties for this control
PeakMeterControl Properties
| Property |
Description |
| MeterStyle |
Show Meter bands in Horizontal (PMS_Horizontal) or Vertical (PMS_Vertical) |
| ShowGrid |
Show meter background grid |
| ColoredGrid |
Show meter backgroung grid using color schemes |
| GridColor |
Background grid color (when ColoredGrid property is false) |
| ColorNormal |
Low range color |
| ColorNormalBack |
Low range color Background (ColoredGrid=1) |
| ColorMedium |
Medium range color |
| ColorMediumBack |
Medium range color Background (ColoredGrid=1) |
| ColorHigh |
High range color |
| ColorHighBack |
High range color Background (ColoredGrid=1) |
| BandsCount |
Number of bands |
| LEDCount |
Number of LED per bands (when 1, band is smooth) |
| FalloffSpeed |
Falloff effect speed (1=fast, 10=normal, 100=slow) |
| FalloffEffect |
Enable falloff effect, call Start() to run |
| FalloffColor |
Falloff line color |
PeakMeterControl Methods
| Name |
Description |
| bool Start(int delay) |
Start animation (delay in ms). Can be called from non-UI thread. |
| bool Stop() |
Stop animation. Can be called from non-UI thread. |
| void SetMeterBands(int bands, int led) |
Set meter bands properties and number of LED in one call |
| void SetRange(int min, int med, int max) |
Change meter control default range |
| bool SetData(int[] values, int offset, int size) |
Set peak meter data. Can be called from non-UI thread. |
Using the PeakMeter
Using this control is very straightforward, add it to your toolbox and drop it to your form. You can use Start method to animate the falloff effect. The demo fills the data with random numbers.
private void FillMeterData()
{
int[] meters1 = new int[NumLEDS];
Random rand = new Random();
for (int i = 0; i < meters1.Length; i++)
{
meters1[i] = rand.Next(0, 100);
}
this.peakMeterCtrl1.SetData(meters1, 0, meters1.Length);
}
SoundStudio Demo
SoundStudio Application is a simple sound player application capable of playing various audio files (.wav, .mp3. and .wma). It uses the WindowsMedia .NET library to parse the audio. SoundStudioCS (C# version) can be built using the unmanaged DLL (FFTLib.dll). Simply add USE_FFTLIB to your project build settings (Build->General tab).
Some of the features of WindowsMedia .NET (Release)
- Microsoft WAVE device support (waveInOpen, waveOutOpen)
- DirectShow Filters, including sample grabber filter
- Microsoft Multimedia Streaming Interfaces
References
Discrete Fourier TranformDiscrete Fourier Transform (Math)FFTNyquist Theorem
History
09/04/2008: Updated all samples (+WindowsMedia release) 08/13/2008: SoundStudio Release (include WindowsMedia pre-release) 05/24/2008: First revision for .NET
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 35 (Total in Forum: 35) (Refresh) | FirstPrevNext |
|
 |
|
|
we use waveOutXXX and DirectSound for output module, with waveOutXXX, system notify application by message WOM_DONE. we can get sample from WAVEHDR, but with DirectSound, it is a circle buffer, how do i get accurate position from this circle buffer?
i hope you can give me some useful suggestion?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I need some help for my project.I just wanna know how to convert microphone signals (wave) to a stream of musical notes (text stream indicating the musical notes of the signal)? If anybody knows anything regaurding this subject pls contact me thanks
Hashan Fernando (SLIIT)
|
| Sign In·View Thread·PermaLink | 2.33/5 (2 votes) |
|
|
|
 |
|
|
is it possible what gets samples from directsound primary buffer and exactly playing position? in another word, can i access directsound primary buffer and exactly play position?
modified on Friday, September 12, 2008 2:44 AM
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
hi, i got a program from codeproject which playes wave file with directsound. and i want to modify it and add spectrum support to it. but i got some questiones about it, can you help me resolve it?
question one: the program open wave file and read wave file information to struct WAVEFORMATEX, the members of it like wFormatTag=1, nChannels=2, nSamplesPerSec=44100, nAvgBytesPerSec=176400, nBlockAlign=4, wBitsPerSample=16, cbSize=0. then program initial DirectSoundBuffer's size as 176400, we must set size to 176400, it can be set any number?
question two: i add code to log DirectSoundBuffer's current play position and current write position to listbox control, the max value displayed in it which each of them may big than 176400, how can i get right start postion what i want to sample the buffer? code like:
DWORD dwCurPlayPos, dwCurWritePos; m_lpDSB->GetCurrentPosition(&dwCurPlayPos, &dwCurWritePos);
question three: if i get right start postion of buffer, what right sample size may be suggest?
code modified by me can download here.
regards, jacky_zz
modified on Thursday, September 4, 2008 2:31 AM
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
From what I can understand from your comments, you have a 44.1KHz stereo wave file (2 channels). This is the reason for 176400 (44100*(16/8)*2). This represents 1 second of raw PCM audio. It's ok to read that much memory from disk but if you want to do the FFT and show the spectrum, you should consider breaking it into smaller samples. For example, if you want 50ms samples buffer you will get roughly 8820 bytes(/per 50ms block)(or 4410 bytes/channel). You need to pass the data for each channel separately. The FFT algorithm in my article requires a buffer size multiple of 2. Sorry, I cannot give recommendations based on someone else code.
In the end, we will remember not the words of our enemies, but the silence of our friends. - Martin Luther King Jr. Ernest Laurentin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Ernest
Your wonderful code has helped me out of a tight situation. I am developing a program and wanted to convert the output audio in to amplitude and frequency information. Your code was really helpful. Since I am pretty new to C#, I am taking some time to understand the code. But I have already achieved a part of what I wanted. Can you tell me/provide me with the modified code to take the audio feed from the sound card/audio out instead of from an audio file. Your help would be appreciated much. Thank you
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Deepak, Thanks for your feedback. I believe you meant to take audio from wave input (microphone) not audio out. Please write me directly and I will send it to you. If more people are interested, I will update the article. Thanks
In the end, we will remember not the words of our enemies, but the silence of our friends. - Martin Luther King Jr. Ernest Laurentin
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I'd be very interested too - for monitoring both audio inputs and outputs (I have an M-Audio Deta 1010 - 8 channel analog simultaneous in and out).
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)Expect everything to be hard and then enjoy the things that come easy. (code-frog)
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Hi,
Thank you for all the explaination and code . I'm working on an app that have to manage some sound and your article will help me so mutch .
Thank's again .
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Welcome! Glad to hear this is working for you.
In the end, we will remember not the words of our enemies, but the silence of our friends. - Martin Luther King Jr. Ernest Laurentin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yep, It did
Do you have or know any example, ressource or algorithm to implements a BBC PPM ? (In any programming language... I'll try to translate...)
Thank's.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
kj_dsp_src.zip the class KJDigitalSignalProcessingAudioDataConsumer responsible for PCM data compute, the class KJFFT responsible for FFT compute, and the class KJScopeAndSpectrumAnalyser responsible for draw visualization. can you give me what difference process PCM data between your work and it?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
bass[^] sound library which provides many useful interfaces to call, free only non-commercial. i want to get an open source sound library for study, can you introduce me an open source sound library like bass?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
i got two questiones about function CSoundStudioDlg::GetAudioData, assume WaveFormat.wBitsPerSample=16, WaveFormat.nChannels=2. 1. why did you get right channel first, not left? 2. i got a program which process PCM data in java, and PCM data is a byte array, it's way is: int c = 0; for ( int a = 0; a < sampleSize; ) { if (c >= audioDataBuffer.length) { offset++; c -= audioDataBuffer.length; } left[a] = (float) ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767F; right[a] = (float) ((audioDataBuffer[c + 3] << 8) + audioDataBuffer[c + 2]) / 32767F; a++; c += 4; }
and i convert it to C code below: const byte* pfData = reinterpret_cast<const byte*>(pbData); for (size_t i = 0, j=0; i < Samples; ++i, j+=4) { //m_RealIn_RT[i] = static_cast<float>( pfData[j] ); //m_RealIn_LT[i] = static_cast<float>( pfData[j+1] );
m_RealIn_RT[i] = (float)( pfData[j+1]<<8 + pfData[j] ) / 32767; m_RealIn_LT[i] = (float)( pfData[j+3]<<8 + pfData[j+2] ) / 32767; }
and run it, the spectrum(every band) higher than before, why?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
1. No special reason. I believe the C# version reads both channels but only the right one is shown. 2. I'm not sure your conversion is correct. For mono, the correct conversion must be done like this:
if ( wfmt.nChannels == 1 ) // mono { for (size_t i = 0; i < cbSize; ++i) { m_RealIn_RT[i] = static_cast<float>((pbData[i] - 128) << 6);// Out = (In-128)*64 m_RealIn_LT[i] = m_RealIn_RT[i]; } } else if ( wfmt.nChannels == 2 ) // stereo { // Stereo has Left+Right channels size_t Samples = cbSize >> 1; for (size_t i = 0, j=0; i < Samples; ++i, j+=2) { m_RealIn_RT[i] = static_cast<float>((pbData[j] - 128) << 6); // Out = (In-128)*64 m_RealIn_LT[i] = static_cast<float>((pbData[j+1] - 128) <<6); // Out = (In-128)*64 } }
In the end, we will remember not the words of our enemies, but the silence of our friends. - Martin Luther King Jr. Ernest Laurentin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
it's great! i've knew two ways to show spectrum when play music. one is record sound card data and show it, one is use mp3 decoder decodes data to PCM data and show it. your way is third way. my question is: we must use PCM format data to analysis?
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
I'm not sure I understand your question but if you have an MP3, ideally, you need to get the raw data (PCM). The Multimedia streaming class will do that, it gives you back your data as PCM.
In the end, we will remember not the words of our enemies, but the silence of our friends. - Martin Luther King Jr. Ernest Laurentin
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
Hey,
Just scanned this site to find out if there was anyone who had made a peakmeter control for audio for Silverlight and found this article.
Do you think it's possible (and how if it is) to make this control you've made into a Silverlight 2 usercontrol?
Thanks & regards in advance! - Jones M
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You can host winform control. No need to rewrite. Thanks for your feedback.
1. I will develop myself to the maximum of my potential in all ways 2. I will look for the good in all people and make them feel worthwhile. 3. If I have nothing good to say about a person, I will say nothing. 4. I will always be as enthusiastic about the success of others as I am about my own. 5. I will always remain loyal to God, my country, family and my friends - Chuck Norris
Ernest Laurentin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|