Convertire un file WAV in formato OggVorbis con le funzioni esterne del API di libvorbisfile, libvorbisenc e libogg
Per convertire un file "WAV" (ma anche un file "AIFF") in formato VorbisOgg, è possibile utilizzare le risorse delle funzioni esterne contenute nelle librerie libvorbisfile, libvorbisenc e libogg.
Per poter fuire in Gambas di tali librerie esterne, è necessario avere installate le seguenti librerie condivise: "libvorbisfile.so.3.3.8 ", "libvorbisenc.so.2.0.12 " e "libogg.so.0.8.5 " .
Nel semplice esempio appresso mostrato, saremo costretti a creare, inoltre, un nostra apposita libreria dinamica condivisa esterna, nella quale porre una buona parte del codice necessario per la conversione, atteso che in Gambas attualmente non è dichiarabile un tipo di valore corrispondente al "signed char ", come richiesto appunto dalla parte di codice C.
Il file WAV da convertire dovrà avere le seguenti caratteristiche fondamentali: 44100 hertz, 16 bit, 2 canali.
Public Struct ogg_stream_state body_data As Pointer body_storage As Long body_fill As Long body_returned As Long lacing_vals As Pointer granule_vals As Pointer lacing_storage As Long lacing_fill As Long lacing_packet As Long lacing_returned As Long header[282] As Byte header_fill As Integer e_o_s As Integer b_o_s As Integer serialno As Long pageno As Long packetno As Long granulepos As Long End Struct Public Struct ogg_page header As Pointer header_len As Long body As Pointer body_len As Long End Struct Public Struct ogg_packet packet As Pointer bytes As Long b_o_s As Long e_o_s As Long granulepos As Long packetno As Long End Struct Public Struct vorbis_info version As Integer channels As Integer rate As Long bitrate_upper As Long bitrate_nominal As Long bitrate_lower As Long bitrate_window As Long codec_setup As Pointer End Struct Public Struct vorbis_comment user_comments As Pointer comment_lengths As Pointer comments As Integer vendor As Pointer End Struct Public Struct vorbis_dsp_state analysisp As Integer vi As Pointer pcm As Pointer pcmret As Pointer pcm_storage As Integer pcm_current As Integer pcm_returned As Integer preextrapolate As Integer eofflag As Integer lW As Long W As Long nW As Long centerW As Long granulepos As Long sequence As Long glue_bits As Long time_bits As Long floor_bits As Long res_bits As Long End Struct Public Struct oggpack_buffer endbyte As Long endbit As Integer buffer As Pointer ptr As Pointer storage As Long End Struct Public Struct vorbis_block pcm As Pointer opb As Struct Oggpack_buffer lW As Long W As Long nW As Long pcmend As Integer mode As Integer eofflag As Integer granulepos As Long sequence As Long vd As Pointer localstore As Pointer localtop As Long localalloc As Long totaluse As Long reap As Pointer glue_bits As Long time_bits As Long floor_bits As Long res_bits As Long internal As Pointer End Struct Library "libvorbisfile:3.3.8" ' void vorbis_info_init(vorbis_info *vi) ' Initializes a vorbis_info structure and allocates its internal storage. Private Extern vorbis_info_init(vo_inf As Vorbis_info) ' void vorbis_comment_init(vorbis_comment *vc) ' Initializes a vorbis_comment structure for use. Private Extern vorbis_comment_init(vc As Vorbis_comment) ' void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents) ' Adds a tag-comment pair to a vorbis_comment structure. Private Extern vorbis_comment_add_tag(vc As Vorbis_comment, tag As String, contents As String) ' int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi) ' Allocates and initializes the encoder's analysis state inside a is vorbis_dsp_state. Private Extern vorbis_analysis_init(v As Vorbis_dsp_state, vi As Vorbis_info) As Integer ' int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb) ' Initializes a vorbis_block structure and allocates its internal storage. Private Extern vorbis_block_init(v As Vorbis_dsp_state, vb As Vorbis_block) As Integer ' int vorbis_analysis_headerout(vorbis_dsp_state *v, vorbis_comment *vc, ogg_packet *op, ogg_packet *op_comm, ogg_packet *op_code) ' Creates and returns the three header packets needed to configure a decoder to accept compressed data. Private Extern vorbis_analysis_headerout(v As Vorbis_dsp_state, vc As Vorbis_comment, op As Ogg_packet, op_comm As Ogg_packet, op_code As Ogg_packet) As Integer ' int vorbis_block_clear(vorbis_block *vb) ' Frees the internal storage for a vorbis_block structure. Private Extern vorbis_block_clear(vb As Vorbis_block) ' void vorbis_dsp_clear(vorbis_dsp_state *v) ' Frees the internal storage for a vorbis_dsp_state structure. Private Extern vorbis_dsp_clear(vd As Vorbis_dsp_state) ' void vorbis_comment_clear(vorbis_comment *vc) ' Frees the internal storage associated with a vorbis_comment structure. Private Extern vorbis_comment_clear(vc As Vorbis_comment) ' vorbis_info_clear(vorbis_info *vi) ' Frees the internal storage for a vorbis_info structure. Private Extern vorbis_info_clear(vi As Vorbis_info) Library "libvorbisenc:2.0.12" ' int vorbis_encode_init_vbr(vorbis_info *vi, long channels, long rate, float base_quality) ' For setting up variable bitrate ("quality" based) modes. Private Extern vorbis_encode_init_vbr(vi As Vorbis_info, channels As Long, rate As Long, base_quality As Single) As Integer Library "libogg:0.8.5" ' int ogg_stream_init(ogg_stream_state *os,int serialno) ' Initialize an ogg_stream_state struct and allocates appropriate memory in preparation for encoding or decoding. Private Extern ogg_stream_init(os As Ogg_stream_state, serialno As Integer) As Integer ' int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op) ' Submits a packet to the bitstream for page encapsulation. Private Extern ogg_stream_packetin(os As Ogg_stream_state, op As Ogg_packet) As Integer ' int ogg_stream_flush(ogg_stream_state *os, ogg_page *og) ' checks for remaining packets inside the stream and forces remaining packets into a page, regardless of the size of the page. Private Extern ogg_stream_flush(os As Ogg_stream_state, og As Ogg_page) As Integer ' int ogg_stream_clear(ogg_stream_state *os) ' Clears and frees the internal memory used by the ogg_stream_state struct, but does not free the structure itself. Private Extern ogg_stream_clear(os As Ogg_stream_state) Library "libc:6" ' FILE *fopen(const char *__restrict __filename, const char *__restrict __modes) ' Apre il file path associandolo ad uno stream. Private Extern fopen(__filename As String, modes As String) As Pointer ' size_t fwrite(const void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __s) ' Scrive su stream nmemb elementi, ciascuno di dimensione size. Private Extern fwrite(__ptr As Pointer, __size As Integer, __n As Integer, __s As Pointer) As Integer ' int fclose(FILE *__stream) ' Chiude il file associato a stream. Private Extern fclose(stmP As Pointer) As Integer Library "/tmp/libso" ' int creaOGG(FILE **fl, signed char readbuffer[READ*4+44], vorbis_info *vi, vorbis_comment *vc, vorbis_dsp_state *vd, vorbis_block *vb, ogg_stream_state *os, ogg_page *og) ' Funzione contenente il codice in C puro per la creazione del file OGG. Private Extern creaOGG(inout As Pointer[], buff As Byte[], vi As Vorbis_info, vc As Vorbis_comment, vd As Vorbis_dsp_state, vb As Vorbis_block, os As Ogg_stream_state, og As Ogg_page) As Integer Public Sub Main() Dim percorsoFileWAV, percorsoFileOGG As String Dim readbuffer As Short[] Dim files As New Pointer[] Dim os As New Ogg_stream_state Dim og As New Ogg_page Dim vi As New Vorbis_info Dim vc As New Vorbis_comment Dim vd As New Vorbis_dsp_state Dim vb As New Vorbis_block Dim eos, ret, result As Integer Dim header, header_comm, header_code As New Ogg_packet Creaso() percorsoFileWAV = "/percorso/del/file.wav" percorsoFileOGG = "/tmp/audioOGG.ogg" readbuffer = New Byte[](1024 * 8 + 44) ' Apriamo un file wav presumendo che sia 44.100 hertz, stereo, 16 bit: files.Push(fopen(percorsoFileWAV, "rb")) files.Push(fopen(percorsoFileOGG, "wb")) vorbis_info_init(vi) ret = vorbis_encode_init_vbr(vi, 2, 44100, 0.1) If ret <> 0 Then Error.Raise("Errore alla funzione 'vorbis_encode_init_vbr()' !") ' Viene aggiunto un commento nel futuro file "ogg": vorbis_comment_init(vc) vorbis_comment_add_tag(vc, "ENCODER", "codificatore gambas") ' Imposta lo stato di analisi e l'archiviazione ausiliaria di codifica: vorbis_analysis_init(vd, vi) vorbis_block_init(vd, vb) Randomize CInt(Time(Null)) ogg_stream_init(os, Rnd()) vorbis_analysis_headerout(vd, vc, header, header_comm, header_code) ogg_stream_packetin(os, header) ogg_stream_packetin(os, header_comm) ogg_stream_packetin(os, header_code) Write "\e[5mAttendere...\e[0m" Flush ' In questo modo i dati audio effettivi avranno inizio su una nuova pagina, come da specifiche: While Not eos result = ogg_stream_flush(os, og) If result = 0 Then Break fwrite(og.header, 1, og.header_len, files[1]) fwrite(og.body, 1, og.body_len, files[1]) Wend creaOGG(files, readbuffer, vi, vc, vd, vb, os, og) Write "\rConversione da WAV a OGG terminata !" ' Va in chiusura liberando la memoria precedentemente allocata: fclose(files[0]) fclose(files[1]) ogg_stream_clear(os) vorbis_block_clear(vb) vorbis_dsp_clear(vd) vorbis_comment_clear(vc) ' La funzione "vorbis_info_clear()" va sempre chiamata per ultima: vorbis_info_clear(vi) End Private Procedure Creaso() File.Save("/tmp/libso.c", "/********************************************************************\n" & "* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *\n" & "* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *\n" & "* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\n" & "* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *\n" & "* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *\n" & "* by the Xiph.Org Foundation http://www.xiph.org/ *\n" & "********************************************************************/\n\n" & "#include <stdio.h>\n#include <vorbis/vorbisenc.h>\n#include <vorbis/codec.h>\n#include <ogg/ogg.h>\n\n" & "#define READ 1024\n\n" & "int creaOGG(FILE **fl, signed char readbuffer[READ*4+44], vorbis_info *vi, vorbis_comment *vc, vorbis_dsp_state *vd, vorbis_block *vb, ogg_stream_state *os, ogg_page *og) {\n\n" & " ogg_packet op;\n" & " int eos = 0, i;\n" & " fseek(*fl, 4, SEEK_SET);\n\n" & " while(!eos){\n" & " long bytes=fread(readbuffer, 1, READ*4, *fl);\n\n" & " if(0==bytes){\n" & " vorbis_analysis_wrote(vd, 0);\n" & " }else{\n" & " float **buffer=vorbis_analysis_buffer(vd, READ);\n\n" " for(i=0;i<bytes/4;i++){\n" & " buffer[0][i]=((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))/32768.f;\n" " buffer[1][i]=((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))/32768.f;\n}\n\n" & " vorbis_analysis_wrote(vd,i);\n}\n\n" & " while(vorbis_analysis_blockout(vd, vb)==1){\n\n" & " vorbis_analysis(vb,NULL);\n" & " vorbis_bitrate_addblock(vb);\n\n" & " while(vorbis_bitrate_flushpacket(vd, &op)){\n\n" & " ogg_stream_packetin(os, &op);\n\n" & " while(!eos){\n" & " int result=ogg_stream_pageout(os, og);\n" & " if(0==result)break;\n" & " fwrite(og->header,1,og->header_len,*(fl+1));\n" & " fwrite(og->body,1,og->body_len,*(fl+1));\n" & " if(ogg_page_eos(og)) eos=1;\n\n}\n}\n}\n}\n\n" & " return (0);\n\n}") Shell "gcc -o /tmp/libso.so /tmp/libso.c -shared -fPIC -lvorbis" Wait End