La gestione dell'audio e dei file audio mediante le funzioni esterne del API di Opus
Opus è un codec audio totalmente aperto, esente da diritti e altamente versatile.
Opus è in grado di gestire un'ampia gamma di applicazioni audio, tra cui Voice over IP, videoconferenze, chat in-game e persino esibizioni di musica dal vivo in remoto.
Può passare dal parlato, a banda stretta, a basso bitrate e a musica stereo di altissima qualità.
E' necessario avere installata nel sistema e richiamare in Gambas la libreria condivisa: "libopus.so.0.10.1 ".
Codificare e decodificare un flusso audio Opus mediante la libreria Libopus
Vediamo di seguito un breve esempio di codifica e decodifica audio usando Opus, per mostrare semplicemente come questa libreria funziona. In particolare da un file wav si otterrà un flusso audio codificato con Opus, e si decodificherà tale flusso opus codificandolo nuovamente in un file di tipo wav.
Private Const FRAME_SIZE As Integer = 960 Private Const SAMPLE_RATE As Integer = 48000 Private Const CANALI As Integer = 2 Private Const MAX_FRAME_SIZE As Integer = 6 * 960 Private Const MAX_PACKET_SIZE As Integer = 3 * 1276 Library "libopus:0.10.1" Private Const OPUS_APPLICATION_VOIP As Integer = 2048 Private Const OPUS_APPLICATION_AUDIO As Integer = 2049 Private Const OPUS_APPLICATION_RESTRICTED_LOWDELAY As Integer = 2051 ' OpusEncoder *opus_encoder_create( opus_int32 Fs, int channels, int application, int *error ) ' Allocates and initializes an encoder state. Private Extern opus_encoder_create(Fs As Integer, channels As Integer, _application As Integer, _error As Pointer) As Pointer ' const char *opus_strerror(int error) ' Converts an opus error code into a human readable string. Private Extern opus_strerror(_error As Integer) As String ' opus_int32 opus_encode( OpusEncoder *st, const opus_int16 *pcm, int buffer, unsigned char *data, opus_int32 max_data_bytes) ' Encodes an Opus frame. Private Extern opus_encode(st As Pointer, pcm As Pointer, buffer As Integer, data As Pointer, max_data_bytes As Integer) As Integer ' OpusDecoder *opus_decoder_create( opus_int32 Fs, int channels, int *error ) ' Allocates and initializes a decoder state. Private Extern opus_decoder_create(Fs As Integer, channels As Integer, _error As Pointer) As Pointer ' int opus_decode( OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) ' Decode an Opus packet. Private Extern opus_decode(st As Pointer, data As Pointer, _len As Integer, pcm As Pointer, frame_size As Integer, decode_fec As Integer) As Integer ' void opus_encoder_destroy(OpusEncoder *st) ' Frees an OpusEncoder allocated by opus_encoder_create(). Private Extern opus_encoder_destroy(st As Pointer) Public Sub Main() Dim wav As String Dim enco, deco As Pointer Dim c, i, nb, frames As Integer Dim fen, fex As File Dim buffIn As New Integer[FRAME_SIZE * CANALI] Dim buffOut As New Integer[MAX_FRAME_SIZE * CANALI] Dim cbits As New Short[MAX_PACKET_SIZE] Dim pcm_bytes As Short[] Write "\e[5mAttendere...\e[0m" Flush wav = "/percorso/del/file.wav" ' Crea il codificatore in formato "opus":" enco = opus_encoder_create(SAMPLE_RATE, CANALI, OPUS_APPLICATION_AUDIO, VarPtr(i)) If enco = 0 Then Error.Raise("Errore: " & opus_strerror(i)) fen = Open wav For Read ' Crea il file finale wav che dovrà contenere i dati audio del flusso "opus" ri-decodificato:: fen = Open wav For Read ' Crea il decodificatore: deco = opus_decoder_create(SAMPLE_RATE, CANALI, VarPtr(i)) If deco = 0 Then Error.Raise("Errore: " & opus_strerror(i)) ' Crea il file finale wav che dovrà contenere i dati audio del flusso "opus" ri-decodificato: fex = Open "/tmp/dati.raw" For Create c = SizeOf(gb.integer) * CANALI * FRAME_SIZE Repeat pcm_bytes = New Short[MAX_FRAME_SIZE * CANALI] ''''' Fase di codifica audio Opus ''''' ' Evita l'errore di "Fine del file": If (Lof(fen) - Seek(fen)) < FRAME_SIZE * CANALI * SizeOf(gb.Integer) Then c = Lof(fen) - Seek(fen) ' Legge i dati audio dal file wav iniziale: pcm_bytes.Read(fen, 0, c) ' Effettua la conversione dall'ordine Little-Endian: For i = 0 To (CANALI * FRAME_SIZE) - 1 buffIn[i] = pcm_bytes[2 * i + 1] * CInt(2 ^ 8) Or pcm_bytes[2 * i] Next ' Codifica il frame audio: nb = opus_encode(enco, buffIn.Data, FRAME_SIZE, cbits.Data, MAX_PACKET_SIZE) If nb < 0 Then Error.Raise("Errore: " & opus_strerror(nb)) ''''' Fase di decodifica audio da Opus in PCM grezzi ''''' ' Decodifica i dati. In questo esempio, frame_size sarà costante poiché l'encoder utilizza una dimensione di frame costante. ' Tuttavia, potrebbe non essere il caso per tutti gli encoder, quindi il decoder deve sempre controllare la dimensione del frame restituita. frames = opus_decode(deco, cbits.Data, nb, buffOut.Data, MAX_FRAME_SIZE, 0) If frames < 0 Then Error.Raise("Errore: " & opus_strerror(frames)) ' Effettua la conversione all'ordine Little-Endian: For i = 0 To (CANALI * frames) - 1 pcm_bytes[SizeOf(gb.Integer) * i] = buffOut[i] And &FF pcm_bytes[SizeOf(gb.Integer) * i + 4] = (buffOut[i] \ CInt(2 ^ 8)) And &FF Next ' Scrive l'audio decodificato nel file di dati grezzi: pcm_bytes.Write(fex, 0, SizeOf(gb.Integer) * frames * CANALI)'pcm_bytes.Count) Until (Lof(fen) - Seek(fen)) < FRAME_SIZE * CANALI * SizeOf(gb.Integer) fen.Close fex.Close HeaderWav() opus_encoder_destroy(deco) opus_encoder_destroy(enco) End Private Procedure HeaderWav() ' Crea l'header del file wav Dim hdr As Byte[] Dim b As Byte Dim s As String ' Imposta i dati principali dell'header del file WAV finale: hdr = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56, &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00, &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04, &00, &10, &00, &64, &61, &74, &61, &00, &00, &00, &00] s = File.Load("/tmp/dati.raw") ' Determina i valori a 32-bit, relativi alla dimensione del file wav, richiesti al 5° e al 41° byte dell'header: For b = 0 To 3 hdr[4 + b] = Shr(Len(s) + 38, 8 * b) And &FF hdr[40 + b] = Shr(Len(s), 8 * b) And &FF Next ' Genera il file finale di tipo WAV dai dati Opus riconvertiti in PCM grezzi: File.Save("/tmp/file_finale.wav", hdr.ToString(0, hdr.Count) & s) Write "\rFile WAV creato !" End