XA Format Specs

Audio and Music (Sound Processing Unit) based area of development, including VAB, XA, etc
Post Reply
TubeBar
What is PSXDEV?
What is PSXDEV?
Posts: 3
Joined: Nov 10, 2013

XA Format Specs

Post by TubeBar » November 10th, 2013, 11:23 pm

I am looking for technical docs on the XA Container File?

User avatar
Shadow
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2670
Joined: Dec 31, 2012
PlayStation Model: H2000/5502
Discord: Shadow^PSXDEV

Post by Shadow » November 10th, 2013, 11:28 pm

Enjoy!
XA subheader information.txt
XA ADPCM documentation.txt
You do not have the required permissions to view the files attached to this post.
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 2nd, 2014, 9:39 am

Has anyone had success using this documentation? I'm writing an app to convert XA files just for kicks (I know there are some out there but they don't work on win7) and everything seems to be legit until it comes to converting ADPCM to PCM. It looks like the documentation is wrong, since the pseudocode has some errors in it. Basically I tried using the method ADPCMtoPCM provided and it turned all of my soundData to zeroes.

So in attempt to making my own, I was confused on the instructions. I think it has some things backwards or unexplained. This line is confusing to me:
"Shifting is done to the right, so a nibble of 0xF is first extended to a
word: 0xF00, then (arithmetically) shifted to the right, e.g. if range=11, the
result would be 0xFFEE."

So first it's shifted left 8 bits to turn it into a word and then it states to shift to the right. From their example, I cannot find any way that 0xF00 turns into 0xFFEE. In fact, that would be shifting left instead of right since the number increased...right? Am I losing my mind or missing something obvious?

Thanks so much for any help in advance. I'm having fun debugging playstation logic/files/games/etc :) Please help me continue the journey!

*Edit: fixed grammar and typos

User avatar
nocash
Verified
PSX Aficionado
PSX Aficionado
Posts: 534
Joined: Nov 12, 2012
Contact:

Post by nocash » December 3rd, 2014, 8:17 pm

Mind that the nibbles are signed, ie. "F" means "-1".
The 4bit nibbles are left-shifted by 12, to expand them to 16bits (this should give F000, not F00).
And then right shifted (arithmetically = with the sign bit shifted into the upper bits) (with shift amount 11, that would give FFFE, not FFEE).
Here's my own doc on CD-XA, http://problemkaputt.de/psx-spx.htm#cdr ... ompression don't know if it's of any use, but (I hope) it can't be worse than the description that you are currently using).

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 5th, 2014, 5:42 am

Thank you so much! With your help I was able to read and play XA audio. I'll use your document since it explains it better :)

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 10th, 2014, 8:44 am

Hi. Guess I celebrated too early on the XA audio. Are you willing to double check my work? I understand if you're too busy or do not want to so don't hesitate to say no.

I know I'm close. I hear a voice but it's mixed with some static. I can tell the wav has some +32.768 or - 32,768 areas that shouldn't be there if I compare what the wav sound looks like compared to the right one in Audacity.

I changed my code to act like yours so it might be easy for you to spot what I did wrong :) it is in C# if you can understand it.

Code: Select all

 
            bw.Write(Encoding.Default.GetBytes("data"));
            bw.Write(size);

            short dstLeft = 0, oldLeft = 0, olderLeft = 0, dstRight = 1, oldRight = 0, olderRight = 0;

            foreach (var sg in c.SoundGroups)
            {
                for (byte b = 0; b < 4; b++)
                {
                    DecodeBlock(sg.AudioBytes, sg.SoundParameters, b, 1, dstLeft, ref oldLeft, ref olderLeft);
                    DecodeBlock(sg.AudioBytes, sg.SoundParameters, b, 0, dstRight, ref oldRight, ref olderRight);

                    for (byte d = 0; d < decoded.Length; d++)
                        bw.Write(decoded[d]);
                }
            }

Code: Select all

private void DecodeBlock(byte[] samples, byte[] parameters, byte block, byte nibble, short dst, ref short old, ref short older)
        {
            byte shift = (byte)(12 - (parameters[4+block*2+nibble] & 0xF));
            byte filter = (byte)(parameters[4+block*2+nibble] & 0x30 >> 4);

            short f0 = pos_adpcm_table[filter];
            short f1 = neg_adpcm_table[filter];

            for(int d = 0; d < 28; d++)
            {
                sbyte t = Signed4bit((byte)((samples[block + d * 4] >> (nibble * 4)) & 0xF));
                short s = (short)((t << shift) + ((old * f0 + older * f1 + 32) / 64));
                s = MinMax(s, -0x8000, 0x7fff);
                decoded[dst] = s;
                dst += 2;
                older = old;
                old = s;
            }
        }

User avatar
nocash
Verified
PSX Aficionado
PSX Aficionado
Posts: 534
Joined: Nov 12, 2012
Contact:

Post by nocash » December 10th, 2014, 10:55 am

I am more familar with asm. What means "short"? Is that a signed/unsigned variable? And how many bits is it?
If it's only 16bits, then the MinMax function obviously can't adjust values that are exceeding the 16bit range : - )

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 11th, 2014, 1:23 am

Yeah, I wish I could just breakpoint PSX and follow the assembly to figure it out :P

Short is a signed 16 bit, so yeah it already has the min/max, whoops! To test it, I even break pointed the return min or max lines and they are never hit (even after changing the type to be shifted to int32).

Ah yeah, here are the couple other methods in there for reference:

Code: Select all

private int MinMax(int number, int min, int max)
        {
            if (number < min)
                return min;
            if (number > max)
                return max;

            return number;
        }

Code: Select all

private sbyte Signed4bit(sbyte number)
        {
            if ((number & 0x8) == 0x8)
                return (sbyte)((number & 0x7)-8);
            else
                return (sbyte)number;
        }

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 11th, 2014, 6:18 am

So I can see the pattern is there, at least I have the blocks/samples in the right order for both channel. Just doing some shifting or something wrong as it seems I'm getting much higher (or lower) values than I'm suppose to which make the wave forms look very large. Here is a comparison to the same sound I am trying to decode.

Top one is the way it should look, and the bottom one is what I am outputting.

Image

User avatar
meth962
Interested PSXDEV User
Interested PSXDEV User
Posts: 8
Joined: Sep 11, 2014
I am a: Bucket List Enthusiast
Motto: Masakatsu agatsu
Location: USA

Post by meth962 » December 12th, 2014, 9:30 am

Got it folks! It was the Filter.........bad parenthesis!

Error:
sbyte filter = (sbyte)(parameters[4+block*2+nibble] & 0x30 >> 4);

Correction:
sbyte filter = (sbyte)((parameters[4+block*2+nibble] & 0x30) >> 4);

Simple order of operations whoops! Thank you for your support, Shadow and NoCash!

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests