Convertire un file WAV in formato OggVorbis con le funzioni esterne del API di libvorbisfile, libvorbisenc e libogg

Da Gambas-it.org - Wikipedia.

Per convertire un file WAV 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 dinamiche condivise: "libvorbisfile.so.3.3.4", "libvorbisenc.so.2.0.8" e "libogg.so.0.8.1" .


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.4"
 
' 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.8"

' 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.1"

' 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)
  
' 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)
  
  Print "Conversione 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



Riferimenti