Deteccion de Sonido Con Vb.Net

Un detector de sonido es una practica aplicacion que se puede realizar implementando un microfono para determinar cualquier tipo de ruido que se produzca y posteriormente realizar cualquier actividad especifica al escuchar dicho sonido, existen dispositivos electronicos especializados para realizar dicha labor, sin embargo, en este tutorial se va a explicar una forma alternativa de llevarlo acabo con nuestro computador.

para poder realizar esta aplicacion, vamos a hacer uso de la transformada rapida de fourier y de varias clases que nos permiten capturar la entrada de audio, generar la onda y determinar el umbral de aproximacion de la onda a partir del cual se decidira si existe sonido o no.

La aplicacion tendra la siguiente interfaz:

Bien amigos, para comenzar debo aclara que para la realizacion de este software me he basado en varias aplicaciones que he conseguido util, como son:

Grabador y activador de sonido con c# y Visualizador de sonido en c# ambos alojados en la pagina web CodeProject.

Ahora elaboramos una presentacion como la siguiente en vb:

aqui, agregamos 1 picturebox, 2 botones, 1 TrackBar para graduar la sensibilidad de la captura de audio, 1 groupbox, 2 textbox y varios labels, se puede personalizar al gusto con otros picturebox tal y como se ve en la anterior imagen.

Bien, acontinuacion es necesario crear las siguientes clases:

* WaveOut.vb  para procesar y presentar la salida del audio capturado.

* WaveNative.vb Para realizar operaciones en el core con la tarjeta de audio.

* WaveIn.vb  Encargada de procesar el audio que esta entrando por el microfono.

* SignalGenerator.vb Para crear la onda y si se desea se puede variar la forma de la onda por sinusoidal, triangular, cuadrada, etc.

* FourierTransform.vb que es la que recibe la onda auditiva y la transforma en una descomposición en distintas frecuencias,

* FifoStream.vb Para procesar el flujo de entrada y salida,

* AudioFrame.vb para realizar gran parte de la deteccion del audio y personalizar las graficas.

Sabiendo ya las clases que vamos a necesitar, podemos proceder a codificar nuestro proyecto, en esta ocasion, solo voy escribir un fragmento de la clase AudioFrame ya que es la que vamos a utilizar en gran manera para interactuar con los elementos del formulario y es la que se encarga de determinar si hay sonido o no. En Dicho fragmento se estudiara solamente la subrutina proccess, tal y como se ve a continuacion:

Clase  AudioFrame.vb:

Imports System.Drawing

Imports System.Windows.Forms

Namespace detector_de_sonido

Class AudioFrame

Private _canvasTimeDomain As Bitmap

Private _canvasFrequencyDomain As Bitmap

Private _waveLeft As Double()

Private _waveRight As Double()

Private _fftLeft As Double()

Private _fftRight As Double()

Private _signalGenerator As SignalGenerator

Private _isTest As Boolean = False

Public IsEventActive As Boolean = False

Public IsDetectingEvents As Boolean = False

Public AmplitudeThreshold As Integer

'valor original de la amplitud=16384

Public Sub New(ByVal isTest As Boolean)

_isTest = isTest

End Sub

Public Sub Process(ByRef wave As Byte())

IsEventActive = False

_waveLeft = New Double(wave.Length \ 4 - 1) {}

_waveRight = New Double(wave.Length \ 4 - 1) {}

If _isTest = False Then

' Split out channels from sample

Dim h As Integer = 0

For i As Integer = 0 To wave.Length - 1 Step 4

_waveLeft(h) = CDbl(BitConverter.ToInt16(wave, i))

_waveRight(h) = CDbl(BitConverter.ToInt16(wave, i + 2))

If IsDetectingEvents = True Then

If _waveLeft(h) > AmplitudeThreshold OrElse _waveLeft(h) < -AmplitudeThreshold Then

IsEventActive = True

End If

End If

_waveRight(h) = CDbl(BitConverter.ToInt16(wave, i + 2))

If IsDetectingEvents = True Then

If _waveRight(h) > AmplitudeThreshold OrElse _waveRight(h) < -AmplitudeThreshold Then

IsEventActive = True

End If

End If

h += 1

Next

End If

End Sub
End Class

End Namespace

las variables IsEventActive, e IsDetectingEvents son las encargadas de controlar las interrupciones que determinan si existe algun sonido, ademas la variable AmplitudeThreshold indica el umbral o nivel maximo de la amplitud de la onda para determinar que ha ocurrido algun evento o ha entrado algun sonido.

Como la entrada de un microfono es una señal estero en la mayoria de los casos se realiza una comparacion con la onda izquierda que representa la señal con la variable que establece el umbral y se hace la misma comparacion nuevamente pero con la onda de la entrada derecha, si la señal de entrada supera al umbral establecido automaticamente se coloca la variable IsEventActive en true o activa tal y como se puede observar en el fragmento de codigo de arriba dentro del ciclo for.

Bien para poder continuar es necesario descargar todas las clases que conforman el proyecto, por ello les coloco el siguiente link para que encuentren la informacion completa de las clases: Bajar Clases del Proyecto.

a continuacion pasemos a programar dentro del formulario:

Inicialmente importemos las siguientes librerias,

Imports System.Collections.Generic

Imports System.ComponentModel

Imports System.Data

Imports System.Drawing

Imports System.Text

Imports System.Windows.Forms

Imports Deteccion_de_Sonido.detector_de_sonido  'lleva el nombre de acuerdo al espacio de nombre o namespace que definamos en las clases indicadas

Imports System.Threading

'-----------

Imports System.Diagnostics.Process

Imports System.IO.Path

Luego declaremos las siguientes variables como globales:

Private _recorder As WaveInRecorder

Private _recorderBuffer As Byte()

Private _player As WaveOutPlayer

Private _playerBuffer As Byte()

Private _stream As FifoStream

Private _waveFormat As WaveFormat

Private _audioFrame As AudioFrame

Private _audioSamplesPerSecond As Integer = 44100

Private _audioFrameSize As Integer = 16384

Private _audioBitsPerSample As Byte = 16

Private _audioChannels As Byte = 2

Private _isPlayer As Boolean = False

Private _isTest As Boolean = False

Dim contador_eventos As Integer

Dim indicador, i, sensibilidad, cant_proces As Integer

' Creamos una variable del tipo Thread

Private hebra As Thread

Dim pList1() As Process

Ahora vamos a crear la funcion Start que es la encargada de iniciar la entrada de audio por el microfono, hay que recordar que aqui en esta funcion vamos a activar o colocar en true la variable IsDetectingEvents para que se comience a comparar la señal de audio que entra con el umbral establecido para la amplitud.
la funcion o porcedimiento start se observa a continuacion:

Private Sub Start()

Stop_sonido()

Try

_waveFormat = New WaveFormat(_audioFrameSize, _audioBitsPerSample, _audioChannels)

_recorder = New WaveInRecorder(0, _waveFormat, _audioFrameSize * 2, 3, New BufferDoneEventHandler(AddressOf DataArrived))

If _isPlayer = True Then

_player = New WaveOutPlayer(-1, _waveFormat, _audioFrameSize * 2, 3, New BufferFillEventHandler(AddressOf Filler))

End If

textBox1.AppendText(DateTime.Now.ToString() & " : Dispositivo de Audio Inicializado" & vbCr & vbLf)

textBox1.AppendText(DateTime.Now.ToString() & " : Dispositivo de Audio en Escucha" & vbCr & vbLf)

textBox1.AppendText(DateTime.Now & " : Muestras Por Segundo = " & _audioSamplesPerSecond.ToString() & vbCr & vbLf)

textBox1.AppendText(DateTime.Now & " : Tamaño de la Trama = " & _audioFrameSize.ToString() & vbCr & vbLf)

textBox1.AppendText(DateTime.Now & " : Bits por Muestra = " & _audioBitsPerSample.ToString() & vbCr & vbLf)

textBox1.AppendText(DateTime.Now & " : Canales = " & _audioChannels.ToString() & vbCr & vbLf)

_audioFrame.IsDetectingEvents = True

Catch ex As Exception

textBox1.AppendText(DateTime.Now & " : Ha Ocurrido una excepcion con el Audio" & vbCr & vbLf & ex.ToString() & vbCr & vbLf)

End Try

End Sub

Luego pasamos a crear la funcion stop_sonido que detiene la entrada de audio y libera de la memoria el player o el procesamiento de la onda

Sub Stop_sonido()

If _recorder IsNot Nothing Then

Try

_recorder.Dispose()

Finally

_recorder = Nothing

End Try

End If

If _isPlayer = True Then

If _player IsNot Nothing Then

Try

_player.Dispose()

Finally

_player = Nothing

End Try

End If

' clear all pending data

_stream.Flush()

End If

End Sub

Ahora, en el evento load del formulario colocamos lo siguiente:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

sensibilidad = 16384

CheckForIllegalCrossThreadCalls = False 'Desactiva error por subproceso

contador_eventos = 0

Me.Text_num_eventos.Text = 0

indicador = 0

i = 0

If WaveNative.waveInGetNumDevs() = 0 Then

TextBox1.AppendText(DateTime.Now.ToString() & " : El Dispositivo de Audio no se Encuentra Disponible" & vbCr & vbLf)

Else

If _isPlayer = True Then

_stream = New FifoStream()

End If

_audioFrame = New AudioFrame(_isTest)

_audioFrame.AmplitudeThreshold = sensibilidad

Start()

End If

pList1 = Process.GetProcesses()

cant_proces = pList1.Count

End Sub

La funcion Filler es la encargada de manejar el flujo de datos capturados por el microfono y pasarla al player o visualizadores de onda:

Private Sub Filler(ByVal data As IntPtr, ByVal size As Integer)

If _isPlayer = True Then

If _playerBuffer Is Nothing OrElse _playerBuffer.Length < size Then

_playerBuffer = New Byte(size - 1) {}

End If

If _stream.Length >= size Then

_stream.Read(_playerBuffer, 0, size)

Else

For i As Integer = 0 To _playerBuffer.Length - 1

_playerBuffer(i) = 0

Next

End If

System.Runtime.InteropServices.Marshal.Copy(_playerBuffer, 0, data, size)

End If

End Sub

Posteriormente pasamos a elaborar el procedimiento DataArrived que es el que se encarga de procesar los datos que van de llegando o saliento despues de haber evaluado la señal de la onda:

Private Sub DataArrived(ByVal data As IntPtr, ByVal size As Integer)

indicador = 0

Me.Button_sdetec.Text = "Sonido No Detectado"

Me.Button_sdetec.ForeColor = Color.Black

Me.Button_sdetec.BackColor = Color.LightGray

If _recorderBuffer Is Nothing OrElse _recorderBuffer.Length < size Then

_recorderBuffer = New Byte(size - 1) {}

End If

If _recorderBuffer IsNot Nothing Then

System.Runtime.InteropServices.Marshal.Copy(data, _recorderBuffer, 0, size)

If _isPlayer = True Then

_stream.Write(_recorderBuffer, 0, _recorderBuffer.Length)

End If

_audioFrame.Process(_recorderBuffer)

_audioFrame.RenderTimeDomain(pictureBox1)

'-------------------------------------------
If (_audioFrame.IsEventActive = True) Then

contador_eventos += 1

Me.Text_num_eventos.Text = contador_eventos

indicador = 1

Me.Button_sdetec.Text = "Sonido Detectado"

Me.Button_sdetec.ForeColor = Color.White

Me.Button_sdetec.BackColor = Color.Red

End If

End If

End Sub

Esta funcion es muy importante ya que aqui se determina si hay algun sonido o no, la comparacion que establece el if _audioFrame.IsEventActive = True permite realizar las operaciones a desencadenar si se detecto algun sonido, como se puede ver alli, se incrementa la variable contador, la variable indicador se coloca en 1 y el texto y color del boton se cambian.

para ir variando la sensibilidad de nuestro detector de sonido solo basta con cambiar el valor del umbral de la amplitud, dicho proceso se lleva a cabo cuando variamos la barra de desplazamiento del trackbar:

Private Sub TrackBar_sensibilidad_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar_sensibilidad.Scroll

If (Me.TrackBar_sensibilidad.Value = 0) Then

sensibilidad = 16384

_audioFrame.AmplitudeThreshold = sensibilidad

End If

If (Me.TrackBar_sensibilidad.Value = 1) Then

sensibilidad = 15500

_audioFrame.AmplitudeThreshold = sensibilidad

End If

If (Me.TrackBar_sensibilidad.Value = 2) Then

sensibilidad = 9900

_audioFrame.AmplitudeThreshold = sensibilidad

End If
End Sub

por ultimo elaboramos el procedimiento cerrar_ventana que permitira cerrar el formulario de manera segura, ya que el proceimiento stop_sonido solo detiene la captura de audio y sin embargo existe una saturacion de flujo de datos ya que el microfono permanecio todo el tiempo en escucha y eso genera cierto bloqueo al programa, por tal motivo se crea una funcion aparte para cerrar la ventana, tal y como se ve a continuacion:

Sub cerrar_ventana()

Dim j, posi, encontro As Integer

Dim nomp As String

Dim vect() As String

encontro = 0

For j = 0 To cant_proces - 1

Try

nomp = pList1(j).ProcessName.ToString

vect = Split(nomp, ".")

If (vect(0) = "Deteccion de Sonido") Then

posi = j

encontro = 1

End If

Catch ex As Exception

End Try

Next

hebra.Abort()

If (encontro = 1) Then

pList1(posi).Kill()

End If

End Sub

Luego, en el boton salir colocamos lo siguiente para el correcto cierre de la aplicacion:

Private Sub Button_salir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_salir.Click

'crear objeto y asignarlo al sub que queremos ejecutar

hebra = New Thread(AddressOf Stop_sonido)

'ponemos al hilo en marcha

hebra.Start()

cerrar_ventana()

End Sub

Asi como en el evento formclosing de la aplicacion:

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

'crear objeto y asignarlo al sub que queremos ejecutar

hebra = New Thread(AddressOf Stop_sonido)

'ponemos al hilo en marcha

hebra.Start()

cerrar_ventana()

End Sub

Bien por ultimo solo resta hacerle una prueba a la aplicacion, se ejecuta y empezamos a hacer ruidos, nos podemos dar cuenta como se observa la señal que esta entrando por el microfono y si ocurre algun evento, inmediantamente el contador comienza a avanzar y el botn que indica el sonido se coloca de color rojo tal y como se ve en la siguiente imagen:

Bueno eso es todo amigos, espero y este tutorial les resulte de utilidad, si desean descargar la aplicacion pueden hacer click sobre el siguiente link: Descargar Aplicacion

Anuncios

21 respuestas a “Deteccion de Sonido Con Vb.Net

  1. hola tengo una pregunta se puede identificar las palabras pronunciadas osea aparte de reconocimiento de sonido se puede poner como reconocimiento de voz?

  2. Muchas gracias, muy bueno y bien explicado. Una consulta, si quisiera ver el valor del volumen de la señal del micrófono en lugar de verla en el visor de espectro. ¿Cómo seria?

  3. Muy bueno el tutorial, yo tengo un poco de conocimiento de visual basic 6.0 y estoy intentando mostrar la intensidad señal del microfono en un textbox pero no lo consigo. ¿me podrías dar una ayuda?. gracias

    • Hola, las variables: _waveLeft(h) y _waveRight(h)
      son las que obtienen el valor de la señal del microfono y la variable IsEventActive es la que determina si hay o no sonido de acuerdo al umbral establecido.

  4. Hola!!.
    Sabes la aplicacion me a servido mucho en realida un amigo lo pporbo y le funciona en su computador pero sabes que yo lo uso en mi computador y no me funciona me tira el siguiente error.

    Detalles de entrada de audio

    13-12-2012 17:13:38 : Ha Ocurrido una excepcion con el Audio
    System.NullReferenceException: Referencia a objeto no establecida como instancia de un objeto.
    en Sensor_de_Movimiento_Webcam.detector_de_sonido.WaveNative.waveInOpen(IntPtr& phwi, Int32 uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, Int32 dwInstance, Int32 dwFlags)
    en Sensor_de_Movimiento_Webcam.detector_de_sonido.WaveInRecorder..ctor(Int32 device, WaveFormat format, Int32 bufferSize, Int32 bufferCount, BufferDoneEventHandler doneProc) en C:\Users\Adrian\Desktop\Proyecto 09122012 (FINAL)\Sensor de Movimiento Webcam\WaveIn.vb:línea 127
    en Sensor_de_Movimiento_Webcam.deteccion_sonido.Start() en C:\Users\Adrian\Desktop\Proyecto 09122012 (FINAL)\Sensor de Movimiento Webcam\DeteccionSonido.vb:línea 87

    y es cuando lo ejecuto quiero decir que ya estando visible el form del detector de sonido en ese cuadrado de detalles de entrada de audio sale ese problema te doy las gracias por anticipado si sabes alguna solucion =)

  5. A mi me manda también el mismo error
    Ha Ocurrido una excepcion con el Audio
    System.NullReferenceException: Referencia a objeto no establecida como instancia de un objeto.
    en Deteccion_de_Sonido.detector_de_sonido.WaveNative.waveInOpen(IntPtr& phwi, Int32 uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, Int32 dwInstance, Int32 dwFlags)
    en Deteccion_de_Sonido.detector_de_sonido.WaveInRecorder..ctor(Int32 device, WaveFormat format, Int32 bufferSize, Int32 bufferCount, BufferDoneEventHandler doneProc) en C:\Users\GCH\Desktop\Deteccion de Sonido\Deteccion de Sonido\Deteccion de Sonido\WaveIn.vb:línea 127
    en Deteccion_de_Sonido.Form1.Start() en C:\Users\GCH\Desktop\Deteccion de Sonido\Deteccion de Sonido\Deteccion de Sonido\Form1.vb:línea 78

  6. amigo me puedes decir como funciona el programa
    por que al ejecutarlo me sale este Error

    30/10/2014 09:52:29 a.m. : Ha Ocurrido una excepcion con el Audio
    System.NullReferenceException: Referencia a objeto no establecida como instancia de un objeto.

    en Deteccion_de_Sonido.detector_de_sonido.WaveNative.waveInOpen(IntPtr& phwi, Int32 uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, Int32 dwInstance, Int32 dwFlags)

    en Deteccion_de_Sonido.detector_de_sonido.WaveInRecorder..ctor(Int32 device, WaveFormat format, Int32 bufferSize, Int32 bufferCount, BufferDoneEventHandler doneProc) en C:\Users\DANIELL\Downloads\Deteccion de Sonido\Deteccion de Sonido\WaveIn.vb:línea 127

    en Deteccion_de_Sonido.Form1.Start() en C:\Users\DANIELL\Downloads\Deteccion de Sonido\Deteccion de Sonido\Form1.vb:línea 78

  7. Hola, te felicito por la app, pero me pasa el mismo error que los chicos anteriores de verdad nos ayudarías mucho si respondieras el mensaje para saber como podemos solucionar estos errores

    Gracias

    • Hola, he estado testeando el programa en mi equipo y este funciona correctamente, tal vez el problema radique en que mi equipo es de 32 bits y algunas funciones no se ejecuten bien en sistemas de 64 bits, verifica el tipo de sistema que posees y también la versión del mismo ya que con sistemas operativos inferiores a Windows 7 el programa puede no funcionar correctamente. Cabe aclarar que hay algunas tarjetas de micrófono que no pueden ser reconocidas por dicho programa, es mejor realizar la prueba en un computador portátil que trae el micrófono integrado que en un computador de mesa al cual hay que conectarle uno. Espero y puedas probar el programa en otro computador que tenga los requerimientos que te he indicado para que este pueda funcionar correctamente. Gracias por leer mi blog. Si tienes otra duda no dudes en hacérmela llegar, con gusto te responderé!

      • Hola! Excelente trabajo, solo tengo el problema con la excepción que muestran arriba “System.NullReferenceException: Referencia a objeto no establecida como instancia de un objeto.” Igual en WaveInRecorder. Lo extraño y por lo que comento es que lo estamos intentando implementar en OpenSIm, para que corra junto con el simulador y ahí marca el error, PERO cuando ejecutamos el programa aparte, fuera de OpenSim funciona perfectamente. No sé si tengas alguna idea, no estoy tan metido en c# pero pienso que puede ser algo relacionado con los demás procesos que tiene OpenSim o algo así.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s