Você está na página 1de 12

Grabadora wav

Descripción del ejemplo

Durante un tiempo estuve utilizando la Grabadora de Windows para capturar audio de la


tarjeta de sonido de mi computadora, pero realmente esa aplicación no me satisfacía así
que me embarque en el proyecto de construir mi propia grabadora. Pensé que era fácil
pero no lo era tanto como pensé.

Lo primero que debes hacer para poder capturar audio en tu computadora es configurar
el audio digital para grabar. ¿Y como haces eso?

1 - Revisa en tu barra de herramientas si tienes el icono de control de volumen, sino lo


tienes ahí puedes activarlo desde el panel de control – Sonido y Multimedia. Si lo tienes
ya dale doble clic. Te aparecerá el control de volumen.

2 - Haz clic en el menú Opciones, luego en Propiedades selecciona Grabación.


3 - En la parte inferior de la pantalla selecciona Stereo Mix (como se ve en la figura) y
ahora podrás grabar cualquier sonido que este reproduciendo tu PC. Si no lo haces solo
escucharas estática. Ahora desliza el control de volumen del Stereo Mix a la mitad, te
preguntaras por que? Simple, porque si lo dejas a todo volumen la grabación será
distorsionada.

Hasta aquí todo bien.

Abre tu Visual Basic 6.0, selecciona un Exe Estándar y agrégale un modulo.

Coloca como referencia del proyecto la librería Microsoft Scripting Runtime y agrega el
componente Microsoft Common Dialog Control 6.0. La primera la necesitamos para
poder manejar los archivos del sistema y la segunda para que el usuario pueda guardar
el archivo Wav donde el desee.

En el modulo vamos a declarar 2 funciones del API de Windows:

Texto planoImprimir
1. Declare Function mciSendString _
2. Lib "winmm.dll" _
3. Alias "mciSendStringA" ( _
4. ByVal lpstrCommand As String, _
5. ByVal lpstrReturnString As String, _
6. ByVal uReturnLength As Long, _
7. ByVal hwndCallback As Long) As Long
8.
9. Declare Function mciGetErrorString _
10. Lib "winmm.dll" _
11. Alias "mciGetErrorStringA" ( _
12. ByVal dwError As Long, _
13. ByVal lpstrBuffer As String, _
14. ByVal uLength As Long) As Long

La primera te permite tomar el control de cualquier dispositivo multimedia instalado en


tu PC con simples instrucciones en ingles; la segunda te permite detector si a ocurrido
un error con cualquiera de las instrucciones que has enviado.

Ahora en el formulario vas a colocar 6 botones: CmdPrev, CmdNext, CmdPlay,


CmdStop, CmdRec y CmdGuardar. Un control Timer, un control CommonDialog y dos
etiquetas. Algo así:

Si quieres ponerle imágenes puede quedar así:

Coloca la propiedad Enable de los botones como falsa, menos la de CmdRec .

Ya que tienes el formulario listo voy a contarte de 2 problemas que se me presentaron al


realizar esta aplicación. El primero fue que la función mciSendString tiene la limitante
que no acepta path largos para salvar el archivo en memoria, así que si lo quieres
guardar en mis documentos directamente no puedes; la solución que encontré sin
enrollarme mucho fue dar un rodeo y almacenar temporalmente el archivo en la unidad
c y luego moverlo a donde yo quería. Resuelto ese problema me encontré con otro mas
difícil y que me puso a pensar: el archivo guardado no se podía reproducir en ningún
reproductor solo en la grabadora de Windows, su tamaño era demasiado grande y si lo
escuchabas era como una música macabra sin relación a lo que habías grabado. No te
preocupes que eso también tiene solución.

Primero vamos a declarar unas variables:

Texto planoImprimir
1. Dim s, m As String
2. Dim x, minutos As Integer

Estas variables están asociadas al control Timer y nos van a permitir mostrar al usuario
cuando se esta grabando o reproduciendo un archivo Wav.

Texto planoImprimir
1. Dim Result As Long
2. Dim errormsg As Integer
3. Dim cadena As String * 1024
4. Dim CadenaError As String * 1024
5. Dim mssg As String * 255
6. Dim i As Long
7. Dim BlockAlign As Integer
8. Dim sBytes As String

Estas son nuestras variables de trabajo, donde se almacenaran los valores devueltos por
las funciones API mciSendString y mciGetErrorString.

Y tenemos esta variable muy importante:

Texto planoImprimir
1. Dim lBytes As Long

Cuando se almacena un archivo wav con mciSendString, la función realmente no lo


guarda con calidad CD esto es: 44100 Hz, l6 bits y 2 canales de audio sino que lo
guarda a 11025, por esta razón no lo puedes escuchar en cualquier otro reproductor.
La solución a este problema se la debo al señor S. Clarke que se topo con el mismo
problema que yo y publico sus descubrimientos en : www.rediware.com

Así que esta variable la utilizaremos para calcular el lugar exacto donde se produce el
error de almacenamiento del archivo wav.
Texto planoImprimir
1. Dim s, m As String
2. Dim x, minutos As Integer

Estas variables las utilizaremos con un control Timer para llevar el tiempo de grabación
y reproducción.

Como te habrás dado cuenta en la ilustración del formulario todos los botones están
desactivados menos el de grabar. Vamos a programar el evento clic de este botón:

Texto planoImprimir
1. Private Sub CmdRec_Click()
2.
3. ' cierro todos los dispositivos que pueden estar abiertos
4. mciSendString "close all", 0, 0, 0
5.
6. Result = mciSendString("open new Type waveaudio Alias sonido", cadena, Le
n(cadena), 0)
7.
8. ' Muestro un mensaje si se produce algun error
9. If Not Result = 0 Then
10. errormsg = mciGetErrorString(Result, CadenaError, 1024)
11. MsgBox CadenaError, 0, "Error"
12. End If
13.
14. ' Determinamos el formato de tiempo en millisegundos
15. Result = mciSendString("set sonido time format ms", cadena, 1024, 0)
16.
17. ' Determínanos el formato pcm del archivo wav (Microsoft standard)
18. Result = mciSendString("set sonido format tag pcm", cadena, 1024, 0)
19.
20. ' Determinamos las propiedades de grabación con calidad CD
21. Result = mciSendString("set sonido channels 2", cadena, 1024, 0) ' dos canales
de audio
22. Result = mciSendString("set sonido samplespersec 44100", cadena, 1024, 0) ' T
aza de muestreo
23. Result = mciSendString("set sonido bitspersample 16", cadena, 1024, 0) ' Bits
por muestra
24.
25. ' Determinamos el tipo de alineamientos de los byte del archivo
26. BlockAlign = CInt((CLng(16) / 8) * CLng(2))
27. Result = mciSendString("set sonido alignment " & Str$(BlockAlign), cadena, 1
024, 0)
28.
29. ' Calculamos donde se da el error interno dentro del archivo a grabar
30. lBytes = CLng(2) * ((CLng(2) * CLng(16)) / 8)
31. sBytes = Str$(lBytes)
32.
33. CmdStop.Enabled = True
34. CmdRec.Enabled = False
35.
36. ' Empezamos a grabar
37. Result = mciSendString("record sonido", cadena, Len(cadena), 0)
38.
39. End Sub

Recuerda que ambas funciones API siempre retornan un valor y La calidad de sonido
CD comprende 2 canales de audio, una frecuencia de muestreo de 44100 Hz y se
almacena a una tasa de 16 bits.

Ya tenemos nuestro sonido en memoria, entonces podemos reproducirlo.

Texto planoImprimir
1. Private Sub CmdPlay_Click()
2.
3. CmdStop.Enabled = True
4. CmdNext.Enabled = True
5. cmdPrev.Enabled = True
6. CmdRec.Enabled = False
7. CmdGuardar.Enabled = False
8. CmdPlay.Enabled = False
9.
10. Result = mciSendString("play sonido from 0", cadena, Len(cadena), 0)
11.
12. End Sub

Esta simple instrucción reproduce el archivo en memoria desde su primera posición

Texto planoImprimir
1. Result = mciSendString("play sonido from 0", cadena, Len(cadena), 0)

Ahora se quieres rebobinarlos para revisar tu sonido, puedes programar el botón Previo

Texto planoImprimir
1. Private Sub cmdPrev_Click()
2. If CmdPlay.Enabled = False Then
3. Timer1.Enabled = False
4. x=0
5. minutos = 0
6. Result = mciSendString("stop sonido", cadena, Len(cadena), 0)
7. Timer1.Enabled = True
8. Result = mciSendString("play sonido from 0", cadena, Len(cadena), 0)
9. Else
10. CmdGuardar.Enabled = True
11. CmdRec.Enabled = True
12. CmdStop.Enabled = False
13. CmdNext.Enabled = True
14. cmdPrev.Enabled = False
15. CmdPlay.Enabled = False
16. End If
17.
18. End Sub

Fíjate apagamos el Timer un momento, reinicializamos las variables de tiempo y


detenemos el sonido que esta en memoria para poder otra vez encender el proceso de
reproducción.

El botón Next lo que hace es detener la reproducción.

Result = mciSendString("stop sonido", cadena, Len(cadena), 0)

Esta sentencia detiene la reproducción y la grabación del sonido.

Ahora hablemos del control Timer, este tiene un intervalo de 1000 el equivalente a un
segundo, cada segundo el control revisa que esta pasando con la aplicación basándose
en el comportamiento de los botones. Como se puede ver en el código siguiente:

Texto planoImprimir
1. Private Sub Timer1_Timer()
2. If CmdRec.Enabled = False And CmdStop.Enabled = True And CmdNext.En
abled = False Then
3. Label1.Caption = "Grabando....."
4. CalcularTiempo
5. Label2.Caption = m + ":" + s
6. End If
7.
8. If CmdRec.Enabled = False And CmdStop.Enabled = True And CmdNext.En
abled = True Then
9. Label1.Caption = "Reproduciendo....."
10. CalcularTiempo
11. Label2.Caption = m + ":" + s
12. End If
13.
14. If CmdStop.Enabled = False Then
15. Label1.Caption = "Detenido....."
16. Label2.Caption = "00:00"
17. x=0
18. minutos = 0
19. End If
20.
21. End Sub

El procedimiento CalcularTiempo nos permite determinar el tiempo de reproducción o


grabación como cualquier reproductor comercial

Texto planoImprimir
1. Private Sub CalcularTiempo()
2. x = x + 1
3. If x = 60 Then
4. minutos = minutos + 1
5. x=0
6. End If
7. m = Trim(Str(minutos))
8. s = Trim(Str(x))
9.
10. If minutos < 10 Then m = "0" + m
11. If x < 10 Then s = "0" + s
12.
13. Label2.Caption = m + ":" + s
14.
15. End Sub

Ahora vamos a guardar en disco nuestro sonido, suena fácil pero vamos a tener que dar
unas vueltas primero.

Texto planoImprimir
1. Private Sub CmdGuardar_Click()
2. ' Grabar el archivo wav que esta en la memoria en una carpeta temporal
3. Result = mciSendString("save sonido C:\NewWav.wav", cadena, Len(cadena),
0)
4.
5. ' Aqui llamamos a un procedimiento para leer los valores del wav en memoria
6. GetRecStatus
7.
8. ' cierra el archivo en memoria
9. Result = mciSendString("close sonido", cadena, 1024, 0)
10. If Not Result = 0 Then
11. errormsg = mciGetErrorString(Result, CadenaError, 1024)
12. MsgBox CadenaError, 0, "Error (close)"
13. End If
14.
15. ' cierra todos los archivos en memoria
16. mciSendString "close all", 0, 0, 0
17.
18. ' Aqui accedemos al archivo temporal para modificarlo binariamente
19. FixWaveFile
20.
21. ' guardamos en disco
22. GrabarArchivo
23. End Sub

Creo que ya te conté que mciSendString no soporta path largos, así que vamos a guardar
nuestro sonido en un archivo temporal en el directorio raíz de C y llamamos al
procedimiento GetRecStatus que va a leer toda la información sobre el sonido grabado
que esta en memoria, esa información nos será útil ya que esa información no se grabo
en el archivo Wav.

Texto planoImprimir
1. Private Sub GetRecStatus()
2.
3. Dim i As Long
4. Dim MSchan As String
5. Dim MSbits As String
6. Dim MSsamples As String
7. Dim MSbytes As String
8. Dim lChan As Long
9. Dim lBits As Long
10. Dim lSamples As Long
11. Dim sChan As String
12. Dim mssg As String * 255
13.
14. ' Canales de audio
15. i = mciSendString("status sonido channels", mssg, 255, 0)
16. If Str(mssg) = "1" Then
17. MSchan = "mono"
18. sChan = "1"
19. Else
20. MSchan = "stereo"
21. sChan = "2"
22. End If
23.
24. ' bits por muestra
25. i = mciSendString("status sonido bitspersample", mssg, 255, 0)
26. MSbits = Str(mssg)
27.
28. 'muestra
29. i = mciSendString("status sonido samplespersec", mssg, 255, 0)
30. MSsamples = Str(mssg)
31.
32. ' Aqui se presenta unos de los errores la frecuencia que devuelve es 11025 Hz
33. ' cuando en realidad es 44100 Hz
34. i = mciSendString("status sonido bytespersec", mssg, 255, 0)
35. MSbytes = Str(mssg)
36.
37. ' Calculamos el valor real de los byte por segundos
38. lBytes = CLng(MSsamples) * ((CLng(sChan) * CLng(MSbits)) / 8)
39.
40. End Sub

Cerramos el archivo en memoria para poder acceder a la copia en disco y llamamos al


procedimiento FixWaveFile, que tendrá acceso binario al archivo para corregir el error.

Texto planoImprimir
1. Private Sub FixWaveFile()
2.
3. ' Este es el procedimiento para arreglar el error del archivo wav
4. Dim Indexnum As Integer
5. Dim x As Integer
6. Dim HexCode As String
7. Dim Hex1 As String
8. Dim Hex2 As String
9. Dim Hex3 As String
10. Dim lByteNum As Long ' numero del byte (29,30, & 31) en el archivo wave
11. Dim bByte As Byte ' byte hexadecimal a escribir
12.
13. ' obtiene el hexadecimal para la variable lByte
14. HexCode = Hex(lBytes) ' lBytes que calculamos en el procedimiento de graba
r
15. Do While Len(HexCode) < 6 ' Revisar si tiene los 6 caracteres necesarios
16. HexCode = "0" & HexCode ' Si no agregar ceros
17. Loop
18.
19. ' Nota: este valor debe ser escrito en el archivo al revés!
20. Hex1 = Right$(HexCode, 2) ' obtienes el ultimo byte hexadecimal
21. Hex2 = Mid$(HexCode, 3, 2) ' obtienes el byte de en medio
22. Hex3 = Left$(HexCode, 2) ' obtienes el primer byte
23.
24. 'Abres el archivo
25. Indexnum = FreeFile
26. Open "C:\NewWav.wav" For Binary Access Write As #Indexnum ' Abres com
o binario
27. lByteNum = 29 ' primer byte a escribir es el 29
28. bByte = CInt("&H" & Hex1)
29. Put #Indexnum, lByteNum, bByte 'escribe el valor bByte a la posición de lByt
eNum en el archivo
30. bByte = CInt("&H" & Hex2)
31. lByteNum = lByteNum + 1
32. Put #Indexnum, lByteNum, bByte
33. bByte = CInt("&H" & Hex3)
34. lByteNum = lByteNum + 1
35. Put #Indexnum, lByteNum, bByte
36. Close #1
37. End Sub

Estos dos procedimientos se los debo a S. Clark que se topo con el mismo problema que
yo y estoy realmente agradecida. Bueno, ahora que ya tenemos todo arreglado vamos
aguardar el sonido donde realmente queremos.

Texto planoImprimir
1. Public Sub GrabarArchivo()
2. Dim Nfile As String
3. Dim ruta As String
4. Dim osf As Object
5. Set osf = CreateObject("Scripting.FileSystemObject")
6. Dim origen As File
7. Set origen = osf.GetFile("C:\NewWav.wav")
8.
9. With MDialogo
10. .CancelError = False
11. .Filter = "WAV file (*.wav*)|*.wav"
12. .Flags = &H2 Or &H400
13. .InitDir = GetSetting(App.EXEName, App.EXEName, "Default Path")
14. .FileName = GetSetting(App.EXEName, App.EXEName, "Default Filename
")
15. .ShowSave
16.
17. ' obtenemos el nombre que el usuario le ha puesto
18. Nfile = .FileTitle
19.
20. ' obtenemos la ruta completa donde lo guardaremos
21. ruta = .FileName
22. wavruta = ruta
23. End With
24.
25. ' cambiamos el nombre del archivo
26. origen.Name = Nfile
27.
28. 'lo movemos a la ruta elegida por el usuario
29. origen.Move (ruta)
30. MsgBox "Archivo Salvado", vbInformation, "Salvar"
31.
32. End Sub
Primero creamos un objeto archivo de sistema para manejar nuestro archivo wav,
definimos una variable como tipo File y le asignamos el archivo en disco, abrimos un
cuadro de dialogo salvar para que el usuario coloque el nombre que le quiere poner al
archivo y en que carpeta lo quiere guardar. La variable Nfile almacena el nuevo nombre
del archivo y la variable ruta el path donde se guardara. Renombramos el archivo wav y
lo movemos a la ruta seleccionada.

Y aquí tienes un grabador de sonidos básico, puedes probar el ejemplo, ampliarlo o


utilizar el código en tus propios programas, pero recuerda de donde lo sacaste y no
quites merito a su autor. Espero haberte ayudado. Cualquier cosa puedes escribirme al
correo acvg_correo@yahoo.com

Você também pode gostar