psx.wiki
Log in
Main page
Hardware
Hardware tests
System software
SDKs
File formats
Games
Tools
History
All pages
page
view source
history
View source for SPU ADPCM
← SPU ADPCM
You do not have permission to edit this page.
Log in
to edit.
--- title: SPU ADPCM type: format summary: 16-byte compressed sample blocks played by the SPU voices. category: Hardware category: File formats --- ## Overview The [SPU](/hardware/spu/) plays only ADPCM sample data. Sony calls the format VAG: compressed audio arranged in 16-byte blocks, about 3.5 to 1 smaller than the 16-bit source, and Sony treats the compression method as proprietary.[^ovr163] psx-spx describes it as an extension of the SNES bit rate reduction (BRR) format that uses 16-byte blocks in place of 9-byte blocks and five filters in place of four.[^spxintro] Uncompressed samples are not supported.[^spxadpcm] A [VAG](/formats/vag/) file adds a 48-byte header to the blocks. The header must be removed before the data is played, and the first block of every VAG is 16 bytes of zero data. Sony calls this the lead-in and explains that it initializes the SPU so that the sample starts without a click.[^ovr163] ## Block Format Each block holds 28 samples in 16 bytes. The first two bytes are the block header and the other fourteen bytes each hold two 4-bit samples. The layout is shown below.[^spxadpcm] Table: ADPCM block | Offset | Contents | | --- | --- | | 00h | Shift and filter | | 01h | Flag bits | | 02h | Samples 1 (low nibble) and 2 (high nibble) | | 03h | Samples 3 and 4 | | 04h to 0Fh | Samples 5 to 28, two per byte | The 28 samples of a 16-byte block therefore take 4.57 bits per sample (16 x 8 / 28), where PCM takes 16 bits. The shift and filter byte is reported to have the same layout as in XA-ADPCM, where bits 0 to 3 hold the shift and the bits above hold the filter.[^spxadpcm][^spxxahdr] ## Flag Bits The flag byte controls looping and the end of the sample.[^spxadpcm] Table: ADPCM flag bits | Bit | Name | Set means | | --- | --- | --- | | 0 | Loop End | Set the ENDX bit and jump to LSAX after this block | | 1 | Loop Repeat | Keep playing at the loop. When clear with bit 0 set, the voice goes to release with the envelope at zero. | | 2 | Loop Start | Copy the current address to LSAX | | 3 to 7 | Unknown | Usually 0 | Bits 0 and 1 together give four codes. Code 0 continues at the next block and code 2 acts the same. Code 3 jumps to the loop address and sets ENDX, and code 1 does the same but also forces release with the envelope at zero.[^spxadpcm] The flags allow the whole sample or only its last blocks to repeat. There is no flag that stops output. A one-shot sample therefore ends in a block with Loop Start and Loop End both set and all samples zero, which repeats forever without sound.[^spxadpcm] Sony's tools add this block to every one-shot VAG and call it the SPU IRQ clear block. It reads "00077777 77777777 77777777 77777777" or "00070000 00000000 00000000 00000000", and looping VAGs do not have it.[^ovr164] The block keeps the voice from running on through the sound buffer and raising stray SPU interrupts. Sony allows the block to be removed when no SPU IRQ function is used. However, SpuGetIRQ(), SpuGetIRQAddr(), SpuSetIRQ(), SpuSetIRQAddr(), SpuSetIRQCallback() and the SpuSt streaming functions all use the SPU IRQ.[^ovr164] ## Decoding The hardware expands each 4-bit sample to 16 bits, shifts it right by the shift value and adds a prediction from the two previous output samples. The filter selects the prediction weights, and the result is clamped to -8000h to +7FFFh.[^spxxadec] The weights are the same as for XA-ADPCM, but the SPU accepts filter 4, which XA does not.[^spxxatab] Table: ADPCM filter coefficients | Filter | Weight of old sample | Weight of older sample | | --- | --- | --- | | 0 | 0 | 0 | | 1 | +60 | 0 | | 2 | +115 | -52 | | 3 | +98 | -55 | | 4 | +122 | -60 | The decoding of one sample is as follows. The weights are in 64ths, so the prediction is divided by 64 with rounding.[^spxxadec] ``` f0 = pos_table[filter] f1 = neg_table[filter] t = signed 4-bit sample s = (t << 12) >> shift s = s + ((old * f0 + older * f1 + 32) / 64) s = clamp(s, -8000h, +7FFFh) older = old old = s ``` ## SPU-ADPCM and XA-ADPCM The PlayStation has two ADPCM formats. The decoder algorithm is the same for both. However, XA-ADPCM is decoded by the CD-ROM controller and goes to the SPU mixer directly. It uses neither the sound buffer nor a voice.[^spxvsxa] The two formats also differ in layout. XA arranges its nibbles in a different order and holds 2 x 28 nibbles per block. It can be mono or stereo, has only two sample rates and has no looping.[^spxvsxa] The [XA audio](/hardware/cd-rom/xa-audio/) page describes the XA side. ## Interpolation Each voice interpolates between samples with a 4-point Gaussian filter. The four most recent samples are weighted by entries of a 512-entry table, and bits 4 to 11 of the pitch counter give the 8-bit index i into it.[^spxgauss] ``` out = (gauss[0FFh - i] * oldest) >> 15 out = out + (gauss[1FFh - i] * older) >> 15 out = out + (gauss[100h + i] * old) >> 15 out = out + (gauss[000h + i] * new) >> 15 ``` In theory each set of four weights sums to 8000h. In practice the sums are 7F7Fh to 7F81h, which keeps the result within range.[^spxgauss] The table is as follows (eight entries per line):[^spxgauss] ``` -001h,-001h,-001h,-001h,-001h,-001h,-001h,-001h ; 000h -001h,-001h,-001h,-001h,-001h,-001h,-001h,-001h 0000h,0000h,0000h,0000h,0000h,0000h,0000h,0001h 0001h,0001h,0001h,0002h,0002h,0002h,0003h,0003h 0003h,0004h,0004h,0005h,0005h,0006h,0007h,0007h 0008h,0009h,0009h,000Ah,000Bh,000Ch,000Dh,000Eh 000Fh,0010h,0011h,0012h,0013h,0015h,0016h,0018h 0019h,001Bh,001Ch,001Eh,0020h,0021h,0023h,0025h 0027h,0029h,002Ch,002Eh,0030h,0033h,0035h,0038h 003Ah,003Dh,0040h,0043h,0046h,0049h,004Dh,0050h 0054h,0057h,005Bh,005Fh,0063h,0067h,006Bh,006Fh 0074h,0078h,007Dh,0082h,0087h,008Ch,0091h,0096h 009Ch,00A1h,00A7h,00ADh,00B3h,00BAh,00C0h,00C7h 00CDh,00D4h,00DBh,00E3h,00EAh,00F2h,00FAh,0101h 010Ah,0112h,011Bh,0123h,012Ch,0135h,013Fh,0148h 0152h,015Ch,0166h,0171h,017Bh,0186h,0191h,019Ch 01A8h,01B4h,01C0h,01CCh,01D9h,01E5h,01F2h,0200h ; 080h 020Dh,021Bh,0229h,0237h,0246h,0255h,0264h,0273h 0283h,0293h,02A3h,02B4h,02C4h,02D6h,02E7h,02F9h 030Bh,031Dh,0330h,0343h,0356h,036Ah,037Eh,0392h 03A7h,03BCh,03D1h,03E7h,03FCh,0413h,042Ah,0441h 0458h,0470h,0488h,04A0h,04B9h,04D2h,04ECh,0506h 0520h,053Bh,0556h,0572h,058Eh,05AAh,05C7h,05E4h 0601h,061Fh,063Eh,065Ch,067Ch,069Bh,06BBh,06DCh 06FDh,071Eh,0740h,0762h,0784h,07A7h,07CBh,07EFh 0813h,0838h,085Dh,0883h,08A9h,08D0h,08F7h,091Eh 0946h,096Fh,0998h,09C1h,09EBh,0A16h,0A40h,0A6Ch 0A98h,0AC4h,0AF1h,0B1Eh,0B4Ch,0B7Ah,0BA9h,0BD8h 0C07h,0C38h,0C68h,0C99h,0CCBh,0CFDh,0D30h,0D63h 0D97h,0DCBh,0E00h,0E35h,0E6Bh,0EA1h,0ED7h,0F0Fh 0F46h,0F7Fh,0FB7h,0FF1h,102Ah,1065h,109Fh,10DBh 1116h,1153h,118Fh,11CDh,120Bh,1249h,1288h,12C7h 1307h,1347h,1388h,13C9h,140Bh,144Dh,1490h,14D4h ; 100h 1517h,155Ch,15A0h,15E6h,162Ch,1672h,16B9h,1700h 1747h,1790h,17D8h,1821h,186Bh,18B5h,1900h,194Bh 1996h,19E2h,1A2Eh,1A7Bh,1AC8h,1B16h,1B64h,1BB3h 1C02h,1C51h,1CA1h,1CF1h,1D42h,1D93h,1DE5h,1E37h 1E89h,1EDCh,1F2Fh,1F82h,1FD6h,202Ah,207Fh,20D4h 2129h,217Fh,21D5h,222Ch,2282h,22DAh,2331h,2389h 23E1h,2439h,2492h,24EBh,2545h,259Eh,25F8h,2653h 26ADh,2708h,2763h,27BEh,281Ah,2876h,28D2h,292Eh 298Bh,29E7h,2A44h,2AA1h,2AFFh,2B5Ch,2BBAh,2C18h 2C76h,2CD4h,2D33h,2D91h,2DF0h,2E4Fh,2EAEh,2F0Dh 2F6Ch,2FCCh,302Bh,308Bh,30EAh,314Ah,31AAh,3209h 3269h,32C9h,3329h,3389h,33E9h,3449h,34A9h,3509h 3569h,35C9h,3629h,3689h,36E8h,3748h,37A8h,3807h 3867h,38C6h,3926h,3985h,39E4h,3A43h,3AA2h,3B00h 3B5Fh,3BBDh,3C1Bh,3C79h,3CD7h,3D35h,3D92h,3DEFh 3E4Ch,3EA9h,3F05h,3F62h,3FBDh,4019h,4074h,40D0h ; 180h 412Ah,4185h,41DFh,4239h,4292h,42EBh,4344h,439Ch 43F4h,444Ch,44A3h,44FAh,4550h,45A6h,45FCh,4651h 46A6h,46FAh,474Eh,47A1h,47F4h,4846h,4898h,48E9h 493Ah,498Ah,49D9h,4A29h,4A77h,4AC5h,4B13h,4B5Fh 4BACh,4BF7h,4C42h,4C8Dh,4CD7h,4D20h,4D68h,4DB0h 4DF7h,4E3Eh,4E84h,4EC9h,4F0Eh,4F52h,4F95h,4FD7h 5019h,505Ah,509Ah,50DAh,5118h,5156h,5194h,51D0h 520Ch,5247h,5281h,52BAh,52F3h,532Ah,5361h,5397h 53CCh,5401h,5434h,5467h,5499h,54CAh,54FAh,5529h 5558h,5585h,55B2h,55DEh,5609h,5632h,565Bh,5684h 56ABh,56D1h,56F6h,571Bh,573Eh,5761h,5782h,57A3h 57C3h,57E2h,57FFh,581Ch,5838h,5853h,586Dh,5886h 589Eh,58B5h,58CBh,58E0h,58F4h,5907h,5919h,592Ah 593Ah,5949h,5958h,5965h,5971h,597Ch,5986h,598Fh 5997h,599Eh,59A4h,59A9h,59ADh,59B0h,59B2h,59B3h ``` ## References [^ovr163]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-3. [^ovr164]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-4. [^spxintro]: psx-spx. Sound Processing Unit (SPU). https://psx-spx.consoledev.net/soundprocessingunitspu/ [^spxadpcm]: psx-spx. Sound Processing Unit (SPU), SPU ADPCM Samples. https://psx-spx.consoledev.net/soundprocessingunitspu/ [^spxvsxa]: psx-spx. Sound Processing Unit (SPU), SPU-ADPCM vs XA-ADPCM. https://psx-spx.consoledev.net/soundprocessingunitspu/ [^spxgauss]: psx-spx. Sound Processing Unit (SPU), 4-Point Gaussian Interpolation. https://psx-spx.consoledev.net/soundprocessingunitspu/ [^spxxadec]: psx-spx. CDROM Format, CDROM XA Audio ADPCM Compression, decode_28_nibbles. https://psx-spx.consoledev.net/cdromformat/ [^spxxahdr]: psx-spx. CDROM Format, CDROM XA Audio ADPCM Compression, XA-ADPCM Header Bytes. https://psx-spx.consoledev.net/cdromformat/ [^spxxatab]: psx-spx. CDROM Format, CDROM XA Audio ADPCM Compression, Pos/neg Tables. https://psx-spx.consoledev.net/cdromformat/