Reputation: 417
I'm attempting to write a peak volume meter using NAudio. My code is very similar to http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder, but both my code and the linked Voice Recorder project suffer from an issue.
When playing a sound of constant frequency and volume, the volume meter initially begins at a reasonable level, but then decays to a very small value. I'm not sure why this is the case, for the peak volume meter in the NAudioDemo does not do this. I attempted to replicate the code from NAudioDemo in my program, but I was unable to find the code file containing the peak volume meter code.
Can somebody guide me to an alternative solution for creating a peak volume meter or help me determine why my solution (and the one provided at the link) both don't work?
public MainWindow()
{
int waveInDevices = WaveIn.DeviceCount;
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
Console.WriteLine("Device {0}: {1}, {2} channels",
waveInDevice, deviceInfo.ProductName, deviceInfo.Channels);
WaveIn waveIn = new WaveIn();
waveIn.DeviceNumber = 0; //TODO: Let the user choose which device, this comes from the device numbers above
waveIn.DataAvailable += waveIn_DataAvailable;
int sampleRate = SAMPLE_RATE; // 8 kHz
int channels = 1; // mono
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
}
}
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
for (int index = 0; index < e.BytesRecorded; index += 2)
{
short sample = (short)((e.Buffer[index + 1] << 8) |
e.Buffer[index + 0]);
float sample32 = sample / 32768f;
ProcessSample(sample32);
}
}
void ProcessSample(float sample1)
{
samplenumber += 1;
if (sample1 > maxval)
{
maxval = sample1;
}
if (sample1 < minval)
{
minval = sample1;
}
//Run updateView every few loops
if (samplenumber > (double)SAMPLE_RATE / DISPLAY_UPDATE_RATE)
{
samplenumber = 0;
updateView(); //needs to be fast!
}
}
void updateView()
{
Console.WriteLine(maxval);
Console.WriteLine(minval);
progressBar1.Value = (maxval - minval)*50;
maxval = 0;
minval = 0;
}
Upvotes: 3
Views: 14524
Reputation: 617
Trying to get the levels with MasterPeakValue appears to be more complicated than just calling the method, which defeats its simplicity.
I accidentally realized that you have to open the device for recording, even if you don't use with the incoming data. Since you are starting a WaveIn, MasterPeakValue should return a non-0 value.
A simple alternative, just for testing, is to open the properties of system's recording devices (right-click on system volume icon and choose "Recording devices").
(Tested on 2 different computers.)
Upvotes: 0
Reputation: 769
This was my little solution for getting peak from output device. I'm using NAudio version 1.7.0.15
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
var devices = enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
comboboxDevices.Items.AddRange(devices.ToArray());
}
private void timer1_Tick(object sender, EventArgs e)
{
if (comboboxDevices.SelectedItem != null)
{
var device = (MMDevice)comboboxDevices.SelectedItem;
progressBar1.Value = (int)(Math.Round(device.AudioMeterInformation.MasterPeakValue * 100));
}
}
}
Upvotes: 3
Reputation: 49522
All that is happening in that article is that it is finding the maximum audio peak over a small interval (e.g. 20ms) and then plotting that on a decibel scale. To find the peak, examine the value of each sample in the interval and select the max value (It's what the SampleAggregator
class is doing). To convert to decibels, take the log base 10 of the maximum value, and multiply by 10. So 0dB is the loudest, and anything below say -96dB is effectively silence. (actually, looking back at the article, I don't think I even bothered to convert to a decibel scale, which I probably should have done)
Upvotes: 6