ADX es un formato de compresión y almacenamiento de audio patentado con pérdidas desarrollado por CRI Middleware específicamente para su uso en videojuegos ; se deriva de ADPCM . Su característica más notable es una función de bucle que ha demostrado ser útil para los sonidos de fondo en varios juegos que han adoptado el formato, incluidos muchos juegos para Sega Dreamcast , así como algunos juegos de PlayStation 2 , GameCube y Wii . Uno de los primeros juegos en usar ADX fue Burning Rangers , en Sega Saturn . En particular, la serie Sonic the Hedgehogdesde la generación Dreamcast hasta al menos Shadow the Hedgehog han utilizado este formato para grabaciones de sonido y voz.
![]() | |
Desarrollador (es) | Middleware de CRI |
---|---|
Plataforma | Multiplataforma |
Tipo | Códec / formato de archivo |
Licencia | Propiedad |
Sitio web | Middleware de CRI |
Además de la codificación ADPCM principal, el kit de herramientas ADX también incluye un formato hermano, AHX, que utiliza una variante de audio MPEG-2 diseñado específicamente para grabaciones de voz y un archivo de empaquetado, AFS, para agrupar múltiples pistas ADX y AHX en una sola archivo contenedor.
La versión 2 del formato (ADX2) usa la extensión HCA y HCA-MX, que generalmente se incluyen en un archivo contenedor con las extensiones ACB y AWB. La extensión AWB no debe confundirse con el formato de audio con la misma extensión y contiene principalmente los datos binarios de los archivos HCA.
Visión general
ADX es un formato de audio comprimido pero a diferencia de MP3 y formatos similares, no aplica un modelo psicoacústico al sonido para reducir su complejidad. En cambio, el modelo ADPCM almacena muestras registrando el error relativo a una función de predicción, lo que significa que una mayor parte de la señal original sobrevive al proceso de codificación; como tal, la compresión ADPCM cambia la precisión de la representación por el tamaño mediante el uso de tamaños de muestra relativamente pequeños, generalmente 4 bits. La tolerancia del sistema auditivo humano al ruido que esto causa hace que la pérdida de precisión sea apenas perceptible.
Al igual que otros formatos de codificación, ADX admite múltiples frecuencias de muestreo, como 22050 Hz , 44100 Hz, 48000 Hz, etc., sin embargo, la profundidad de la muestra de salida está bloqueada en 16 bits, generalmente debido a la falta de precisión ya mencionada. Admite varios canales, pero parece haber una limitación implícita de audio estéreo (2 canales), aunque el formato de archivo en sí puede representar hasta 255 canales. La única característica particularmente distintiva que distingue a ADX de alternativas como IMA ADPCM (además de tener una función de predicción diferente) es la funcionalidad de bucle integrado, esto permite que un reproductor de audio salte opcionalmente hacia atrás después de alcanzar un único punto especificado en la pista para crear una bucle coherente; hipotéticamente, esta funcionalidad también podría usarse para saltar hacia adelante, pero eso sería redundante ya que el audio podría simplemente recortarse con un programa de edición.
Para la reproducción, hay algunos complementos para WinAmp y una herramienta de conversión a onda (consulte la sección de referencias). El programa / biblioteca de código abierto FFmpeg también tiene implementado soporte ADX, sin embargo, su decodificador está codificado de forma rígida, por lo que solo puede decodificar correctamente ADX de 44100 Hz.
Descripción técnica
La especificación ADX no está disponible gratuitamente, sin embargo, los elementos más importantes de la estructura han sido sometidos a ingeniería inversa y documentados en varios lugares de la web. La información aquí puede estar incompleta, pero debería ser suficiente para crear un códec o transcodificador que funcione .
Como nota al margen, los archivos AFS en los que a veces se empaquetan los ADX son una variante simple de un tarball que usa índices numéricos para identificar el contenido en lugar de los nombres. El código fuente de un extractor se puede encontrar en el archivo ADX en. [1]
Encabezado de archivo
El formato de disco ADX se define en big-endian . Las secciones identificadas del encabezado principal se describen a continuación:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | mi | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0 | 0x80 | 0x00 | Compensación de derechos de autor | Tipo de codificación | Tamaño de bloque | Bitdepth de muestra | Recuento de canales | Frecuencia de muestreo | Muestras totales | |||||||
0x10 | Frecuencia de paso alto | Versión | Banderas | Muestras de alineación de bucle (v3) | Bucle habilitado (v3) | Bucle habilitado (v3) | Índice de muestra de inicio de bucle (v3) | |||||||||
0x20 | Índice de bytes de inicio de bucle (v3) | Bucle habilitado (v4) Índice de muestra de final de bucle (v3) | Índice de muestra de inicio de bucle (v4) Índice de bytes de fin de bucle (v3) | Índice de bytes de inicio de bucle (v4) | ||||||||||||
0x30 | Índice de muestra de final de bucle (v4) | Índice de bytes de fin de bucle (v4) | Cero o más bytes de espacio vacío | |||||||||||||
??? | [CopyrightOffset - 2] Cadena ASCII (sin terminar): "(c) CRI" | |||||||||||||||
... | [CopyrightOffset + 4] Los datos de audio comienzan aquí |
Los campos etiquetados como "Desconocido" contienen datos desconocidos o aparentemente solo están reservados (es decir, están llenos de bytes nulos). Los campos etiquetados con 'v3' o 'v4', pero no ambos, se consideran "Desconocidos" en la versión con la que no están marcados. Este encabezado puede ser tan corto como 20 bytes (0x14), según lo determinado por el desplazamiento de derechos de autor, que elimina implícitamente el soporte para un bucle ya que esos campos no están presentes.
El campo "Tipo de codificación" debe contener uno de los siguientes:
- 0x02 para ADX con coeficientes de predicción preestablecidos
- 0x03 para ADX estándar
- 0x04 para ADX con escala exponencial
- 0x10 o 0x11 para AHX
El campo "Versión" debe contener uno de los siguientes:
- 0x03 para ADX 'versión 3'
- 0x04 para ADX 'versión 4'
- 0x05 para una variante de ADX 4 sin soporte de bucle
Al decodificar audio AHX, el campo de versión no parece tener ningún significado y se puede ignorar con seguridad.
Los archivos con el tipo de codificación '2' usan 4 posibles conjuntos de coeficientes de predicción que se enumeran a continuación:
Coeficiente 0 | Coeficiente 1 | |
---|---|---|
Establecer 0 | 0x0000 | 0x0000 |
Serie 1 | 0x0F00 | 0x0000 |
Conjunto 2 | 0x1CC0 | 0xF300 |
Conjunto 3 | 0x1880 | 0xF240 |
Formato de muestra
Los datos de audio codificados con ADX se dividen en una serie de 'bloques', cada uno de los cuales contiene datos para un solo canal. A continuación, los bloques se disponen en "tramas" que consisten en un bloque de cada canal en orden ascendente. Por ejemplo, en un flujo estéreo (2 canales), esto consistiría en la trama 1: bloque de canal izquierdo, bloque de canal derecho; Cuadro 2: izquierda, derecha; etc. Los bloques suelen tener siempre un tamaño de 18 bytes y contienen muestras de 4 bits, aunque técnicamente son posibles otros tamaños, un ejemplo de un bloque de este tipo se ve así:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | dieciséis | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Predictor / Escala | 32 muestras de 4 bits |
Los primeros 3 bits del entero 'Predictor / Escala' contienen el índice del predictor. La escala está contenida en los 13 bits restantes.
El índice de predicción es un número entero de 3 bits que especifica qué conjunto de coeficientes de predicción se debe utilizar para decodificar ese bloque. Esto solo se usa en archivos con el tipo de codificación '2'.
La escala es un entero sin signo de 13 bits ( big-endian como el encabezado) que es esencialmente la amplificación de todas las muestras en ese bloque. Cada muestra del bloque debe decodificarse en orden de flujo de bits, es decir, primero el bit más significativo. Por ejemplo, cuando el tamaño de la muestra es de 4 bits:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
Primera muestra | Segunda muestra |
Las muestras en sí no están al revés, por lo que no es necesario manipularlas una vez que se extraen. Cada muestra está firmada, por lo que para este ejemplo, el valor puede oscilar entre -8 y +7 (que se multiplicará por la escala durante la decodificación). Aparte, aunque cualquier profundidad de bits entre 1 y 255 es posible gracias al encabezado. Es poco probable que se produzcan muestras de un bit, ya que solo pueden representar los valores {0, 1}, {-1, 0} o {-1, 1}, todos los cuales no son particularmente útiles para codificar canciones, si si ocurriera, no está claro cuál de las tres posibilidades es la interpretación correcta.
Decodificación ADX
Esta sección explica cómo decodificar ADX 'versión 3' o 'versión 4' cuando "Tipo de codificación" es "ADX estándar" ( 0x03 ). También se puede construir un codificador simplemente volteando el código para que se ejecute en reversa. Todos los ejemplos de código de esta sección están escritos con C99 .
Antes de que un ADX "estándar" pueda codificarse o decodificarse, se debe calcular el conjunto de coeficientes de predicción. Por lo general, esto se hace mejor en la etapa de inicialización:
#define M_PI acos (-1.0) double a , b , c ; un = sqrt ( 2,0 ) - cos ( 2,0 * M_PI * (( doble ) adx_header -> highpass_frequency / adx_header -> SAMPLE_RATE )); b = raíz cuadrada ( 2.0 ) - 1.0 ; c = ( a - raíz cuadrada (( a + b ) * ( a - b ))) / b ; // (a + b) * (ab) = a * ab * b, sin embargo, la fórmula más simple pierde precisión en coma flotante // coeficiente doble [2]; coeficiente [ 0 ] = c * 2,0 ; coeficiente [ 1 ] = - ( c * c );
Este código calcula los coeficientes de predicción para predecir la muestra actual a partir de las 2 muestras anteriores. Estos coeficientes también forman un filtro de paso alto de respuesta de impulso finito de primer orden . [ aclaración necesaria ]
Una vez que conocemos los coeficientes de decodificación, podemos comenzar a decodificar el flujo:
static int32_t * past_samples ; // Muestras previamente decodificadas de cada canal, puesta a cero al inicio (tamaño = 2 * channel_count) static uint_fast32_t sample_index = 0 ; // sample_index es el índice del conjunto de muestras que debe decodificarse a continuación estático ADX_header * adx_header ; // el búfer es donde se colocarán las muestras decodificadas // samples_needed indica cuántos 'conjuntos' de muestras (una muestra de cada canal) deben decodificarse para llenar el búfer // looping_enabled es una bandera booleana para controlar el uso de in loop // Devuelve el número de 'conjuntos' de muestras en el búfer que no se pudieron llenar (EOS) unsigned decode_adx_standard ( int16_t * buffer , unsigned samples_needed , bool looping_enabled ) { unsigned const samples_per_block = ( adx_header -> block_size - 2 ) * 8 / adx_header -> sample_bitdepth ; int16_t scale [ adx_header -> channel_count ]; if ( looping_enabled && ! adx_header -> loop_enabled ) looping_enabled = false ; // Repite el ciclo hasta que se decodifique el número solicitado de muestras o se alcance el final del archivo while ( samples_needed > 0 && sample_index < adx_header -> total_samples ) { // Calcula el número de muestras que quedan por decodificar en el bloque actual unsigned sample_offset = sample_index % samples_per_block ; unsigned samples_can_get = samples_per_block - sample_offset ; // Sujete las muestras que podemos obtener durante esta ejecución si no caben en el búfer if ( samples_can_get > samples_needed ) samples_can_get = samples_needed ; // Clamp el número de muestras a ser adquirida si la corriente no es lo suficientemente largo o el gatillo bucle está cerca si ( looping_enabled && sample_index + samples_can_get > adx_header -> loop_end_index ) samples_can_get = adx_header -> loop_end_index - sample_index ; otra cosa si ( sample_index + samples_can_get > adx_header -> total_samples ) samples_can_get = adx_header -> total_samples - sample_index ; // Calcular la dirección de bit del inicio de la trama que reside en sample_index y constancia de que la ubicación no firmada largo started_at = ( adx_header -> copyright_offset + 4 + \ sample_index / samples_per_block * adx_header -> block_size * adx_header -> channel_count ) * 8 ; // Lea los valores de escala desde el inicio de cada bloque en este marco para ( unsigned i = 0 ; i < adx_header -> channel_count ; ++ i ) { bitstream_seek ( started_at + adx_header -> block_size * i * 8 ); escala [ i ] = ntohs ( bitstream_read ( 16 ) ); } // Pre-calcular el valor de parada para sample_offset unsigned sample_endoffset = sample_offset + samples_can_get ; // Guarde la dirección de flujo de bits de la primera muestra inmediatamente después de la escala en el primer bloque de la trama starts_at + = 16 ; while ( sample_offset < sample_endoffset ) { for ( unsigned i = 0 ; i < adx_header -> channel_count ; ++ i ) { // Predecir la siguiente muestra double sample_prediction = coefficient [ 0 ] * past_samples [ i * 2 + 0 ] + coeficiente [ 1 ] * pasadas_muestras [ i * 2 + 1 ]; // Busque el desplazamiento de muestra, lea y firme extiéndalo a un entero de 32 bits // La implementación de la extensión del signo se deja como un ejercicio para el lector // La extensión del signo también deberá incluir un ajuste endian si hay más de 8 bits bitstream_seek ( iniciado_en + adx_header -> sample_bitdepth * sample_offset + \ adx_header -> block_size * 8 * i ); int_fast32_t sample_error = bitstream_read ( adx_header -> sample_bitdepth ); sample_error = sign_extend ( sample_error , adx_header -> sample_bitdepth ); // Escale el valor de corrección de errores sample_error * = scale [ i ]; // Calcula la muestra combinando la predicción con la corrección de errores int_fast32_t sample = sample_error + ( int_fast32_t ) sample_prediction ; // Actualiza las muestras pasadas con la muestra más reciente past_samples [ i * 2 + 1 ] = past_samples [ i * 2 + 0 ]; past_samples [ i * 2 + 0 ] = muestra ; // Fije la muestra decodificada al rango válido para un entero de 16 bits if ( sample > 32767 ) sample = 32767 ; else if ( muestra < -32768 ) muestra = -32768 ; // Guarde la muestra en el búfer y luego avance un lugar * búfer ++ = muestra ; } ++ sample_offset ; // Hemos decodificado una muestra de cada bloque, avanzamos el desplazamiento del bloque en 1 ++ sample_index ; // Esto también significa que estamos una muestra más adelante en la secuencia - samples_needed ; // Y entonces hay un conjunto menos de muestras que necesitan ser decodificadas } // Verificamos si alcanzamos el marcador de finalización del ciclo, si lo hicimos, debemos saltar al inicio del ciclo if ( looping_enabled && sample_index == adx_header -> loop_end_index ) sample_index = adx_header -> loop_start_index ; } return samples_needed ; }
La mayoría del código anterior debe ser lo suficientemente sencillo para cualquier persona versada en C . El ADX_header
puntero " " se refiere a los datos extraídos del encabezado como se describió anteriormente, se supone que ya se han convertido al host Endian. Esta implementación no pretende ser óptima y se han ignorado las preocupaciones externas, como el método específico para la extensión del signo y el método para adquirir un flujo de bits de un archivo o fuente de red. Una vez que se complete, habrá conjuntos de samples_needed (si es estéreo, habrá pares, por ejemplo) de muestras en el búfer de salida . Las muestras decodificadas estarán en formato PCM intercalado estándar de host-endian , es decir, 16 bits izquierdo, 16 bits derecho, izquierdo, derecho, etc. Finalmente, si el bucle no está habilitado o no es compatible, la función devolverá el número de espacios de muestra que no se utilizaron en el búfer. La persona que llama puede probar si este valor no es cero para detectar el final de la transmisión y colocar o escribir silencio en los espacios no utilizados si es necesario.
Cifrado
ADX admite un esquema de encriptación simple que XORs valores de un generador de números pseudoaleatorios congruentes lineales con los valores de escala de bloque. Este método es computacionalmente económico de descifrar (de acuerdo con la decodificación en tiempo real de ADX) pero deja inutilizables los archivos cifrados. El cifrado está activo cuando el valor de "Banderas" en el encabezado es 0x08 . Como XOR es simétrico, se utiliza el mismo método para descifrar que para cifrar. La clave de cifrado es un conjunto de tres valores de 16 bits: el multiplicador, el incremento y los valores iniciales para el generador congruente lineal (el módulo es 0x8000 para mantener los valores en el rango de 15 bits de escalas de bloque válidas). Normalmente, todos los archivos ADX de un solo juego utilizarán la misma clave.
El método de cifrado es vulnerable a los ataques de texto sin formato conocidos . Si se conoce una versión sin cifrar del mismo audio, el flujo de números aleatorios se puede recuperar fácilmente y, a partir de él, se pueden determinar los parámetros clave, haciendo que cada ADX cifrado con esa misma clave sea descifrable. El método de cifrado intenta hacer esto más difícil al no cifrar los bloques silenciosos (con todos los nybbles de muestra iguales a 0), ya que se sabe que su escala es 0.
Incluso si el ADX cifrado es la única muestra disponible, es posible determinar una clave asumiendo que los valores de escala del ADX descifrado deben estar dentro de un "rango bajo". Sin embargo, este método no encuentra necesariamente la clave utilizada para cifrar el archivo. Si bien siempre puede determinar las claves que producen una salida aparentemente correcta, es posible que existan errores sin ser detectados. Esto se debe a la distribución cada vez más aleatoria de los bits más bajos de los valores de escala, que resulta imposible de separar de la aleatoriedad añadida por el cifrado.
Decodificación AHX
Como se señaló anteriormente, AHX es solo una implementación de audio MPEG2 y el método de decodificación es básicamente el mismo que el estándar, es posible simplemente demultiplicar el flujo del contenedor ADX y alimentarlo a través de un decodificador de audio MPEG estándar como mpg123 . La "frecuencia de muestreo" y las "muestras totales" del encabezado ADX suelen ser correctas si un decodificador las necesita (por lo que deben establecerse mediante implementaciones de codificador / muxer), pero la mayoría de los otros campos, como "tamaño de bloque" y "profundidad de bits de muestra", por lo general, ser cero; como se indicó anteriormente, la funcionalidad de bucle tampoco está disponible.
Referencias
- ^ "Título desconocido" . Archivado desde el original el 18 de marzo de 2009.
- Página del producto ADX en el sitio web de CRI Middleware
- Códec vgmstream WinAMP con fuente (compatible con ADX)
- Utilidades Dreamcast, incluidos convertidores ADX con fuente ((2009-10-24)
- Descripción de CRI ADX de multimedia.cx Wiki
- Descripción técnica de ADX en vgmstream Wiki