compresión de audio

Anuncio
PRÁCTICAS
TXÓN. DATOS
MULTIMEDIA
COMPRESIÓN DE AUDIO
1. Introducción
En esta práctica vamos a tratar la compresión de audio. En concreto vamos a estudiar la
conversión de una serie de muestras de audio sin comprimir (codificadas en formato
PCM, con 16 bits por muestra y en un único canal, o sea “mono”) a codificación
ADPCM. Particularmente, usaremos la versión de ADPCM de IMA (también conocido
como DVI ADPCM), en la que la predicción de la muestra actual se basa simplemente
en la muestra previamente codificada, y la adaptación del paso de cuantización se hace
de manera adaptativa usando para ello unas tablas estándar.
Además, estudiaremos el formato WAV diseñado inicialmente por IBM y Microsoft
para almacenar ficheros de audio en ordenadores PC. Veremos cuál es su estructura para
guardar sonido en ambos formatos, tanto PCM como IMA ADPCM.
Como en el resto de prácticas, proporcionaremos el código fuente con una
implementación parcial del compresor, y que se deberá de analizar y completar. En
concreto, la función a implementar es la codificación de una muestra de formato PCM a
ADPCM, usando el algoritmo adaptativo estudiado en las sesiones de teoría. De nuevo,
esta implementación se ha escrito en lenguaje ANSI C++, y la interacción con el usuario
se realiza por medio de paso de comandos en una ventana de sistema, por lo que su
compilación se puede realizar en cualquier entorno de desarrollo C++, tanto Windows
como Linux.
Un requerimiento adicional en esta práctica, si se desea poder escuchar el fichero
resultante de la codificación, es disponer de un ordenador con capacidad de
reproducción de audio, además de un programa reproductor que sea compatible con
ambos formatos .wav, tanto PCM como IMA ADPCM. En general, en los sistemas
operativos MS Windows se incluye por defecto tanto el decodificador de IMA ADPCM
como algún reproductor de audio compatible (por ejemplo, la “grabadora de sonidos” o
el “reproductor de windows media”).
2. Codificación IMA ADPCM
La codificación ADPCM es un tipo de codificación diferencial con pérdidas, en la que
la diferencia de la muestra codificada respecto a la muestra anterior se cuantiza con un
paso de cuantización (step) adaptativo. Este paso de cuantización es adaptativo porque
se va incrementando o decrementando en función de la magnitud de las diferencias
previamente codificadas.
En esta práctica nos vamos a centrar en la versión concreta de ADPCM propuesta por la
extinta Asociación de Multimedia Interactiva (Interactive Multimedia Association,
IMA). Esta versión de ADPCM, que a veces también es denominada como Intel DVI
ADPCM, es capaz de comprimir muestras usando 3 ó 4 bits por muestra. En el caso que
vamos a tratar en esta práctica convertiremos muestras de 16 bits en muestras de 4 bits,
1
con lo que el nivel de compresión alcanzado será de 4:1. Aunque la tasa de compresión
alcanzada con este tipo de compresión no es mucha, su sencillez de implementación
tanto en hardware como en software ha provocado que tenga una gran difusión dentro
de la industria audiovisual. Así, prácticamente todos los sistemas operativos MS
Windows incluyen un codificador de esta versión de ADPCM. Además, muchas
grabadoras de audio digital de modestas prestaciones utilizan este formato para
almacenar el audio de una forma más compacta. Por ejemplo, muchos reproductores
MP3 con capacidad de grabar audio directamente a través de un micrófono incorporado
codifican el resultado de la grabación en este formato.
2.1 Algoritmo IMA ADPCM
Veamos a continuación cómo funciona este algoritmo, cuya implementación se realizará
en el fichero ADPCM.cpp proporcionado en esta práctica.
Como ya hemos dicho, básicamente se realiza una codificación diferencial respecto a la
muestra anterior, pero usando una cuantización adaptativa, de forma que si el resultado
de cuantizar las muestras anteriores ha dado un valor muy grande, se aumenta el paso de
cuantización, y si ha sido más bien pequeño se disminuye.
Para indicar los posibles pasos de cuantización a aplicar se dispone de una tabla (cuyos
pasos se incrementan siguiendo una escala logarítmica). Dentro del código fuente a
completar en esta práctica, esta tabla viene definida como sigue:
static const unsigned short IMA_ADPCMStepTable[89] =
{
7,
8,
9,
10,
11,
12,
13,
14,
16,
17,
19,
21,
23,
25,
28,
31,
34,
37,
41,
45,
50,
55,
60,
66,
73,
80,
88,
97, 107, 118, 130, 143,
157,
173, 190, 209, 230, 253, 279, 307,
337,
371, 408, 449, 494, 544, 598, 658,
724,
796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493,10442,11487,12635,13899,
15289,16818,18500,20350,22385,24623,27086,29794,
32767
};
Para la compresión de una muestra m codificada en formato PCM (es decir, sin
compresión) se parte de uno de los pasos de esta tabla (en concreto de aquel indexado
por la variable global int StepIndex del fichero ADPCM.cpp), y de la muestra que se
codificó en el paso anterior, tal y como la leerá el decodificador (variable global signed
short PredictedValue). Por tanto, lo primero que hay que calcular es la diferencia
(delta, ∆) entre esta muestra y la anterior
∆ = m - PredictedValue
siendo este valor de delta lo que vamos a codificar con el paso de cuantización (step)
que nos indique la tabla anterior (que lo podremos obtener como
step=IMA_ADPCMStepTable[StepIndex]).
2
A continuación vamos a ver exactamente cómo codificar esta diferencia usando los
cuatro bits de ADPCM (del bit 3 al bit 0):
•
El bit 3 tiene un tratamiento especial ya que nos indica el signo de la diferencia.
Codificamos 1 para signo negativo, 0 en otro caso. Además, para continuar con
la codificación, aplicaremos valor absoluto a la diferencia delta: ∆ = ∆
A continuación, el bit 2 se codifica con un 1, si ∆ > step . En ese caso,
actualizamos delta como sigue: ∆ = ∆ − step
step
. En ese caso, también
• Ahora, el bit 1 se codifica con un 1, si ∆ >
2
step
actualizaremos delta como sigue: ∆ = ∆ −
2
step
• Por último, el bit 0 se codifica con un 1, si ∆ >
.
4
Es importante destacar que todas las operaciones que se realizan en la codificación IMA
ADPCM son siempre enteras, para lo que bastará con usar tipos de datos enteros (o sea,
operandos enteros).
•
A continuación hay que decodificar el valor que acabamos de codificar para asignarlo a
la variable global PredictedValue, de forma que la próxima muestra se pueda
codificar diferencialmente a partir de este valor. Observa que usamos el valor de la
muestra tal y como lo leerá el decodificador (es decir, después de la cuantización y la
decuantización) y no la muestra original. Esto se hace así porque el decodificador no
dispone de los valores de estas muestras originales sino tan sólo de su decodificación.
Por último, hay que realizar la adaptación de la cuantización. Para esto debemos de
actualizar el índice del paso de cuantización (la variable global int StepIndex) según
el resultado de la codificación ADPCM que acabamos de realizar. Para esta
actualización usaremos los tres bits de menor peso del resultado de la muestra
codificada1 como índice a otra tabla que se usa para incrementar o decrementar la
variable global StepIndex. En concreto, esta tabla está definida en ADPCM.cpp como
sigue:
static const int IMA_ADPCMIndexTable[8] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
};
Como se puede observar, resultados entre 0 y 3 provocan que el índice del paso de
cuantización (StepIndex) se decremente en uno, mientras que un resultado de 4, 5, 6 ó
7 hace que este índice aumente en 2, 4, 6 u 8 respectivamente (lo que resultará en
aumentos en el paso de cuantización mucho mayores). De esta forma es como
adaptamos el paso de cuantización al resultado de previas codificaciones.
1
Para obtener los tres bits de menor peso basta con aplicar una máscara usando la operación “and” entre
“7” y el valor resultante de la codificación. En lenguaje C esta operación se puede hacer utilizando el
operador “&”.
3
Algo a tener en cuenta es que la tabla IMA_ADPCMStepTable sólo contiene 89 valores, y
por tanto la variable StepIndex debe de mantenerse siempre dentro del rango de [0 a
88].
3. Ficheros WAV
Los ficheros WAV (cuya extensión es .wav) se basan en un formato diseñado por
Microsoft e IBM para almacenar ficheros de audio. Aunque su uso más habitual es
guardar información sin comprimir en formato PCM, también se puede usar como un
“contenedor” de otros tipos de formatos, como es el caso de IMA ADPCM. En este
punto vamos a describir cuál es el formato habitual de este tipo de ficheros. Sin
embargo, es importante destacar que existe una gran variedad dentro de este tipo de
ficheros, que a su vez son una variante del formato RIFF para almacenar un stream de
datos multimedia en fichero a base de “chunks” (o por “trozos”).
0
Identificador (“RIFF”)
4
Longitud de fichero - 8
8
Formato (“WAVE”)
12
Sub-identificador de formato (“fmt “)
16
Longitud de formato de audio
20
Formato de audio
24
Frecuencia de muestreo (muestras/seg.)
28
Tasa de bytes (bytes/seg.)
Alineamiento de
Bits por muestra
bloques
32
Número de canales
36/40
Sub-identificador de datos (“data”)
40/44
Longitud del campo de datos
44/48
DATOS
Tamaño de
parámetros
extra
Cuenta de
muestras por
36
canal por bloque
Figura 1: Formato de los ficheros .wav (tanto PCM como ADPCM)
En la Figura 1 se describe cuál es el formato de un fichero .wav canónico, para su uso
tanto en codificación de muestras PCM como IMA ADPCM. A continuación
explicaremos brevemente los campos (de 4 bytes en la mayor parte de casos) que lo
forman, según cada una de las tres partes que componen un fichero .wav:
•
Descripción general del fichero RIFF. Se incluye un identificador del propio
formato general (codificación ASCII de la cadena “RIFF”), la longitud del
fichero (a partir de esa etiqueta, por tanto sin contar los 8 primeros bytes) y otro
identificador de formato del fichero (en este caso la cadena “WAVE”).
4
•
Descripción del formato de audio. Está formado a su vez por:
- El identificador en código ASCII “fmt “
- El campo longitud del formato de audio (a partir de esa posición). En
concreto será de 16 para codificación PCM y de 20 para IMA ADPCM.
- Formato de audio. Indica cómo se encuentran representadas las muestras
de audio en los datos. Puede ser 0x01 para PCM o 0x11 para IMA
ADPCM. Observa que este campo es de sólo dos bytes.
- Número de canales. Uno para mono y dos para estéreo. Por sencillez, en
esta práctica sólo manejaremos ficheros mono.
- Frecuencia de muestreo. En el caso de IMA ADPCM, tan sólo son
válidas las frecuencias de 8000 Hz, 11025 Hz, 22050 Hz y 44100 Hz.
- Tasa de bytes por segundo. Indica el número de bytes de datos que se
deben de leer por segundo para reproducir el audio. A partir de este
valor, el software de reproducción puede hacer las reservas de memoria
oportunas.
- Alineamiento de bloques. Para PCM representa el número de bytes por
muestra (2 con las muestras de 16 bits de la práctica). En IMA ADPCM
indica el tamaño de los bloques de datos en los que se guardan las
muestras (ver más adelante).
- Bits por muestra. En nuestro caso, debe de ser 16 bits para los datos
PCM y 4 bits para los ADPCM.
- Tamaño de parámetros extra. Este campo y el siguiente (de dos bytes
cada uno) sólo aparecen en los ficheros IMA ADPCM. Este campo
indica la longitud de estos datos extra que vamos a añadir a la cabecera
estándar WAV. Debe de ser 2 bytes.
- Cuenta de número de muestras por canal y por bloque. Se calcula como:
(( Alineamiento − (4 * NumeroDeCanales)) * 8
cuenta =
+1
( BitsPorMuestra )( NumeroDeCanales)
En nuestro caso será de 0x1F9.
•
Por último están almacenados los datos, con un identificador previo del campo
de datos (la cadena “data”) y otro campo indicando la longitud en bytes de los
propios datos.
Dentro del campo de datos, en los ficheros de tipo PCM simplemente se encuentra el
conjunto de muestras de 16 bits. Sin embargo, la codificación para IMA ADPCM es un
poco más compleja. En este caso los datos se almacenan utilizando bloques cuyo
tamaño viene indicado por el campo “Alineamiento de bloques” que se encuentra en la
descripción del formato de audio.
En general, los bloques de datos de IMA ADPCM que tratamos (mono con 4
bits/muestra) van a ser de 256 bytes, y van a constar de una cabecera de 4 bytes y un
cuerpo de datos de 252 bytes. En la cabecera se tiene la siguiente información:
- PredictedValue (2 bytes): La primera muestra del bloque. Cuando se
decodifica, éste será el valor que se tomará como referencia, como
muestra anterior a partir de la que empezar con la decodificación.
5
- StepIndex (1 byte): Índice a la tabla de pasos de cuantización (tiene un
valor de entre 0 y 88) que indica el paso de cuantización inicial a emplear
en el bloque.
- Reservado (1 byte): No se usa y normalmente es 0.
Posteriormente, los 252 bytes de datos tendrán el resultado de la codificación de 504
muestras en formato IMA ADPCM.
4. Código fuente
Esta práctica consta sólo de tres ficheros en lenguaje C.
•
•
•
El fichero audio.cpp sirve para obtener los datos del usuario por parámetro (o si
no se indica ningún dato, se asignan valores por defecto) y llama a las rutinas
necesarias para realizar la compresión y descompresión ADPCM.
En FichWav.cpp se encuentra completamente implementadas las funciones de
carga y grabación de datos en ficheros en formato .wav, a partir de la estructura
descrita en el anterior punto.
Por último, ADPCM.cpp implementa los algoritmos de codificación y
decodificación de IMA ADPCM. En concreto la codificación ADPCM se hará
pasando un vector M_PCM con NMuestras a la función
unsigned int ConviertePCMMono16aADPCMMono4
(short *M_PCM, int NMuestras, unsigned char **M_ADPCM);
El vector resultante con la codificación se guardará en *M_ADPCM, y la
función devolverá la longitud de este vector (en bytes).
Para realizar el proceso inverso hay que usar la función
unsigned int ConvierteADPCMMono4aPCMMono16
(unsigned char *M_ADPCM, int longDatos, short **M_PCM)
que devuelve en este caso el número de muestras PCM de 16 bits que se ha
decodificado y se han dejado en *M_PCM.
Además, dentro de ADPCM.cpp podemos destacar la siguiente función en la que
hay que implementar la codificación de una muestra PCM a IMA ADPCM
unsigned char Codifica(signed int pcm16)
5. Trabajo a realizar
El trabajo que debe realizarse en esta práctica es el siguiente:
1) Leerse la memoria, analizar los ficheros fuentes proporcionados y entender
cómo funciona la codificación IMA ADPCM.
2) En esta práctica hay que implementar una única función: Codifica(...) del
fichero ADCPM.cpp. Para implementar esta función podremos seguir los pasos
descritos en el punto anterior (codificación ADPCM). Fíjate que para la
6
codificación hay que usar también la decodificación, ya que el valor diferencial
se obtiene a partir de la decodificación de la muestra previa. Sin embargo, este
proceso se encuentra ya implementado por la función
int DecodificaValor(unsigned int adpcm, int step)
a la que simplemente tenemos que pasar la muestra actual que acabamos de
codificar y el paso de cuantización que hemos empleado, y nos devuelve el valor
decodificado, que podremos asignar a la variable global PredictedValue para
poder usarlo la siguiente vez que codifiquemos otra muestra.
3) Por último, debes de comprobar que la implementación es correcta. Para esto
puedes ejecutar el programa con los parámetros por defecto (por defecto se
comprime el fichero “homerPCM.wav” con muestras PCM y el resultado se deja
en el fichero “homerADPCM.wav”), o tecleando
audio –c –i homerPCM.wav –o homerADPCM.wav
Si todo ha ido bien, se debe de haber generado un fichero con la codificación
IMA ADPCM de las muestras del fichero de entrada, que podrá ser reproducido
con un reproductor de audio adecuado (por ejemplo, el reproductor de windows
media).
Además, el propio programa facilita el PSNR de las muestras de audio
comprimida, que indica el nivel de calidad de la señal comprimida respecto a la
original. En el caso del fichero “homerPCM.wav”, el PSNR debe de ser de 34.72
dB. En caso de no disponer de ningún programa de reproducción de audio, o de
un ordenador con capacidad de reproducción de audio, se puede comprobar que
el PSNR alcanzado en vuestra implementación es coincidente con éste para
validar la implementación realizada.
Además comprueba también que el nivel de compresión alcanzado finalmente es
el esperado.
Aunque la descompresión no hay que implementarla en esta práctica, sino que
ya viene resuelta, si se desea realizar el proceso inverso de recuperación de
muestras PCM se puede teclear
audio –d –i homerADPCM.wav –o homerPCMrec.wav
6. Posibles extensiones de la práctica
Como posible ampliación a partir de la práctica, se propone implementar alguno de los
codificadores de audio vistos en las sesiones de teoría, junto con el correspondiente
descompresor.
Por tanto, se puede implementar un compresor basado en la codificación logarítmica
(como el u-law ó A-law), algunas versiones estándar de ADPCM (G.721, G.722, G.723,
G.726 y G.727), un codificador especifico para voz usando técnicas vo-coding (como
7
LPC, CELP, GSM, etc), o incluso algún codificador destinado a audio de mayor
calidad, como el descrito en el estándar MPEG1 (en su versiones 1, 2 ó 3, siendo esta
última el famoso MP3).
Evidentemente, la complejidad de los compresores de audio mencionados anteriormente
es distinta, y el trabajo recibirá mejor puntuación cuanto mayor dificultad entrañe el
códec seleccionado.
Para realizar las implementaciones se permite (e incluso en algunos casos, como en
MPEG1, es aconsejable) consultar otras implementaciones disponibles, que pueden
servir de referencia, y se pueden encontrar buscando por diversas fuentes en Internet.
Es importante destacar en la memoria de la ampliación cuál es la estructura del
programa, y cómo se ha efectuado la implementación del mismo, indicando el grado de
aportación de otras fuentes. Además, hay que incluir una descripción teórica, que se
relacionará con las distintas partes del programa.
8
Descargar