Click here to Skip to main content
13,410,805 members (30,853 online)
Click here to Skip to main content
Add your own
alternative version


69 bookmarked
Posted 12 Feb 2010

Sound Scanner and FFT Analyzer

, 16 Feb 2010
Rate this:
Please Sign up or sign in to vote.
Scanning analog input, and FFT convertion and analyzing.


Due to a new project in the company I’ve been working in, we have been engaged in a project which should implement pattern recognition to detect whether an in use gearbox works well or not. The first step was to analyze the gearbox vibration which captured by an ordinary vibration sensor generated analog signals. With the assumption of resembling outcome of a microphone and a vibration sensor, we connect the sensor to the microphone input directly.

Note: If you have a problem with downloading, you can use this or this link. If the problem persists, leave your mail id so it can be sent to you directly! 

Code Explanation

After creating the project and adding PORT.DLL and SoundAnalysis.dll references, it's needed to define Sound related function at header which has been encapsulated in PORT.DLL.

Private Declare Function SOUNDIS Lib "Port.Dll" () As Integer

It's called to detect whether a sound card is available or not. If there is no sound card, the return value will be 0.

Private Declare Function SOUNDGETRATE Lib "Port.Dll" () As Integer

It's called to detect the current sampling rate. Default sampling rate is 11025 which is equal to 11KHz. Other possible sampling rate is 22050 (22KHz) and 44100 (44KHz).

Private Declare Function SOUNDGETBYTES Lib "Port.Dll" () As Integer

It's called to detect the current resolution whether may be 8 bits (1 Byte) or 16 bits (2 Bytes). Default resolution is 8 bits (1 Byte).

Private Declare Function SOUNDSETRATE Lib "Port.Dll" (ByVal Rate As Long) As Long

It's called to set the sampling rate. Accepted passing values are 11025, 22050 and 44100 and the return will be exactly equal to set value. In case of passing other values, resulted error is unknown.

Private Declare Function SOUNDSETBYTES Lib "Port.Dll" (ByVal Rate As Long) As Long

It's called to set the sampling resolution. Accepted passing values are 8 and 16 how return will be exactly equal to set value. I did not check its related error in case of other values.

Private Declare Auto Function BitBlt Lib "gdi32.dll" (ByVal hdcDest As IntPtr,
    ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer,
    ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer,
    ByVal nYSrc As Integer, ByVal dwRop As System.Int32) As Boolean

It's one of the API functions so called my trace in programming which I have been using for making form printing possible. There are two functions in the program (Printing region) that clearly describe how it can be implemented.

Recording Timing NumericUpDown determines the sampling period in milliseconds which sets the timer interval.

Window Filter Size NumericUpDown allocates the length of window filter when 1 means no window filter will be implemented.

There are also two other NumericUpDown shown Freq 01 and Freq 02. These two set the frequency of two intentional noise added to the main signal string to check the correctness of FFT function which can be removed or disabled by just inserting a comment sign in _Data_Capturing() function.

Private Sub Tmr_Runner_Tick(ByVal sender As System.Object,
    ByVal e As System.EventArgs) Handles Tmr_Runner.Tick
        If Not Working Then
            Call _Stop()
            Exit Try
        End If
        Call _Data_Capturing()
        Call _Fourier_Transformation()
        Call Picture_Redrawing_Wave(_Samples_Refined)
        Call Draw_Fourier(_Arr_Spec, _Width_Fourier, _Heigth_Fourier / 2)
    Catch ex As Exception
        Call _Stop()
        MsgBox(ex.ToString, MsgBoxStyle.Critical, "FKR_Sound Scan")
    End Try
End Sub

In Timer events, four functions are called which I can say the program relies on _Data_Capturing() function.

Private Function _Data_Capturing() As Boolean
        Dim I As Integer, J As Integer
        Dim Str_Out As String = ""
        Dim _Sum As Double = 0
        Dim _X_Unit_01 As Single = _Width / _Freq_01
        Dim _X_Unit_02 As Single = _Width / _Freq_02
        Dim _Step_01 As Single = _Width / _Size
        Dim _Temp_01 As Single = 0
        Dim _Temp_02 As Single = 0
        If _Bits = _Sample_Bit.Mono Then
            ReDim _Samples(_Size - 1)
            ReDim _Samples((_Size * 2) - 1)
        End If
        SOUNDIN(_Samples, CLng(_Size))
        If _Bits = _Sample_Bit.Mono Then
            Str_Out = ""
            ReDim _Samples_Refined(_Size - 2)
            For I = 0 To (UBound(_Samples) - 1)
                'The Range is amoung 0 to 255
                _Temp_01 = (I * _Step_01 * 100) Mod (_X_Unit_01 * 100)
                _Temp_01 = _Temp_01 / (100 * _X_Unit_01)
                _Temp_02 = (I * _Step_01 * 100) Mod (_X_Unit_02 * 100)
                _Temp_02 = _Temp_02 / (100 * _X_Unit_02)
                _Samples_Refined(I) = CDbl(CInt(_Samples(I)) - 128) + 
                   (Math.Sin(2 * Math.PI * _Temp_01) * 32) + 
                   (Math.Sin(2 * Math.PI * _Temp_02) * 32)
                _Samples_Refined(I) = ((_Samples_Refined(I) / 128) * _Gain) * 128
            ReDim _Samples_Refined(_Size - 1)
            Dim _Byte_arr(1) As Byte
            For I = 0 To UBound(_Samples) Step 2
                _Byte_arr(0) = _Samples(I)
                _Byte_arr(1) = _Samples(I + 1)
                'The Range changed to 0 to 65535
                _Temp_01 = (I * _Step_01 * 50) Mod (_X_Unit_01 * 100)
                _Temp_01 = _Temp_01 / (100 * _X_Unit_01)
                _Temp_02 = (I * _Step_01 * 50) Mod (_X_Unit_02 * 100)
                _Temp_02 = _Temp_02 / (100 * _X_Unit_02)
                _Samples_Refined(I / 2) = CDbl(CInt(BitConverter.ToInt16(_Byte_arr,
                    0))) + (Math.Sin(2 * Math.PI * _Temp_01) * 512) + 
                    (Math.Sin(2 * Math.PI * _Temp_02) * 512)
                _Samples_Refined(I / 2) = ((_Samples_Refined(I / 2) / 32768) *
                    _Gain) * 32768
        End If
        'Window Filter Implementing
        ReDim _WindowFilter(_Window_Size - 1)
        For I = 0 To UBound(_Samples_Refined)
            _WindowFilter(I Mod _Window_Size) = _Samples_Refined(I)
            _Sum = 0
            For J = 0 To UBound(_WindowFilter)
                _Sum += _WindowFilter(J)
            _Samples_Refined(I) = (_Sum / _Window_Size)
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical, "FKR_Sound Scan")
        Call _Stop()
    End Try
End Function

_Samples is an array being used to store captured data on it, depending on data resolution its size varied between _Size or _Size * 2.

Using SOUNDIN, the captured data is stored in _Samples. There are two variables named _Temp_01 and _Temp_02 that determine points of two intentional noise.

The _Samples_Refined is used to store refined data. Depending on resolution, two different methods are enacted.

_Samples_Refined(I) = CDbl(CInt(_Samples(I)) - 128) + 
                      (Math.Sin(2 * Math.PI * _Temp_01) * 32) + 
                      (Math.Sin(2 * Math.PI * _Temp_02) * 32)

The above is being used if 8 bit resolution is selected. In this case, the returned sampled value varies from 0 to 255 in which 128 means silent, so after casting data to a 32 bit integer, -128 added to, removes its offset. " + (Math.Sin(2 * Math.PI * _Temp_01) * 32) + (Math.Sin(2 * Math.PI * _Temp_02) * 32) " is the effect of intentional noise that can be omitted by just adding an ' before.

_Samples_Refined(I) = ((_Samples_Refined(I) / 128) * _Gain) * 128

It's used to implement user defined gain to refined signal.

It's important to note the returned captured data in 16 bits resolutions varies from -32768 to +32765 so removing the offset is not implemented.

'Window Filter Implementing
ReDim _WindowFilter(_Window_Size - 1)
For I = 0 To UBound(_Samples_Refined)
     _WindowFilter(I Mod _Window_Size) = _Samples_Refined(I)
     _Sum = 0
     For J = 0 To UBound(_WindowFilter)
         _Sum += _WindowFilter(J)
    _Samples_Refined(I) = (_Sum / _Window_Size)

It's just a simple window filtering implemented before FFT function is called.

Private Function _Fourier_Transformation() As Boolean
        _Arr_Spec = SoundAnalysis.FftAlgorithm.Calculate(_Samples_Refined)
        For _I = 0 To CInt(UBound(_Arr_Spec) * 0.95)
            If (_Size * _I / _Arr_Length >= 0) And _
			(_Size * _I / _Arr_Length < 1) Then
                _Arr_Spec(_I) = 0
            End If 
            If (_Size * _I / _Arr_Length > (_Removed_Freq - 1)) And (
                _Size * _I / _Arr_Length < (_Removed_Freq + 1)) Then
                _Arr_Spec(_I) = 0
            End If
            If _Max < _Arr_Spec(_I) Then
                _Max = _Arr_Spec(_I)
                _Index = _I
            End If
End Function

_Arr_Spec saves the returned FFT array using SoundAnalysis.FftAlgorithm.Calculate() function.

It's needed to pay attention that the returned FFT array length is nearest upper 2's power of input array length, e.g., if input array length is 100 (2^6 < 100 < 2^7), output length will be 128 (2^7). Finding the related frequency in an array may seem a bit strange. First of all, note just first half elements are usable and the other second half is exactly the mirror reflection of elements. For calculation related frequency, you have to use this formula:

_Size * _I / _Arr_Length 

where _Size is equal to number of samples, _Arr_Length is returned FFT array (here is _Arr_Spec) and _I is elements index is FFT returned array which have to be between 0 and (_Arr_Length/2) .

If (_Size * _I / _Arr_Length >= 0) And (
    _Size * _I / _Arr_Length < 1) Then
    _Arr_Spec(_I) = 0
End If

The above piece of code is implemented to remove any effective frequency amoung 0 and 1. The same code:

If (_Size * _I / _Arr_Length > (_Removed_Freq - 1)) And (
   _Size * _I / _Arr_Length < (_Removed_Freq + 1)) Then

   _Arr_Spec(_I) = 0

End If

is doing exactly the same which removed frequency determined by related value in Removed Frequency NumericUpDown.

There are two other functions in Timer event that crystal clear using to draw captured signal and FFT signal in related picture boxes.

Points of Interest & Acknowledgements

The project I’ve made is a simple voice spectrum using a DLL as voice in capturing device meanwhile implementing FFT method helping to convert it to frequency. The project structure is simply trying to avoid usual showing off programming complexity. I have to appreciate Mr. Burkhard Kainka for his useful (but a bit CPU grappling!!) .DLL and also thank notmasteryet for very useful FFT convertor.

I would also like to give special thanks to Richard and Sean.

The project is just a simple VB.NET based initiative representation, hopefully the main has to be based on VC++ .NET using DirectSound.

Don’t hesitate to ask if you encounter any problems or have any questions.


  • 12th February, 2010: Initial post
  • 16th February, 2010: Updated source code


This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


About the Author

Mahdi Mansouri
Iran (Islamic Republic of) Iran (Islamic Republic of)
Control System Engineer

You may also be interested in...

Comments and Discussions

QuestionHow to get the frequency in real-time? Pin Pin
Member 1277003713-Mar-17 7:22
memberMember 1277003713-Mar-17 7:22 
QuestionLoad audio file Pin
Member 1263150212-Jul-16 8:29
memberMember 1263150212-Jul-16 8:29 
QuestionSimilar Problem Pin
meusbur225-Nov-14 12:50
membermeusbur225-Nov-14 12:50 
QuestionChoose different sound card Pin
Punhavan Saroeun13-Jun-14 7:16
memberPunhavan Saroeun13-Jun-14 7:16 
QuestionFast Fourier Transform on Noise wave Pin
meghranjani15-Nov-12 20:56
membermeghranjani15-Nov-12 20:56 
AnswerRe: Fast Fourier Transform on Noise wave Pin
Mahdi Mansouri15-Nov-12 22:27
memberMahdi Mansouri15-Nov-12 22:27 
Questionpeaks in each (range) Pin
LuizSp Antonio15-Aug-12 18:22
memberLuizSp Antonio15-Aug-12 18:22 
AnswerRe: peaks in each (range) Pin
Mahdi Mansouri27-Oct-12 19:03
memberMahdi Mansouri27-Oct-12 19:03 
QuestionError windows 7 - 64 bits Pin
Leticia Nascimento13-Aug-12 19:01
memberLeticia Nascimento13-Aug-12 19:01 
AnswerRe: Error windows 7 - 64 bits Pin
pHat201113-Aug-12 19:37
memberpHat201113-Aug-12 19:37 
QuestionFind different overtones of a violine string Pin
peter specht1-Aug-12 7:40
memberpeter specht1-Aug-12 7:40 
AnswerRe: Find different overtones of a violine string Pin
Mahdi Mansouri27-Oct-12 19:36
memberMahdi Mansouri27-Oct-12 19:36 
QuestionHELP please: How to modify this to work for 2 channels (stereo) Pin
yassindds23-Jun-12 11:44
memberyassindds23-Jun-12 11:44 
AnswerRe: HELP please: How to modify this to work for 2 channels (stereo) Pin
Mahdi Mansouri27-Oct-12 19:37
memberMahdi Mansouri27-Oct-12 19:37 
QuestionDll Error returned. Pin
Txon12-Jun-12 0:06
memberTxon12-Jun-12 0:06 
AnswerRe: Dll Error returned. Pin
Stefan Clements22-Jun-12 0:17
memberStefan Clements22-Jun-12 0:17 
Questionport.dll problem with windows 7 64 bit, VS 2010 Pin
marcopmp9-May-12 4:31
membermarcopmp9-May-12 4:31 
AnswerRe: port.dll problem with windows 7 64 bit, VS 2010 Pin
Mahdi Mansouri27-Oct-12 19:39
memberMahdi Mansouri27-Oct-12 19:39 
Questionthrough speech controling game Pin
maheen shah18-Apr-12 8:22
membermaheen shah18-Apr-12 8:22 
AnswerRe: through speech controling game Pin
Mahdi Mansouri27-Apr-12 9:39
memberMahdi Mansouri27-Apr-12 9:39 
QuestionDetecting Specific Frequencies Pin
Oliver Dalton5-Mar-12 4:17
memberOliver Dalton5-Mar-12 4:17 
AnswerRe: Detecting Specific Frequencies Pin
Mahdi Mansouri13-Mar-12 3:50
memberMahdi Mansouri13-Mar-12 3:50 
QuestionRemark Pin
Viktor Signaievskyi15-Dec-11 9:22
memberViktor Signaievskyi15-Dec-11 9:22 
AnswerRe: Remark Pin
Mahdi Mansouri13-Mar-12 3:02
memberMahdi Mansouri13-Mar-12 3:02 
AnswerError in FFT Routine Pin
Member 797603124-Jul-11 8:50
memberMember 797603124-Jul-11 8:50 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.180221.1 | Last Updated 16 Feb 2010
Article Copyright 2010 by Mahdi Mansouri
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid