mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-07-07 23:20:27 -04:00
Compliant XA decompression code added to the FileHandler interface
This commit is contained in:
parent
1a279588f1
commit
8d06606f28
4 changed files with 390 additions and 0 deletions
155
Libraries/FileHandler/xa/read_xa.c
Normal file
155
Libraries/FileHandler/xa/read_xa.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
read_xa.c - Copyright (c) 2011 Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include "read_xa.h"
|
||||
|
||||
#define HINIBBLE(byte) ((byte) >> 4)
|
||||
#define LONIBBLE(byte) ((byte) & 0x0F)
|
||||
|
||||
#ifndef read_int32
|
||||
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
|
||||
#ifndef __inline
|
||||
#define __inline
|
||||
#endif
|
||||
#ifndef __restrict
|
||||
#define __restrict
|
||||
#endif
|
||||
|
||||
unsigned xa_compressed_size(unsigned Frames, unsigned Channels)
|
||||
{
|
||||
/* The required input size is:
|
||||
** Channels * (ceil(n/2) + ceil(n/28))
|
||||
** | a | | b |
|
||||
**
|
||||
** a = The space required for all 2-sample bytes in the XA data for a single channel (Period: 2 frames)
|
||||
** b = The space required for all control bytes in the XA data for a single channel (Period: 28 frames)
|
||||
** (a+b) is multiplied by Channels to produce the final size
|
||||
**
|
||||
** This source package assumes a partial block at the end of the XA data is legal but a partial frame is not.
|
||||
*/
|
||||
|
||||
unsigned SingleChannelData = (((Frames+1)>>1) + (Frames+27)/28);
|
||||
|
||||
if(Frames > 0xFFFFFFFFu-27) return 0;
|
||||
if(0xFFFFFFFFu/SingleChannelData < Channels) return 0;
|
||||
|
||||
return Channels*SingleChannelData;
|
||||
}
|
||||
|
||||
int xa_read_header(xaheader_t * XAHeader, const uint8_t * Buffer, unsigned FileSize)
|
||||
{
|
||||
if(FileSize < 24) return 0;
|
||||
memcpy(&XAHeader->szID, Buffer, 4);
|
||||
XAHeader->dwOutSize = read_uint32(Buffer+4);
|
||||
XAHeader->wFormatTag = read_uint16(Buffer+8);
|
||||
XAHeader->nChannels = read_uint16(Buffer+10);
|
||||
XAHeader->nSamplesPerSec = read_uint32(Buffer+12);
|
||||
XAHeader->nAvgBytesPerSec = read_uint32(Buffer+16);
|
||||
XAHeader->nBlockAlign = read_uint16(Buffer+20);
|
||||
XAHeader->wBitsPerSample = read_uint16(Buffer+22);
|
||||
|
||||
if(XAHeader->szID[0] != 'X' || XAHeader->szID[1] != 'A' || XAHeader->szID[3] != '\0' ||
|
||||
XAHeader->wFormatTag != 1 ||
|
||||
XAHeader->nChannels == 0 || XAHeader->nChannels > 8 ||
|
||||
XAHeader->nSamplesPerSec < 8000 || XAHeader->nSamplesPerSec > 192000 ||
|
||||
!(XAHeader->nSamplesPerSec%8000==0 || XAHeader->nSamplesPerSec%11025==0) ||
|
||||
XAHeader->wBitsPerSample != 16 ||
|
||||
XAHeader->nBlockAlign != XAHeader->nChannels*(XAHeader->wBitsPerSample>>3) ||
|
||||
XAHeader->nAvgBytesPerSec != XAHeader->nSamplesPerSec*XAHeader->nBlockAlign ||
|
||||
XAHeader->dwOutSize%XAHeader->nBlockAlign != 0
|
||||
) return 0;
|
||||
|
||||
XAHeader->Frames = XAHeader->dwOutSize/XAHeader->nBlockAlign;
|
||||
XAHeader->XADataSize = xa_compressed_size(XAHeader->Frames, XAHeader->nChannels);
|
||||
if(FileSize-24 < XAHeader->XADataSize)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__inline int16_t Clip16(int sample)
|
||||
{
|
||||
if(sample>=32767) return 32767;
|
||||
else if(sample<=-32768) return -32768;
|
||||
else return (int16_t) sample;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int PrevSample, CurSample;
|
||||
int divisor; /* residual right-shift value */
|
||||
int c1, c2; /* predictor coefficients */
|
||||
} channel_t;
|
||||
|
||||
const int XATable[] =
|
||||
{
|
||||
0, 240, 460, 392,
|
||||
0, 0, -208, -220,
|
||||
0, 1, 3, 4,
|
||||
7, 8, 10, 11,
|
||||
0, -1, -3, -4
|
||||
};
|
||||
|
||||
int xa_decode(const uint8_t *__restrict InBuffer, uint8_t *__restrict OutBuffer, unsigned Frames, unsigned Channels)
|
||||
{
|
||||
channel_t * Channel = malloc(Channels * sizeof(channel_t));
|
||||
if(!Channel) return 0;
|
||||
memset(Channel, 0x00, Channels * sizeof(channel_t));
|
||||
|
||||
while(Frames){
|
||||
unsigned i;
|
||||
|
||||
for(i=0; i<Channels; i++){
|
||||
unsigned byte = *(InBuffer++);
|
||||
Channel[i].divisor = LONIBBLE(byte)+8;
|
||||
Channel[i].c1 = XATable[HINIBBLE(byte)];
|
||||
Channel[i].c2 = XATable[HINIBBLE(byte)+4];
|
||||
}
|
||||
|
||||
for(i=0; i<14; i++){
|
||||
unsigned j;
|
||||
for(j=0; j<Channels; j++){
|
||||
unsigned byte = *(InBuffer++);
|
||||
int n;
|
||||
for(n=0; n<2; n++){
|
||||
int NewValue = (n == 0) ? HINIBBLE(byte) : LONIBBLE(byte);
|
||||
NewValue = (NewValue << 28) >> Channel[j].divisor;
|
||||
NewValue = (NewValue + Channel[j].CurSample*Channel[j].c1 + Channel[j].PrevSample*Channel[j].c2 + 128) >> 8;
|
||||
Channel[j].PrevSample = Channel[j].CurSample;
|
||||
Channel[j].CurSample = Clip16(NewValue);
|
||||
}
|
||||
*(OutBuffer++) = (Channel[j].PrevSample&0x00FFu)>>(8*0);
|
||||
*(OutBuffer++) = (Channel[j].PrevSample&0xFF00u)>>(8*1);
|
||||
}
|
||||
if(!--Frames) break;
|
||||
|
||||
for(j=0; j<Channels; j++){
|
||||
*(OutBuffer++) = (Channel[j].CurSample&0x00FFu)>>(8*0);
|
||||
*(OutBuffer++) = (Channel[j].CurSample&0xFF00u)>>(8*1);
|
||||
}
|
||||
if(!--Frames) break;
|
||||
}
|
||||
}
|
||||
|
||||
free(Channel);
|
||||
return 1;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue