Skip to content

Instantly share code, notes, and snippets.

@GregaMohorko
Last active April 13, 2017 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GregaMohorko/356a60d269e8f403af151b1504034b26 to your computer and use it in GitHub Desktop.
Save GregaMohorko/356a60d269e8f403af151b1504034b26 to your computer and use it in GitHub Desktop.
Audio signal analysis to get information about frequencies.
using System;
using NAudio.Dsp;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
namespace GM.SP.Audio
{
public static class SignalAnalysis
{
public class Frequency
{
public float Hz { get; set; }
public float Amplitude { get; set; }
public float Phase { get; set; }
}
public static Frequency[] AnalyzeAudioFile(string audioFile)
{
WaveStream audioWaveProvider = null;
try {
// open audio file
if(audioFile.ToLower().EndsWith(".mp3"))
audioWaveProvider = new Mp3FileReader(audioFile);
else if(audioFile.ToLower().EndsWith(".wav"))
audioWaveProvider = new WaveFileReader(audioFile);
else
throw new Exception("Unsupported format.");
// create a sample provider
ISampleProvider audioSampleProvider;
switch(audioWaveProvider.WaveFormat.BitsPerSample) {
case 8:
audioSampleProvider = new Pcm8BitToSampleProvider(audioWaveProvider);
break;
case 16:
audioSampleProvider = new Pcm16BitToSampleProvider(audioWaveProvider);
break;
case 24:
audioSampleProvider = new Pcm24BitToSampleProvider(audioWaveProvider);
break;
case 32:
audioSampleProvider = new Pcm32BitToSampleProvider(audioWaveProvider);
break;
default:
throw new Exception("Unsupported bits per sample in audio file.");
}
// read all samples (includes left and right channel in case of stereo)
float[] allSamples = new float[audioWaveProvider.Length / (audioWaveProvider.WaveFormat.BitsPerSample / 8)];
audioSampleProvider.Read(allSamples, 0, allSamples.Length);
// unzip to one channel samples that are to be analyzed
float[] samples;
if(audioWaveProvider.WaveFormat.Channels == 2)
samples = AudioUtility.Unzip(allSamples).Item1;
else
samples = allSamples;
return AnalyzeAudio(samples,audioWaveProvider.WaveFormat.SampleRate);
} finally {
audioWaveProvider?.Dispose();
}
}
/// <summary>
/// If the count of samples is not a power of 2, it will be padded by zeros until the next larger power of 2.
/// </summary>
public static Frequency[] AnalyzeAudio(float[] samples,int sampleRate)
{
// size must be a power of 2
int size = 1;
int m = 0;
while(size < samples.Length) {
size <<= 1;
++m;
}
// create complex numbers from floats (X is real, Y is imag)
Complex[] fftResults = new Complex[size];
for(int i = samples.Length - 1; i >= 0; --i)
fftResults[i] = new Complex() { X = samples[i], Y = 0 };
// fourier transform
FastFourierTransform.FFT(true, m, fftResults);
float frequencyStep = sampleRate / (float)size;
Frequency[] frequencies = new Frequency[size / 2];
for(int i = 0; i < frequencies.Length; ++i) {
Complex v = fftResults[i];
Frequency f = new Frequency();
f.Hz = (i+1) * frequencyStep;
f.Amplitude = (float)Math.Sqrt(Math.Pow(v.X, 2) + Math.Pow(v.Y, 2));
f.Phase = (float)Math.Atan(v.Y / v.X);
frequencies[i] = f;
}
return frequencies;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment