How to calculate dB from StreamVolumeEventArgs.MaxSampleValues of NAudio? - c#

I am trying to implement a volume meter to help users select their microphone using NAudio. I need to do my best to weed out devices that just have background noise and insure I show something when they talk.
We are currently using version 1.7.3 within a Unity3D application so none of the MMDevice related approaches are available as they crash.
I am using a WaveInEvent that I feed into a WaveInProvider that I subsequently feed to a SampleChannel. I feed the SampleChannel into a MeteringSampleProvider which I have subscribed to the StreamVolume event.
In my OnPostVolumeMeter event handler when I receive the StreamVolumeEventArgs (I named the parameter e) I'm wondering how to calculate decibels. I have seen plenty of examples that fish out the peak volume (or sometimes it seems to be referred to as an amplitude) from e.MaxSampleValues[0]. Some examples check whether it is a stereo signal and will grab the max between e.MaxSampleValues[0] or e.MaxSampleValues[1].
Anyway, what are the values of this number? Is it a percentage? They are relatively small decimals (10^-3 or 10^-4) when I hillbilly debug to the console.
Is the calculation something like,
var peak = e.MaxSampleValues[0];
if (e.MaxSampleValues.Length > 1)
{
peak = Mathf.Max(e.MaxSampleValues[0], e.MaxSampleValues[1]);
}
var dB = Mathf.Max(20.0f*Mathf.Log10(peak), -96.0f);
or do I need to divide peak by 32768.0? As in,
var dB = Mathf.Max(20.0f*Mathf.Log10(peak/32768.0f), -96.0f);
Is this approach totally incorrect and I need to collect a buffer of samples that I do an RMS sort of calculation where I calculate the square root of the sum of the averages divided by the number of samples all divided by 32768 and feed that into the Log10?
I've seen several references to look at the AudioPlaybackPanel of the NAudioDemo and it sets the volumeMeter Amplitude to be the values of e.MaxSampleValues[0] and e.MaxSampleValues[1]

looking at the date of your post this is probably a solved issue for you but of the benefit of others here goes.
Audio signals swing between negative and positive values in a wave. The frequency of the swing and the Amplitude or height of the swing effect what you hear.
You are correct in saying you are looking for the amplitude to see if audio is present.
For a meter as the sample rate is much higher than the refresh rate of any meter you are likely to display, you will need to either record the peak using math.max or do an average over a number of samples. In your case either would work, unless you are trying to show an accurate meter in bdFS the db calculation would not be needed.
In apps where I have been looking to trigger things based on the presence of audio or lack their of. I normally convert the samples to a float this will give you a range between 0 and 1 and then pick a threshold say 0.2 and say if any sample is above that we have audio.
a float also provides a nice indicative meter for display. Note if your app was for a pro audio application and you were asking about accurate metering my answer would be totally different.

Related

C# Arduino headtracking MPU6050

i'm working on an application that can help people with disabilites to uses the computer. The application reads values from Arduino+MPU6050 (wich is positioned over the head), and converts it into position. The values from serial ports are like "x,y", and the scale of this values goes from -16000 to +16000.
I processing this values in my computemethod (i report it at bottom of this post). Everything works fine, but i have a problem. If the person that use this software/hardware has some type of muscle spams or tics, the software is too precise and moves the mouse. I want to eliminate this chronical movement...how can i do this?
This is the code of computePosition..
public void computePosition()
{
data = connection.readSeriaLine();
words = data.Split(',');
yaw = words[0];
pitch = words[1];
Int32.TryParse(pitch, out posiY);
Int32.TryParse(yaw, out posiX);
posiX = posiX / headSensitivity;
posiX = posiX - globalPosiX;
posiY = posiY / headSensitivity;
posiY = posiY - globalPosiY;
int signX = Math.Sign(posiX);
int signY = Math.Sign(posiY);
int positionX = Cursor.Position.X;
int positionY = Cursor.Position.Y;
Cursor.Position = new Point(positionX + (signX * movementSensitivity), positionY + (signY * movementSensitivity));
}
Many thanks
I would recommmend you use data processing of movement artefacts in firmware. Sicknesses, like Parkinson desease have tremor at frequencies 1-20 Hz. You can use programmatical filters with adaptation to determined frequency.
To calculate frequency use Fourier transform for accelerometer and gyro raw data.
So, in general you should:
store raw data of sensors in corresonding arrays
do FFT
process filtering for the arrays (cut off dominant frequencies from FFT)
send data to motion processing and then to PC
You can try to do the same on X,Y coordinates in winform app. What way you will use depends on what artefacts you encounter in each particular case. You may even need different filter's setups for warious deseases or self-learning algorithms for each patient.
P.S. You may receive more answers if mark the question with "math" (or similar) tag. Because it lays not in C# or Arduino field.
Update.
Before doing programming i would recommend you to do some research work. First of all you need to gather data from the sensors weared on a man with certain desease. You need at least 30-60 seconds of data containing ticks movement artefacts. Write data in 3 columns:
time in ms | x position | y position
Then go to labchart reader download page, download and install it. Open file with data and do "spectrum" command/view on both X and Y. This will give you info about frequencies which are present (both artefacts and "good" movements). I suppose movement artefact frequencies have bigger amplitude. Remember those frequencies.
Then do "digital filter"-> "band stop" command. And cut off frequencies from previous step. I hope that after this proccessing you will see good charts without artefacts.
Then you can do programming. Implementing FFT and digital filtering is not really hard. For FFT you can use Aforge.Math library.

How to detect string when pitch-tracking on electric guitar?

Hi I'm a noob in audio related coding and I'm working in a pitch tracking DLL that I will use to try to create a sort of open-source version of the video-game Rocksmith as a learning experience.
So far I have managed to get the FFT to work so I can detect pitch frequency (Hz) then by using an algorithm and the table below I can manage to determine the octave (2th to 6th) and the note (C to B) for played note.
The next step is to detect the string so I can determine the fret.
I've been thinking about it and in theory I can work with this, I will know when the user is playing the right note but the game could be "Hack" because by just using the Hz the game is not able to detect if a note is played in the right string. For example 5th string + 1th fret = C4 261.63Hz is equals to 6th string + 5th fret = C4 261.63Hz.
The chances of having an user playing a note in the wrong string and getting it right is low, but I think it would be really good to know the string so I can provide to the users some error feedback when they play the wrong string (Like you should go a string up or down).
Do you know what can I do to detect the string? Thanks in advance :)
[edit]
The guitar and strings that we are using affect the timbre so analyzing the timbre seems to not be a easy way of detecting strings:
"Variations in timbre on your guitar are produced by an enormous number of factors from pickup design and position, the natural resonances and damping in your guitar due to the wood used (that's a different sort of timber!) and its construction and shape, the gauge and age of your strings, your playing technique, where you fret and pluck the string, and so on."
This might be a little bit late because the post is one years old. But here's a solution, which I found out after long research for pitch detecting a guitar.
THIS IS WHY FFT DOESN'T WORK :
You cannot use FFT since the result gives you a linear array, and the sound is calculated logarithmically (exponential distance between notes). Plus, FFT gives you an array of bins in which your frequency COULD BE, it doesnt give you the precise result.
THIS IS WHAT I SUGGEST :
Use dywapitchtrack. it's a library that uses a wavelet algorythm, which works directly on your wave instead of calculating large bins like FFT.
description:
The dywapitchtrack is based on a custom-tailored algorithm which is of very high quality:
both very accurate (precision < 0.05 semitones), very low latency (< 23 ms) and
very low error rate. It has been thoroughly tested on human voice.
It can best be described as a dynamic wavelet algorithm (dywa):
DOWNLOAD : https://github.com/inniyah/sndpeek/tree/master/src/dywapitchtrack
USE(C++):
put the .c and .h where you need it and import it in your project
include the header file
//Create a dywapitchtracker Object
dywapitchtracker pitchtracker;
//Initialise the object with this function
dywapitch_inittracking(&pitchtracker);
When your buffer is full (buffer needs to be at 44100 resolution and power of 2 of length, mine is 2048):
//use this function with your buffer
double thePitch = dywapitch_computepitch(&pitchtracker, yourBuffer, 0, 2048);
And voilĂ , thePitch contains precisely what you need. (feel free to ask question if something is unclear)
An simple FFT peak estimator is not a good guitar pitch detector/estimator, due to many potentially strong overtones. There exist more robust pitch estimation algorithms (search stackoverflow and DSP.stackexchange). But if you require the players to pre-characterize each string on their individual instruments, both open and fretted, before starting the game, an FFT fingerprint of those characterizations might be able to differentiate the same note played on different strings on some guitars. The thicker strings will give off slightly different ratios of energy in some of the higher overtones, as well as different amounts of slight inharmonicity.
The other answers seem to suggest a simple pitch detection method. However, it is something you will have to research.
Specifically, compare the overtones of 5th string 1st fret to sixth string 5th fret. that is, only look at 261.63*2, 261.63*3, *4, etc. Also, try looking at 261.63*0.5. Compare the amplitudes of the two signals at these freqs. There might be a pattern that could be detected.

calculating frequency for signal in c# .net

I am developing an application for an oscilloscope in c# .NET, I am drawing different kinds of waves (sine, square etc..) with the help of zedgraph control.
I get values from oscilloscope and stored in a buffer of size 1024(byte array) and have to calculate parameters like time period, Frequency, rise time, fall time etc at run time.
for this purpose i have to extract only a single cycle of whole signal.one more problem is that values are not always rise or fall continuously mean values are stored in buffer like this[0,0,0,1,1,2,3,4,5,5,6,6,6,5,5,4,3,2,1,1,0,0,0..........]. signals are continuously receive from machine.
it is not sure that waves are always oscillating around zero.
Thanks
Regards
Nilesh
You can estimate the frequency a number a of ways. Probably the easiest, if you have a math lib, is to compute the FFT and take the lowest frequency.
Alternatively you can check the zero crossings(around the mean value). The faster it oscillates about 0 the higher its frequency. Similarly the extrema tell you a lot about the frequency(think of a sinusoid whose extrema and zeroes alternate and are evenly spaced).
There is also a transform called the period transform but I don't remember it too much. I saw it in a book about music for finding the tempo of a song.
http://www.cs.berkeley.edu/~vazirani/s09quantum/notes/lecture4.pdf
Another way might be to use the auto-correlation and when it is large it means the function is in "sync" with itself(assuming it doesn't change shape to fast). and it should be easy to calculate the distance between these the maximums.
You could find out the time period between a crest and a trough, which will give you half the wavelength for that particular wave.
For graph 1, the first trough is 2, the first crest is 12. Find out the time taking between these points, and you have half the wavelength.
For graph two, the same principle applies, you can calculate the wavelength (and thus the period) for each section of the graph

Simple signal processing in C#

I'm sampling a real-world sensor, and I need to display its filtered value. The signal is sampled at a rate of 10 Hz and during that period it could rise as much as 80 per cent of the maximum range.
Earlier I've used Root Mean Square as a filter and just applying it to the last five values I've logged. For this application this wouldn't be good because I don't store unchanged values. In other words, I need to consider time in my filter...
I've read at DSP Guide, but I didn't get much out of it. Is there a tutorial that's pinned specifically at programmers, and not Mathcad engineers? Are there some simple code snippets that could help?
Update: After several spreadsheet tests I've taken the executive decision to log all samples, and apply a Butterworth filter.
You always need to store some values (but not necessarily
all input values). A filter's current output depends on a
number of input values and possibly some past output values.
The simplest filter would be a first order Butterworth low-pass
filter. This would only require you to store one past output
value. The (current) output of the filter, y(n) is:
y(n) = x(n) - a1 * y(n-1)
where x(n) is the current input and y(n-1) is the previous
output of the filter. a1 depends on the cut-off frequency
and the sampling frequency. The cut-off frequency frequency
must be less than 5 Hz (half the sampling frequency),
sufficiently low to filter out the noise, but not so low
that the output will be delayed with respect to the input. And of
course not so low that the real signal is filtered out!
In code (mostly C#):
double a1 = 0.57; //0.57 is just an example value.
double lastY = 0.0;
while (true)
{
double x = <get an input value>;
double y = x - a1 * lastY;
<Use y somehow>
lastY = y;
}
Whether a first order filter is sufficient depends on your
requirements and the characteristics of the input signal (a
higher order filter may be able to suppress more of the
noise at the expense of higher delay of the output signal).
For higher order filters, more values would have to be stored
and the code becomes a little bit more complicated. Usually
the values need to be shifted down in arrays; in an array
for past y values and in an array for past x values.
In DSP, the term "filter" usually refers to the amplification or attenuation (i.e. "lowering") of frequency components within a continuous signal. This is commonly done using Fast Fourier Transform (FFT). FFT starts with a signal recorded over a given length of time (the data are in what's called the "time domain") and transforms these values into what's called the "frequency domain", where the results indicate the strength of the signal in a series of frequency "bins" that range from 0 Hz up to the sampling rate (10 Hz in your case). So, as a rough example, an FFT of one second's worth of your data (10 samples) would tell you the strength of your signal at 0-2 Hz, 2-4 Hz, 4-6 Hz, 6-8 Hz, and 8-10 Hz.
To "filter" these data, you would increase or decrease any or all of these signal strength values, and then perform a reverse FFT to transform these values back into a time-domain signal. So, for example, let's say you wanted to do a lowpass filter on your transformed data, where the cutoff frequency was 6 Hz (in other words, you want to remove any frequency components in your signal above 6 Hz). You would programatically set the 6-8 Hz value to zero and set the 8-10 Hz value to 0, and then do a reverse FFT.
I mention all this because it doesn't sound like "filtering" is really what you want to do here. I think you just want to display the current value of your sensor, but you want to smooth out the results so that it doesn't respond excessively to transient fluctuations in the sensor's measured value. The best way to do this is with a simple running average, possibly with the more recent values weighted more heavily than older values.
A running average is very easy to program (much easier than FFT, trust me) by storing a collection of the most recent measurements. You mention that your app only stores values that are different from the prior value. Assuming you also store the time at which each value is recorded, it should be easy for your running average code to fill in the "missing values" by using the recorded prior values.
I don't have a tutorial that will help you, but in C# you may want to consider using Reactive LINQ - see blog post Reactive programming (II.) - Introducing Reactive LINQ.
As a way to get the events, so you can do your processing without having to store all the values, it would just do the processing as you get the next event in.
To consider time, you could just use an exponential with a negative exponent to decrease the impact of the past measurements.
Yes, for complex real-time systems sampling multiple streams of data, there could be an issue in the data processing (calculation and storage of data) and data consistency.

Beats per minute from real-time audio input

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
I'd like to write a simple C# application to monitor the line-in audio and give me the current (well, the rolling average) beats per minute.
I've seen this gamedev article, and that was absolutely no help. I went through and tried to implement what he was doing but it just wasn't working.
I know there have to be tons of solutions for this, because lots of DJ software does it, but I'm not having any luck in finding any open-source library or instructions on doing it myself.
Calculate a powerspectrum with a sliding window FFT:
Take 1024 samples:
double[] signal = stream.Take(1024);
Feed it to an FFT algorithm:
double[] real = new double[signal.Length];
double[] imag = new double[signal.Length);
FFT(signal, out real, out imag);
You will get a real part and an imaginary part. Do NOT throw away the imaginary part. Do the same to the real part as the imaginary. While it is true that the imaginary part is pi / 2 out of phase with the real, it still contains 50% of the spectrum information.
EDIT:
Calculate the power as opposed to the amplitude so that you have a high number when it is loud and close to zero when it is quiet:
for (i=0; i < real.Length; i++) real[i] = real[i] * real[i];
Similarly for the imaginary part.
for (i=0; i < imag.Length; i++) imag[i] = imag[i] * imag[i];
Now you have a power spectrum for the last 1024 samples. Where the first part of the spectrum is the low frequencies and the last part of the spectrum is the high
frequencies.
If you want to find BPM in popular music you should probably focus on the bass. You can pick up the bass intensity by summing the lower part of the power spectrum. Which numbers to use depends on the sampling frequency:
double bassIntensity = 0;
for (i=8; i < 96; i++) bassIntensity += real[i];
Now do the same again but move the window 256 samples before you calculate a new spectrum. Now you end up with calculating the bassIntensity for every 256 samples.
This is a good input for your BPM analysis. When the bass is quiet you do not have a beat and when it is loud you have a beat.
Good luck!
There's an excellent project called Dancing Monkeys, which procedurally generates DDR dance steps from music. A large part of what it does is based on (necessarily very accurate) beat analysis, and their project paper goes into much detail describing the various beat detection algorithms and their suitability to the task. They include references to the original papers for each of the algorithms. They've also published the matlab code for their solution. I'm sure that between those you can find what you need.
It's all available here: http://monket.net/dancing-monkeys-v2/Main_Page
Not that I have a clue how to implement this, but from an audio engineering perspective you'd need to filter first. Bass drum hits would be the first to check. A low pass filter that gives you anything under about 200Hz should give you a pretty clear picture of the bass drum. A gate might also be necessary to cleanup any clutter from other instruments with harmonics that low.
The next to check would be snare hits. You'd have to EQ this one. The "crack" from a snare is around 1.5kHz from memory, but you'd need to definitely gate this one.
The next challenge would be to work out an algorithm for funky beats. How would you programatically find beat 1? I guess you'd keep track of previous beats and use a pattern matching something-or-other. So, you'd probably need a few bars to accurately find the beat. Then there's timing issues like 4/4, 3/4, 6/8, wow, I can't imagine what would be required to do this accurately! I'm sure it'd be worth some serious money to audio hardware/software companies.
This is by no means an easy problem. I'll try to give you an overview only.
What you could do is something like the following:
Compute the average (root-mean-square) loudness of the signal over blocks of, say, 5 milliseconds. (Having never done this before, I don't know what a good block size would be.)
Take the Fourier transform of the "blocked" signal, using the FFT algorithm.
Find the component in the transformed signal that has the largest magnitude.
A Fourier transform is basically a way of computing the strength of all frequencies present in the signal. If you do that over the "blocked" signal, the frequency of the beat will hopefully be the strongest one.
Maybe you need to apply a filter first, to focus on specific frequencies (like the bass) that usually contain the most information about the BPM.
I found this library which seem to have a pretty solid implementation for detecting Beats per Minute.
https://github.com/owoudenberg/soundtouch.net
It's based on http://www.surina.net/soundtouch/index.html which is used in quite a few DJ projects http://www.surina.net/soundtouch/applications.html
First of all, what Hallgrim is producing is not the power spectral density function. Statistical periodicities in any signal can be brought out through an autocorrelation function. The fourier transform of the autocorrelation signal is the power spectral density. Dominant peaks in the PSD other than at 0 Hz will correspond to the effective periodicity in the signal (in Hz)...
The easy way to do it is to have the user tap a button in rhythm with the beat, and count the number of taps divided by the time.
I'd recommend checking out the BASS audio library and the BASS.NET wrapper. It has a built in BPMCounter class.
Details for this specific function can be found at
http://bass.radio42.com/help/html/0833aa5a-3be9-037c-66f2-9adfd42a8512.htm.

Categories