adding cd-xa support (preliminary)

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@97 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
fastelbja 2008-05-10 19:59:29 +00:00
parent f39503701a
commit 9e70f0ec5c
9 changed files with 262 additions and 2 deletions

65
src/coding/xa_decoder.c Normal file
View File

@ -0,0 +1,65 @@
#include "coding.h"
#include "../util.h"
const int SH = 4;
const int SHC = 10;
double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125};
double K1[4] = { 0.0, 0.0, -0.8125,-0.859375};
int IK0(int fid)
{ return ((int)((-K0[fid]) * (1 << SHC))); }
int IK1(int fid)
{ return ((int)((-K1[fid]) * (1 << SHC))); }
int CLAMP(int value, int Minim, int Maxim)
{
if (value < Minim) value = Minim;
if (value > Maxim) value = Maxim;
return value;
}
static uint8_t get_high_nibble=1;
void decode_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int predict_nr, shift_factor, sample;
int32_t hist1=stream->adpcm_history1_32;
int32_t hist2=stream->adpcm_history2_32;
int HeadTable[8]={0,2,8,10};
short scale;
int i;
int32_t sample_count;
int framesin = first_sample / 28;
get_high_nibble=!get_high_nibble;
predict_nr = read_8bit(stream->offset+HeadTable[framesin]+get_high_nibble,stream->streamfile) >> 4;
shift_factor = read_8bit(stream->offset+HeadTable[framesin]+get_high_nibble,stream->streamfile) & 0xf;
first_sample = first_sample % 28;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile);
scale = ((get_high_nibble ?
sample_byte >> 4 :
sample_byte & 0x0f)<<12);
sample = (short)(scale & 0xf000) >> shift_factor;
sample <<= SH;
sample -= (IK0(predict_nr) * hist1 + (IK1(predict_nr) * hist2)) >> SHC;
hist2=hist1;
hist1=sample;
sample = CLAMP(sample, -32768 << SH, 32767 << SH);
outbuf[sample_count] = (short)(sample >> SH);
}
stream->adpcm_history1_32=hist1;
stream->adpcm_history2_32=hist2;
}

View File

@ -48,6 +48,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
else
vgmstream->current_block_offset=-1;
break;
case layout_xa_blocked:
xa_block_update(vgmstream->next_block_offset,vgmstream);
break;
default:
break;
}

47
src/layout/xa_blocked.c Normal file
View File

@ -0,0 +1,47 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
uint8_t currentChannel=0;
uint8_t subAudio=0;
// i used interleave_block_size to check sector read length
if(vgmstream->samples_into_block!=0)
// don't change this variable in the init process
vgmstream->interleave_block_size+=128;
// We get to the end of a sector ?
if(vgmstream->interleave_block_size==(18*128)) {
vgmstream->interleave_block_size=0;
// 0x30 of unused bytes/sector :(
block_offset+=0x30;
begin:
// Search for selected channel & valid audio
currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile);
subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile);
// audio is coded as 0x64
if((subAudio!=0x64) || (currentChannel!=vgmstream->xa_channel)) {
// go to next sector
block_offset+=2352;
if(currentChannel!=-1) goto begin;
}
}
vgmstream->current_block_offset = block_offset;
// Quid : how to stop the current channel ???
// i set up 0 to current_block_size to make vgmstream not playing bad samples
// another way to do it ???
// (as the number of samples can be false in cd-xa due to multi-channels)
vgmstream->current_block_size = (currentChannel==-1?0:112);
vgmstream->next_block_offset = vgmstream->current_block_offset+128;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset;
}
}

View File

@ -250,6 +250,10 @@
RelativePath=".\meta\ps2_npsf.c"
>
</File>
<File
RelativePath=".\meta\psx_cdxa.c"
>
</File>
<File
RelativePath=".\meta\rs03.c"
>
@ -314,6 +318,10 @@
RelativePath=".\coding\psx_decoder.c"
>
</File>
<File
RelativePath=".\coding\xa_decoder.c"
>
</File>
</Filter>
</Filter>
<Filter
@ -350,6 +358,10 @@
RelativePath=".\layout\nolayout.c"
>
</File>
<File
RelativePath=".\layout\xa_blocked.c"
>
</File>
</Filter>
</Filter>
</Files>

View File

@ -35,4 +35,6 @@ VGMSTREAM * init_vgmstream_rsf(const char * const filename);
VGMSTREAM * init_vgmstream_rwsd(const char * const filename);
VGMSTREAM * init_vgmstream_cdxa(const char * const filename);
#endif

106
src/meta/psx_cdxa.c Normal file
View File

@ -0,0 +1,106 @@
#include "meta.h"
#include "../util.h"
/* Sony PSX CD-XA */
/* No looped file ! */
uint8_t AUDIO_CODING_GET_STEREO(uint8_t value) {
return (uint8_t)(value & 3);
}
uint8_t AUDIO_CODING_GET_FREQ(uint8_t value) {
return (uint8_t)((value >> 2) & 3);
}
VGMSTREAM * init_vgmstream_cdxa(const char * const filename) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * infile = NULL;
int channel_count;
uint8_t bCoding;
int i;
/* check extension, case insensitive */
if (strcasecmp("xa",filename_extension(filename))) goto fail;
/* try to open the file for header reading */
infile = open_streamfile(filename);
if (!infile) goto fail;
/* check RIFF Header */
if (!((read_32bitBE(0x00,infile) == 0x52494646) &&
(read_32bitBE(0x08,infile) == 0x43445841) &&
(read_32bitBE(0x0C,infile) == 0x666D7420)))
goto fail;
bCoding = read_8bit(0x3F,infile);
switch (AUDIO_CODING_GET_STEREO(bCoding)) {
case 0: channel_count = 1; break;
case 1: channel_count = 2; break;
default: channel_count = 0; break;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,0);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
switch (AUDIO_CODING_GET_FREQ(bCoding)) {
case 0: vgmstream->sample_rate = 37800; break;
case 1: vgmstream->sample_rate = 19800; break;
default: vgmstream->sample_rate = 0; break;
}
/* Check for Compression Scheme */
vgmstream->coding_type = coding_XA;
vgmstream->num_samples = (int32_t)((((get_streamfile_size(infile) - 0x3C)/2352)*0x1F80)/(2*channel_count));
vgmstream->layout_type = layout_xa_blocked;
vgmstream->meta_type = meta_PSX_XA;
close_streamfile(infile); infile=NULL;
/* open the file for reading by each channel */
{
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = open_streamfile_buffer(filename,0x8000);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}
xa_block_update(init_xa_channel(0),vgmstream);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (infile) close_streamfile(infile);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
// in extension, we can use this fonction to set the channel
// we want to listen to ...
off_t init_xa_channel(int channel,VGMSTREAM* vgmstream) {
off_t block_offset=0x44;
uint8_t currentChannel;
uint8_t subAudio;
vgmstream->xa_channel=channel;
begin:
currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile);
subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile);
if ((currentChannel!=channel) && (subAudio==0x64)) {
block_offset+=2352;
goto begin;
}
return block_offset;
}

View File

@ -15,7 +15,7 @@
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
*/
#define INIT_VGMSTREAM_FCNS 16
#define INIT_VGMSTREAM_FCNS 17
VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_adx,
init_vgmstream_brstm,
@ -33,6 +33,7 @@ VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_ps2_ads,
init_vgmstream_ps2_npsf,
init_vgmstream_rwsd,
init_vgmstream_cdxa,
};
@ -153,6 +154,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
break;
case layout_ast_blocked:
case layout_halpst_blocked:
case layout_xa_blocked:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
}
@ -177,6 +179,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_NGC_AFC:
return 16;
case coding_PSX:
case coding_XA:
return 28;
default:
return 0;
@ -213,6 +216,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 9;
case coding_PSX:
return 16;
case coding_XA:
return 28;
default:
return 0;
}
@ -302,6 +307,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do);
}
break;
case coding_XA:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
}
}
@ -456,6 +468,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
snprintf(temp,TEMPSIZE,"Gamecube \"AFC\" 4-bit ADPCM");
break;
case coding_PSX:
case coding_XA:
snprintf(temp,TEMPSIZE,"Playstation 4-bit ADPCM");
break;
default:
@ -484,6 +497,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
break;
case layout_halpst_blocked:
snprintf(temp,TEMPSIZE,"HALPST blocked");
break;
case layout_xa_blocked:
snprintf(temp,TEMPSIZE,"CD-XA");
break;
default:
snprintf(temp,TEMPSIZE,"INCONCEIVABLE");
@ -563,6 +579,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_RWSD:
snprintf(temp,TEMPSIZE,"Nintendo RWSD header (single stream)");
break;
case meta_PSX_XA:
snprintf(temp,TEMPSIZE,"RIFF/CDXA Header");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
}

View File

@ -23,6 +23,7 @@ typedef enum {
coding_G721, /* CCITT G.721 ADPCM */
coding_NGC_AFC, /* NGC ADPCM, called AFC */
coding_PSX, /* PSX & PS2 ADPCM */
coding_XA, /* PSX CD-XA */
} coding_t;
/* The layout type specifies how the sound data is laid out in the file */
@ -38,6 +39,7 @@ typedef enum {
/* headered blocks */
layout_ast_blocked, /* .ast STRM with BLCK blocks*/
layout_halpst_blocked, /* blocks with HALPST-format header */
layout_xa_blocked,
#if 0
layout_strm_blocked, /* */
#endif
@ -74,6 +76,8 @@ typedef enum {
meta_PS2_SShd, /* .ADS with SShd header */
meta_PS2_NPSF, /* Namco Production Sound File */
meta_PSX_XA,
} meta_t;
typedef struct {
@ -151,6 +155,7 @@ typedef struct {
size_t loop_block_size; /* saved from current_block_size */
off_t loop_next_block_offset; /* saved from next_block_offset */
uint8_t xa_channel; /* Selected XA Channel */
} VGMSTREAM;
/* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */

View File

@ -45,7 +45,7 @@ int fade_samples = 0;
#define EXTENSION_LIST_SIZE 1024
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
#define EXTENSION_COUNT 15
#define EXTENSION_COUNT 16
char * extension_list[EXTENSION_COUNT] = {
"adx\0ADX Audio File (*.ADX)\0",
"afc\0AFC Audio File (*.AFC)\0",
@ -62,6 +62,7 @@ char * extension_list[EXTENSION_COUNT] = {
"ss2\0PS2 SS2 Audio File (*.SS2)\0",
"npsf\0PS2 NPSF Audio File (*.NPSF)\0",
"rwsd\0RWSD Audio File (*.RWSD)\0",
"xa\0PSX CD-XA File (*.XA)\0",
};
/* stubs, we don't do anything fancy yet */