Recientemente me ha surgido la necesidad de convertir unos ficheros de audio que estaban en formato .WAV comprimido con el codec G729A a un formato .WAV reproducible en cualquier PC para hacer unas pruebas. Se trataba de poder escuchar ficheros .WAV que estaban comprimidos con ese codec, pero dada la dificultad de encontrar el codec gratuitamente para poder instalarlo en Windows he encontrado una alternativa que sirve igualmente.
En la página de Voice Age he encontrado una librería gratuita para windows con ejemplos y ejecutables de cómo extraer el audio comprimido con un codec G729A. Si se va a usar comercialmente se debe pedir una licencia a sipro que es quien tiene los derechos de licenciamiento.
El problema con los ejecutables de Voice Age es que convierte de formato G729A a formato RAW, pero ni el origen tiene los datos por sí sólo (están embebidos en un fichero .wav) ni en la conversión se pasa a un fichero .wav reproducible en windows.
Por ello he creado un programa de consola en Visual C++ 6.0 que hace uso de la librería .lib que ofrece VoiceAge para hacer esos dos pasos. La idea es leer unos datos del fichero wav y moverse hasta el byte 44 del fichero wav de origen, accediendo así a los datos de audio directamente; crear un fichero .wav de destino, introduciendo en este la cabecera de un fichero .wav con el tamaño de los datos de audio descomprimido e indicando que tiene formato PCM; finalmente leer los datos de audio comprimido, descomprimirlos con la librería y escribirlos en el fichero de destino.
Este es el código fuente del mismo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
#include "stdafx.h" #include "va_g729.h" #include <stdio.h> #include <memory.h> int main(int argc, char* argv[]) { FILE *entrada; FILE *salida; unsigned char serial[L_FRAME_COMPRESSED]; short synth[L_FRAME]; int bfi; unsigned char cabecera[] = {0x52,0x49,0x46,0x46,0x00,0x00,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x40,0x1F,0x00,0x00,0x80,0x3E,0x00,0x00,0x02,0x00,0x10,0x00,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00}; unsigned long longitud; unsigned long *puntero; puts("SISTEMAS O.R.P.\nConvertidor de WAVs G729A a PCM\n"); // Se comprueban los parámetros if(argc != 3) { puts("Debe introducir el archivo wav de origen y el archivo wav de destino."); return 1; } // Se abre el fichero de origen entrada = fopen(argv[1], "rb"); if(entrada == NULL) { puts("No se pudo abrir el fichero de origen"); return 2; } // Se abre el fichero de destino salida = fopen(argv[2], "wb"); if(salida == NULL) { puts("No se pudo abrir el fichero de destino"); fclose(entrada); return 2; } // Se comprueba que el fichero origen es un .wav fread(serial, sizeof(char), 4, entrada); if(memcmp(serial, "RIFF", 4) != 0) { puts("El fichero de entrada no es un wav"); fclose(entrada); fclose(salida); return 3; } // Se lee el tamaño de los datos de audio del fichero origen // y se calcula el tamaño de los datis de audio del fichero destino fread(&longitud, sizeof(unsigned long), 1, entrada); puntero = (unsigned long *)(cabecera + 4); *puntero = 36 + (longitud - 36) * L_FRAME / L_FRAME_COMPRESSED * 2; puntero = (unsigned long *)(cabecera + 40); *puntero = (longitud - 36) * L_FRAME / L_FRAME_COMPRESSED * 2; // Se escribe la cabecera wav al fichero de destino fwrite(cabecera, sizeof(char), sizeof(cabecera), salida); // Saltamos al byte 44 donde se encuentran los datos de audio comprimido fseek(entrada, 44, SEEK_SET); // Se inicializa el descompresor va_g729a_init_decoder(); // Se lee un grupo de bytes comprimidos y se escriben descomprimidos while (fread(serial, sizeof(char), L_FRAME_COMPRESSED, entrada) == L_FRAME_COMPRESSED) { bfi = 0; va_g729a_decoder(serial, synth, bfi); fwrite(synth, sizeof(short), L_FRAME, salida); } fclose(entrada); fclose(salida); puts("Proceso terminado"); return 0; } |
Y aquí dejo el fichero ejecutable: