Eseguire un file mp3 usando le risorse del API di Mpeg3 e di Alsa

Da Gambas-it.org - Wikipedia.

E' possibile eseguire un file mp3 usando le risorse del API di Mpeg3 e di Alsa: la prima libreria provvedererà a estrarre dal file audio mp3 i dati audio grezzi, mentre la seconda libreria provvederà a eseguire tali dati audio grezzi.

E' necessario avere installate nel proprio sistema e richiamare in Gambas le librerie condivise: "libmpeg3.so.2.1.8 " e "libasound.so.2.0.0 "


Mostriamo un semplice esempio pratico:

Private Const BUFFER As Long = 256

Library "libmpeg3:2.1.8"

Public Struct mpeg3_t
  fs As Pointer
  demuxer As Pointer
  total_astreams As Integer
  atrack[65536] As Pointer
  total_vstreams As Integer
  vtrack[65536] As Pointer
  total_sstreams As Integer
  strack[65536] As Pointer
  frame_offsets As Pointer
  sample_offsets As Pointer
  keyframe_numbers As Pointer
  video_eof As Pointer
  audio_eof As Pointer
  total_frame_offsets As Pointer
  total_sample_offsets As Pointer
  total_samples As Pointer
  total_keyframe_numbers As Pointer
  channel_counts As Pointer
  indexes As Pointer
  total_indexes As Integer
  index_bytes As Long
  is_transport_stream As Integer
  is_program_stream As Integer
  is_ifo_file As Integer
  is_audio_stream As Integer
  is_video_stream As Integer
  is_bd As Integer
  packet_size As Integer
  last_type_read As Integer
  last_stream_read As Integer
  subtitle_track As Integer
  program As Integer
  cpus As Integer
  seekable As Integer
  toc_fd As Pointer
  byte_pts As Long
  have_palette As Integer
  palette[64] As Byte
  source_date As Long
End Struct

' int mpeg3_check_sig(char *path)
' Check for file compatibility.
Private Extern mpeg3_check_sig(path As String) As Integer

' mpeg3_t* mpeg3_open(char *path, int *error_return)
' Open the MPEG stream.
Private Extern mpeg3_open(path As String, error_return As Pointer) As Mpeg3_t

' int64_t mpeg3_get_bytes(mpeg3_t *file)
' Total bytes.
Private Extern mpeg3_get_bytes(mpeg3file As Mpeg3_t) As Long

' int mpeg3_audio_channels(mpeg3_t *file, int stream)
Private Extern mpeg3_audio_channels(mpeg3file As Mpeg3_t, _stream As Integer) As Integer

' int mpeg3_sample_rate(mpeg3_t *file, int stream)
Private Extern mpeg3_sample_rate(mpeg3file As Mpeg3_t, _stream As Integer) As Integer

' char* mpeg3_audio_format(mpeg3_t *file, int stream)
Private Extern mpeg3_audio_format(mpeg3file As Mpeg3_t, _stream As Integer) As Pointer

' long mpeg3_audio_samples(mpeg3_t *file, int stream)
Private Extern mpeg3_audio_samples(mpeg3file As Mpeg3_t, _stream As Integer) As Long

' int mpeg3_read_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream)
' Read a PCM buffer of audio from 1 channel and advance the position.
Private Extern mpeg3_read_audio(mpeg3 As Mpeg3_t, f As Pointer, i As Pointer, can As Integer, sa As Long, st As Integer)

' int mpeg3_reread_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream)
' Reread a PCM buffer of audio from 1 channel and advance the position.
Private Extern mpeg3_reread_audio(mpeg3 As Mpeg3_t, f As Pointer, i As Pointer, can As Integer, sa As Long, st As Integer) 

' double mpeg3_get_time(mpeg3_t *file)
' Give the seconds time in the last packet read.
Private Extern mpeg3_get_time(mpeg3 As Mpeg3_t) As Float

' int mpeg3_close(mpeg3_t *file)
Private Extern mpeg3_close(mpeg3file As Mpeg3_t) As Integer


Library "libasound:2"

Private Const SND_PCM_STREAM_PLAYBACK As Byte = 0
Private Const SND_PCM_FORMAT_S16_LE As Byte = 2
Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3

' int snd_pcm_open (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode)
' Opens a PCM.
Private Extern snd_pcm_open(pcm As Pointer, nome As String, stream As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an Error code.
Private Extern snd_strerror(errnum As Integer) As String

' int snd_pcm_set_params (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int canali, unsigned int rate, int soft_resample, unsigned int latency)
' Set the hardware and software parameters in a simple way.
Private Extern snd_pcm_set_params(pcm As Pointer, formatB As Byte, accessB As Byte, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer

' snd_pcm_sframes_t snd_pcm_writei (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
' Write interleaved frames to a PCM.
Private Extern snd_pcm_writei(pcm As Pointer, buffer As Pointer, uframes As Long) As Integer

' int snd_pcm_drop (snd_pcm_t *pcm)
' Stop a PCM dropping pending frames.
Private Extern snd_pcm_drop(pcmP As Pointer) As Integer

' int snd_pcm_close (snd_pcm_t *pcm)
' Close PCM handle.
Private Extern snd_pcm_close(pcm As Pointer) As Integer


Public Sub Main()

 Dim perc As String
 Dim i, can, freq, n, x As Integer
 Dim cmp As Long
 Dim mp3 As Mpeg3_t
 Dim cc1, cc2, buf As Short[]
 Dim handle As Pointer
 
 perc = "/percorso/del/file.mp3"
 If Not Exist(perc) Then Error.Raise("Errore: file inesistente !")
 
 i = mpeg3_check_sig(perc)
 If i = 0 Then Error.Raise("Tipo file incompatibile !")
 
 mp3 = mpeg3_open(perc, 0)
 
 Print "File audio:     "; perc
 Print "Dimensione:     "; mpeg3_get_bytes(mp3); " byte"
 can = mpeg3_audio_channels(mp3, 0)
 Print "Numero canali:  "; can
 freq = mpeg3_sample_rate(mp3, 0)
 Print "Frequenza:      "; freq; " hertz"
 Print "Formato audio:  "; String@(mpeg3_audio_format(mp3, 0))
 cmp = mpeg3_audio_samples(mp3, 0)
 Print "Campioni audio: "; cmp; " byte"
 Write "Attendere, elaborazione in corso......"
 Flush
 
'Sezione per l'estrazione dei dati audio grezzi (PCM)'
 
' La dimensione dei vettori è aumentata del valore della Costante "BUFFER", per impedire che nella sezione,
' dedicata alla scrittura dei dati nel dispositivo PCM di Alsa, venga sollevato un errore di "Out of bound":
 cc1 = New Short[cmp + BUFFER]
 If can = 2 Then cc2 = New Short[cmp + BUFFER]
 
' Vengono estratti i dati audio grezzi per ciascun canale:
 mpeg3_read_audio(mp3, 0, cc1.Data, 0, cmp, 0)
 If can = 2 Then mpeg3_reread_audio(mp3, 0, cc2.Data, 1, cmp, 0)
 Print "\r" & Space(38); "\rDurata:         "; Time(0, 0, 0, mpeg3_get_time(mp3) * 1000)
 Print
 
'''''''''''''''''''''''''''''''''''
 
' Vengono utilizzate le funzioni esterne essenziali di Alsa:
 i = snd_pcm_open(VarPtr(handle), "default", SND_PCM_STREAM_PLAYBACK, 0)
 If i < 0 Then Error.Raise("Errore nell'apertura del subsistema PCM: " & snd_strerror(i))
 
 i = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, can, freq, 1, 500000)
 If i < 0 Then Error.Raise("Errore nell'impostazione dei parametri audio: " & snd_strerror(i))
 
 buf = New Short[]
 
' Scrive i dati nell'interfaccia PCM:
 While n < (cmp -1)
   buf.Clear
' Scrive progressivamente gruppi di 256 campioni audio di ciascun canale in un vettore,
' per garantire l'accesso ai dati in formato "interleaved" [Nota 1]:
   For x = 1 To BUFFER
     buf.Push(cc1[n])
     If can = 2 Then buf.Push(cc2[n])
     Inc n
   Next
   i = snd_pcm_writei(handle, buf.Data, BUFFER)
   If i < 0 Then Break
' Mostra il tempo trascorso:
   Write "\rTempo trascorso: " & Time(0, 0, 0, (n / freq) * 1000)
 Wend
 
 Chiude(handle, mp3)
  
End


Private Procedure Chiude(han As Pointer, mpe As Mpeg3_t)
 
 Dim err As Integer
 
 err = snd_pcm_drop(han)
 If err <> 0 Then Error.Raise("Impossibile fermare l'esecuzione dei dati audio !")
 Print "\nEsecuzione fermata !"
 
' Alla fine dell'esecuzione del file audio chiude il subsistema PCM ed il file:
 err = snd_pcm_close(han)
 If err = 0 Then Print "\nChiusura dell'interfaccia PCM: regolare."
 
 mpeg3_close(mpe)
  
End


Note

[1] PCM Ring Buffer, http://kom.aau.dk/group/05gr506/report/node21.html