Opened 6 years ago
Last modified 6 years ago
#6690 open enhancement
Raw Electronic Arts ADPCM support (.XA)
Reported by: | koops | Owned by: | |
---|---|---|---|
Priority: | wish | Component: | avformat |
Version: | git-master | Keywords: | electronicarts |
Cc: | Blocked By: | ||
Blocking: | Reproduced by developer: | no | |
Analyzed by developer: | no |
Description (last modified by )
Summary of the bug:
How to reproduce:
$ ffmpeg -i sound.XA sound.wav sound.XA: Invalid data found when processing input
I would like support for headerless Electronic Arts ADPCM files to be added.
These files are common in some Electronic Arts games, like Harry Potter and the Chamber of Secrets and Brother Bear.
The format is similar to adpcm_ea_r1, but the file is always mono, there is no channels header. ADPCM history is always initialized to [0, 0].
File size is always a multiple of 15, there is no raw sample mode (0xEE).
Sample rate is 22050Hz by default.
Files can be encoded into this format using sx.exe:
> sx -raw -eaxa_blk sample.wav -=sample.XA
I attached a test case, a XA file and the corresponding decoded raw file.
This is decoder code in C# (I release it under CC0):
using System; using System.IO; using System.Text; namespace KoopsAudioDecoder { class Program { static int coeff1, coeff2, shift, adpcmHistory1 = 0, adpcmHistory2 = 0; static readonly int[] EA_XA_TABLE = new int[] { 0, 0, 240, 0, 460, -208, 392, -220, }; static void DecodeSingleFrame(BinaryReader stream, BinaryWriter outbuf) { int frameInfo = stream.ReadByte(); coeff1 = EA_XA_TABLE[((frameInfo >> 4) & 15) * 2]; coeff2 = EA_XA_TABLE[((frameInfo >> 4) & 15) * 2 + 1]; shift = (frameInfo & 15) + 8; for (int i = 0; i < 14; i++) { int sample_byte = stream.ReadByte(); int[] nibbles = { sample_byte >> 4, sample_byte & 15 }; foreach (int nibble in nibbles) { int sample = GetSample(nibble); outbuf.Write(Clamp16(sample)); } } } private static int GetSample(int nibble) { int sample = ((nibble << 28 >> shift) + (coeff1 * adpcmHistory1) + (coeff2 * adpcmHistory2)) >> 8; adpcmHistory2 = adpcmHistory1; adpcmHistory1 = sample; return sample; } static private short Clamp16(int sample) { if (sample > 32767) { return 32767; } if (sample < -32768) { return -32768; } return (short) sample; } static int Main(string[] args) { if (args.Length != 1) { Console.WriteLine("This program takes only one argument, input file"); return 1; } string inputFileName = args[0], outputFileName = Path.ChangeExtension(inputFileName, "raw"); Stream inputFile = File.OpenRead(inputFileName), outputFile = File.OpenWrite(outputFileName); BinaryReader inputFileReader = new BinaryReader(inputFile); BinaryWriter outputFileWriter = new BinaryWriter(outputFile); while (inputFile.Length - inputFile.Position >= 15) { DecodeSingleFrame(inputFileReader, outputFileWriter); } if (inputFile.Length - inputFile.Position > 0) { Console.WriteLine("File has {0} spare bytes.", inputFile.Length - inputFile.Position); } return 0; } } }
Attachments (2)
Change History (15)
comment:1 by , 6 years ago
comment:3 by , 6 years ago
Summary: | Raw Electronic Arts ADPCM support → Raw Electronic Arts ADPCM support (.XA) |
---|
by , 6 years ago
Attachment: | FurElise.XA added |
---|
comment:4 by , 6 years ago
Description: | modified (diff) |
---|---|
Keywords: | electronicarts added |
Priority: | normal → wish |
Status: | new → open |
Version: | unspecified → git-master |
comment:8 by , 6 years ago
I uploaded it to https://streams.videolan.org/upload/. It's the one without "fixed" in description, I accidentally created a stereo sample, while I wanted mono.
comment:9 by , 6 years ago
You can detect this format by file size being a multiple of 15 and 0th, 15th, 30th and so on bytes being less than 0x40.
comment:12 by , 6 years ago
Description: | modified (diff) |
---|
The stereo file unfortunately never appeared, please attach it here.
comment:13 by , 6 years ago
The stereo file is two mono files going after each other, not an interleaved file. You can only keep mono support if you like.
comment:15 by , 6 years ago
It seems to me you are the right person to do it, given you already implemented a decoder.
Test case files are uploaded to https://streams.videolan.org/upload/.