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