Sonidos en Visual Basic

Sonidos repetitivos usando el API, o cómo hacer que una canción siempre esté sonando.
Tanto en formato WAV cómo MID

 

Fecha: 10/Abr/98


Aunque ya he puesto un tip en la sección del API, aunque sólo para WAVs, te muestro aquí cómo hacer que también ser repita un fichero de sonido del tipo MIDI, de camino, en el ejemplo también se incluye ese ejemplo, para que puedas probarlo, ya que entre otras cosas, lo que si se puede hacer es tocar un fichero WAV y un MIDI al mismo tiempo... lo mismo ocurriría con una pista de un CD de audio... Aunque este tema es más laborioso por aquello de que hay que controlar la pista que se quiere tocar y esas cosas... así que en este ejemplo sólo se contemplan los WAVs y MIDIs.

 

El ejemplo:

Este ejemplo permite seleccionar dos ficheros de sonido, relamente no permite seleccionar, sino que debes especificar los que quieres usar.

Tiene dos botones para poder tocar cada uno de ellos, siempre que sean de diferentes tipos, ya que no se permite tocar dos WAVs al mismo tiempo...

Sólo habrá un botón de detener, para parar cualquier fichero que se esté tocando y para que se puedan especificar los nombres de esos ficheros a usar, se usan dos TEXTBOXES.

Veamos una "instantánea" del form en tiempo de diseño:

el ejemplo para tocar de forma repetitiva

 

Para los ficheros de tipo WAVs, no hay conplicación, ya que usando sndPlaySound con los parámetros: SND_ASYNC + SND_LOOP, se consigue lo deseado.

Sin embargo para los MIDIs, hay que saber cuando termina para volver a tocarlo de nuevo, esto se soluciona añadiendo un control timer al form y comprobar si se ha terminado de tocar el fichero, en caso de que sea así, empezar de nuevo... y así hasta que lo detengamos.

Este sería el código del Timer1_Timer:

Private Sub Timer1_Timer()
    Dim mciStatusParms As MCI_STATUS_PARMS
    
    'Sólo para el MIDI:
    If IdMIDI Then
        'Obtenemos el estado del dispositivo
        mciStatusParms.dwItem = MCI_STATUS_MODE
        Call mciSendCommand(IdMIDI, MCI_STATUS, MCI_STATUS_ITEM, _
                            mciStatusParms)
        
        'Si no se está reproduciendo
        If mciStatusParms.dwReturn = MCI_MODE_STOP Then
            'Empezar de nuevo
            'Posicionar el puntero al principio
            Call mciSendCommand(IdMIDI, MCI_SEEK, _
                                MCI_SEEK_TO_START, 0)
            'Empezar de nuevo
            Call mciSendCommand(IdMIDI, MCI_PLAY, 0, 0)
        End If
    End If

End Sub

Es decir, se comprueba el estado del dispositivo, si el modo que devuelve es que está parado, se posiciona el "puntero" de la canción al principio y se le indica que vuelva a empezar a tocarlo.

Cuando nos hartemos de que toque... lo paramos y ya está. Esto mismo hay que hacerlo al cerrar el FORM...
Veamos el código para detener el MIDI:

    'Detener el MIDI
    Call mciSendCommand(IdMIDI, MCI_STOP, 0, 0)
    Call mciSendCommand(IdMIDI, MCI_CLOSE, 0, 0)
    IdMIDI = 0
    
    Timer1.Enabled = False

Para detenerlo, le mandamos un comando STOP y de camino cerramos el dispositivo.
Esto lo podemos tener en un procedimiento, para que lo podamos usar de forma genérica, lo mismo desde un botón que detenga la música como desde el evento UNLOAD del form.
Lo único que necesitaríamos es usar un SUB que haga lo mismo, es decir: PARE y CIERRE.

Veamos ahora el código para que la canción empiece a tocar:

'
Private Sub TocarMIDI(ByVal sMID As String)
    'Tocar un Mid usando mciSendCommand
    '
    Dim mciOpenParms As MCI_OPEN_PARMS
    
    If IdMIDI <> 0 Then
        Call mciSendCommand(IdMIDI, MCI_CLOSE, 0, 0)
        IdMIDI = 0
    End If
    
    With mciOpenParms
        .lpstrElementName = sMID
    End With
    
    Call mciSendCommand(0, MCI_OPEN, _
        MCI_OPEN_ELEMENT, _
        mciOpenParms)
        
    IdMIDI = mciOpenParms.wDeviceID
    Call mciSendCommand(IdMIDI, MCI_PLAY, 0, 0)
    Timer1.Enabled = True
End Sub

Aquí se comprueba si ya se está usando otro MIDI, en caso de que sea así, se detiene la anterior y se empieza con la nueva.

Ahora bien... ¿cómo sabemos si es un fichero MID o uno WAV?

Pues con una simple comparación... si la extensión es MID, se tocará como MIDI, si es WAV, como WAV...

Vamos a ver el código completo del botón tocar:

Private Sub cmdTocar_Click(Index As Integer)
    Dim Archivo As String
    
    On Local Error Resume Next
    
    Archivo = Text1(Index)
    
    'Para tocar un fichero se la llamas así:
    If InStr(Archivo, ".wav") Then
        Call sndPlaySound(Archivo, SND_ASYNC + SND_LOOP)
    ElseIf InStr(Archivo, ".mid") Then
        TocarMIDI Archivo
    End If
    
    Err = 0
End Sub

Aquí lo único que se hace es saber que fichero queremos tocar, comprobar si la extensión es WAV, en cuyo caso se llama a la función sndPlaySound con los susodichos parámetros ASYNC y LOOP.
El SND_LOOP es el que se encarga de que siempre esté haciendo "bucles", por otra parte SND_ASYNC lo que hace es que no se espere a que el fichero termine de tocar para que se pueda hacer algo después de empezar a tocarlo. Es decir: tocar de forma asíncrona, osease que no haya que esperar a que termine... ¿'ta claro?

En caso de ser un MIDI, se llama al procedimiento que hemos visto anteriormente.

Este es el código completo del botón parar:

Private Sub cmdParar_Click()
        
    'Para detener lo que se esté tocando
    Call sndPlaySound(ByVal "", 0)
    
    'Detener el MIDI
    Call mciSendCommand(IdMIDI, MCI_STOP, 0, 0)
    Call mciSendCommand(IdMIDI, MCI_CLOSE, 0, 0)
    IdMIDI = 0
    
    Timer1.Enabled = False
End Sub

Para detener un fichero WAV, se llama a la función SndPlaySound con una cadena vacía y se para la música.
Para detener un MIDI, también se podría usar la función: mciSendString con el comando "close all" y se pararía el MIDI que estuviese sonando:

Call mciSendString("close all", 0, 0, 0)

En los listados de ejemplo están todas las declaraciones del API, así cómo las constantes usadas.

Espero que te de pie a investigar un poco más sobre el tema, si es que te interesa... y si "encuentras" los comandos para que se haga de forma "simple" esto de que se toque de forma repetida un MIDI, pues me lo dices, para que el personal se entere de cómo hacerlo... porque haber debe haberlo... pero ¿dónde?

Nos vemos.
Guillermo


Pulsa en este link, si quieres bajarte el listado de ejemplo, se incluyen dos ficheros de prueba (sndAPI_rep.zip 67.8 KB)

la Luna del Guille o... el Guille que está en la Luna... tanto monta...