Eseguire un file audio mediante le funzioni esterne del API di SDL2

Da Gambas-it.org - Wikipedia.

La libreria SDL2 è un API multi-piattaforma contenente funzioni per la gestione multimediale dell'audio e del video.

Per poter utilizzare le funzioni esterne di SDL2 in Gambas, si richiameranno anche separatamente per lo più le seguenti librerie (con le attuali versioni):

  • libSDL2-2.0.so.0.3000.7
  • libSDL2_mixer-2.0.so.0.800.0

Eseguire un solo file audio

E' possibile eseguire vari formati audio [nota 1], utilizzando la funzione "Mix_PlayMusic()" appartenente alla libreria libSDL2_mixer-2.0.so.0.800.0.
Detta funzione non consente di poter eseguire più file contemporaneamente.

Library "libSDL2-2.0:0.3000.7"

Private Const SDL_INIT_AUDIO As Integer = 16
Private Const MIX_DEFAULT_FORMAT As Integer = 32784

' int SDL_Init(Uint32 flags)
' Initialize the SDL library.
Private Extern SDL_Init(flags As Integer) As Integer

' const char* SDL_GetError(void)
' Retrieve a message about the last error that occurred.
Private Extern SDL_GetError() As String

' void SDL_Quit(void)
' Clean up all initialized subsystems.
Private Extern SDL_Quit()


Library "libSDL2_mixer-2.0:0.800.0"

Private Const MIX_DEFAULT_FREQUENCY As Integer = 22050

' int Mix_OpenAudio(int frequency, Uint16 format, int channels, int chunksize)
' Initialize the mixer API.
Private Extern Mix_OpenAudio(frequency As Integer, format16 As Integer, channels As Integer, chunksize As Integer) As Integer

' int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
' Get the actual audio format in use by the opened audio device.
Private Extern Mix_QuerySpec(frequency As Pointer, format16 As Pointer, channels As Pointer) As Integer

' Mix_Music * Mix_LoadMUS(const char *file)
' Load a wave file or a music.
Private Extern Mix_LoadMUS(file As String) As Pointer

' Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
' Find out the music format of a mixer music.
Private Extern Mix_GetMusicType(music As Pointer) As Integer

' int Mix_PlayMusic(Mix_Music *music, int loops)
' Play an audio chunk on a specific channel.
Private Extern Mix_PlayMusic(music As Pointer, loops As Integer) As Integer

' int Mix_PlayingMusic()
' Check the status of a specific channel.
Private Extern Mix_PlayingMusic() As Integer

' void Mix_FreeMusic(Mix_Music *music)
' Free an audio chunk previously loaded.
Private Extern Mix_FreeMusic(music As Pointer)

' void Mix_CloseAudio(void)
' Close the mixer, halting all playing audio.
Private Extern Mix_CloseAudio()


Public Sub Main()

 Dim err As Integer
 Dim canali As String
 Dim music As Pointer
' Vengono impostati i valori predefiniti iniziali della frequenza, del formato e del numero dei canali del file WAV caricato.
' Volendo adattare tali valori alle reali caratteristiche del file audio caricato, bisognerà variare i valori iniziali delle rispettive variabili:
 Dim audio_rate As Integer = MIX_DEFAULT_FREQUENCY
 Dim audio_format As Integer = MIX_DEFAULT_FORMAT
 Dim audio_channels As Integer = 2
 Dim form_audio as string[]
 Dim tempus As Date
 
 form_audio = ["None", "CMD", "WAV", "MOD", "MID", "OGG", "MP3",  "MP3_MAD_UNUSED", "FLAC", "MODPLUG_UNUSED"]

' Inizializza la libreria SDL2:
 err = SDL_Init(SDL_INIT_AUDIO)
 If err < 0 Then Error.Raise("Impossibile inizializzare la libreria SDL2: " & SDL_GetError())
   
' Apre il dispositivo audio:
 If Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0 Then
   Error.Raise("Impossibile aprire il dispositivo audio: " & SDL_GetError())
 Else
   Mix_QuerySpec(VarPtr(audio_rate), VarPtr(audio_format), VarPtr(audio_channels))
 Endif
 If audio_channels > 2 Then
   canali = "surround"
 Else
   If audio_channels > 1 Then
     canali = "stereo"
   Else
     canali = "mono"
   Endif
 Endif
 Print "Audio aperto a "; audio_rate; " Hz, "; audio_format And 255; " bit, "; canali
  
' Carica il file audio:
 music = Mix_LoadMUS("/percorso/del/file/audio")
 If music == 0 Then Error.Raise("Impossibile caricare il file audio: " & SDL_GetError())
  
' Esegue il file audio. Se il secondo argomento è posto a 0 il file sarà eseguito soltanto una volta.
' Se è posto a -1 il file sarà esguito all'infinito:
 err = Mix_PlayMusic(music, 0)
 If err < 0 Then Error.Raise("Impossibile eseguire il file audio: " & SDL_GetError())
  
 Print "Tipo di file: "; form_audio[Mix_GetMusicType(music)]
  
 tempus = Now
  
 While Mix_PlayingMusic() <> 0
' Mostra il tempo trascorso dall'inizio dell'esecuzione del file audio:"
   Write "\r" & CStr(Time(0, 0, 0, DateDiff(tempus, Now, gb.Millisecond)))
   Wait 0.001
 Wend

' Va in chiusura:
 Mix_FreeMusic(music)
 Mix_CloseAudio()
 SDL_Quit()

End


Eseguire due o più file audio

E' possibile riprodurre più suoni contemporaneamente utilizzando le funzioni della sub-libreria mixer audio multi-canale libSDL2_mixer.

Di seguito mostreremo un codice esemplificativo, nel quale verranno eseguiti due file audio:

Library "libSDL2-2.0:0.3000.7"

Private Const SDL_INIT_AUDIO As Integer = 16
Private Const MIX_DEFAULT_FORMAT As Integer = 32784

' int SDL_Init(Uint32 flags)
' Initialize the SDL library.
Private Extern SDL_Init(flags As Integer) As Integer

' const char* SDL_GetError(void)
' Retrieve a message about the last error that occurred.
Private Extern SDL_GetError() As String

' void SDL_Quit(void)
' Clean up all initialized subsystems.
Private Extern SDL_Quit()


Library "libSDL2_mixer-2.0:0.800.0"

Public Struct Mix_Chunk
  allocated As Integer
  abuf As Pointer
  alen As Integer
  volume As Byte
End Struct

Private Const MIX_DEFAULT_FREQUENCY As Integer = 22050

' int Mix_OpenAudio(int frequency, Uint16 format, int channels, int chunksize)
' Initialize the mixer API.
Private Extern Mix_OpenAudio(frequency As Integer, format16 As Integer, channels As Integer, chunksize As Integer) As Integer

' int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
' Get the actual audio format in use by the opened audio device.
Private Extern Mix_QuerySpec(frequency As Pointer, format16 As Pointer, channels As Pointer) As Integer

' SDL_RWops * SDL_RWFromFile(const char *file, const char *mode)
' Create a new SDL_RWops structure for reading from and/or writing to a named file. 
Private Extern SDL_RWFromFile(filewav As String, mode As String) As Pointer

' Mix_Chunk * Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
' Load a wave file or a music.
Private Extern Mix_LoadWAV_RW(src As Pointer, freesrc As Integer) As Mix_Chunk

' int Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks)
' Play an audio chunk on a specific channel.
Private Extern Mix_PlayChannelTimed(channel As Integer, chunk As Mix_Chunk, loops As Integer, ticks As Integer) As Integer

' int Mix_Playing(int channel)
' Check the status of a specific channel.
Private Extern Mix_Playing(channel As Integer) As Integer

' void Mix_FreeChunk(Mix_Chunk *chunk)
' Free an audio chunk previously loaded.
Private Extern Mix_FreeChunk(chunk As Mix_Chunk)

' void Mix_CloseAudio(void)
' Close the mixer, halting all playing audio.
Private Extern Mix_CloseAudio()


Public Sub Main()

 Dim err, cnl As Integer
 Dim canale As New Integer[]
 Dim canali As String
 Dim percorsoFile As String[] = ["/percorso/del/primo/file/audio", "/percorso/del/secondo/file/audio"]
 Dim audio As New Mix_Chunk[]
 Dim tempus As Date
' Vengono impostati i valori predefiniti iniziali della frequenza, del formato e del numero dei canali del file audio caricato.
' Volendo adattare tali valori alle reali caratteristiche del file audio caricato, bisognerà variare i valori iniziali delle rispettive variabili:
 Dim audio_rate As Integer = MIX_DEFAULT_FREQUENCY
 Dim audio_format As Integer = MIX_DEFAULT_FORMAT
 Dim audio_channels As Integer = 2

' Inizializza la libreria SDL2:
 err = SDL_Init(SDL_INIT_AUDIO)
 If err < 0 Then Error.Raise("Impossibile inizializzare la libreria SDL2: " & SDL_GetError())
  
' Apre il dispositivo audio:
 If Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0 Then
   Error.Raise("Impossibile aprire il dispositivo audio: " & SDL_GetError())
 Else
   Mix_QuerySpec(VarPtr(audio_rate), VarPtr(audio_format), VarPtr(audio_channels))
 Endif
 If audio_channels > 2 Then
   canali = "surround"
 Else
   If audio_channels > 1 Then
     canali = "stereo"
   Else
     canali = "mono"
   Endif
 Endif
 Print "Audio aperto a "; audio_rate; " Hz, "; audio_format And 255; " bit, "; canali
  
 With audio
' Carica il primo file audio:
   .Push(Mix_LoadWAV_RW(SDL_RWFromFile(percorsoFile[0], "rb"), 1))
' Carica il secondo file audio:
   .Push(Mix_LoadWAV_RW(SDL_RWFromFile(percorsoFile[1], "rb"), 1))
 End With

' Differenzia il volume dei due file audio:
 audio[0].volume = 30
 audio[1].volume = 100
  
' Esegue contemporaneamente entrambi i file audio caricati , ed intercetta il rispettivo canale sul quale ciascuno di essi viene eseguito.
' Passando il valore -1 al primo argomento della funzione, il campione audio sarà eseguito sul primo canale audio disponibile:
 canale.Push(Mix_PlayChannelTimed(-1, audio[0], 0, 0))
 If canale[0] = -1 Then Error.Raise("Impossibile eseguire il 1° file audio: " & SDL_GetError())

 canale.Push(Mix_PlayChannelTimed(-1, audio[1], 0, 0))
 If canale[1] = -1 Then Error.Raise("Impossibile eseguire il 2° file audio: " & SDL_GetError())

' Verifica quale file audio possiede la maggiore dimensione:
 If Stat(percorsoFile[0]).Size < Stat(percorsoFile[1]).Size Then cnl = 1

 tempus = Now
  
' Attende che sia terminato il file audio di maggiore dimensione (e quindi presumibilmente quello con maggiore durata):
 While Mix_Playing(cnl) <> 0
' ' Mostra il tempo trascorso dall'inizio dell'esecuzione dei file audio:"
   Write "\r" & CStr(Time(0, 0, 0, DateDiff(tempus, Now, gb.Millisecond)))
   Wait 0.001
 Wend

' Libera la memoria precedentemente allocata per l'esecuzione dei due file audio:
 Mix_FreeChunk(audio[0])
 Mix_FreeChunk(audio[1])

' Chiude l'interfaccia audio SDL e SDL_mixer:
 Mix_CloseAudio()

 SDL_Quit()

End


Note

[1] I formati eseguibili sono i seguenti:

  • .WAV (WAV/RIFF)
  • .VOC (Creative Labs' Voice format)
  • .MP3 (MPEG-1 Layer 3 support)
  • .MID (Instrument Digital Interface)
  • .MOD (MOD file: .mod .xm .s3m .669 .it .med ed altri)
  • .OGG (Ogg file)
  • .SPX (Speex file)
  • .SHN (Shorten file)
  • .RAW (Raw sound data in any format)
  • .AU (Sun's Audio format)
  • .AIFF (Audio Interchange format)
  • .FLAC (Lossless audio compression)


Riferimenti