mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-17 19:19:16 +01:00
add support for sdx2 in an AIFF-C package
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@265 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
b2e33edb5b
commit
451dfe0bd9
@ -8,7 +8,8 @@ CODING_OBJS=coding/adx_decoder.o \
|
||||
coding/psx_decoder.o \
|
||||
coding/xa_decoder.o \
|
||||
coding/eaxa_decoder.o \
|
||||
coding/ogg_vorbis_decoder.o
|
||||
coding/ogg_vorbis_decoder.o \
|
||||
coding/sdx2_decoder.o
|
||||
|
||||
LAYOUT_OBJS=layout/ast_blocked.o \
|
||||
layout/blocked.o \
|
||||
@ -56,7 +57,8 @@ META_OBJS=meta/adx_header.o \
|
||||
meta/ps2_vpk.o \
|
||||
meta/genh.o \
|
||||
meta/ogg_vorbis_file.o \
|
||||
meta/ps2_bmdx.o
|
||||
meta/ps2_bmdx.o \
|
||||
meta/aifc.o
|
||||
|
||||
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
|
||||
|
||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libcoding_la_LDFLAGS =
|
||||
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c ogg_vorbis_decoder.c
|
||||
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c ogg_vorbis_decoder.c sdx2_decoder.c
|
||||
|
||||
EXTRA_DIST = coding.h g72x_state.h
|
||||
|
@ -35,4 +35,6 @@ void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
#endif
|
||||
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
#endif
|
||||
|
52
src/coding/sdx2_decoder.c
Normal file
52
src/coding/sdx2_decoder.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* SDX2 - 2:1 Squareroot-delta-exact compression */
|
||||
|
||||
/* for (i=-128;i<128;i++) squares[i+128]=i<0?(-i*i)*2:(i*i)*2); */
|
||||
static int16_t squares[256] = {
|
||||
-32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848,
|
||||
-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898,
|
||||
-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,-19208,-18818,-18432,
|
||||
-18050,-17672,-17298,-16928,-16562,-16200,-15842,-15488,-15138,-14792,-14450,
|
||||
-14112,-13778,-13448,-13122,-12800,-12482,-12168,-11858,-11552,-11250,-10952,
|
||||
-10658,-10368,-10082, -9800, -9522, -9248, -8978, -8712, -8450, -8192, -7938,
|
||||
-7688, -7442, -7200, -6962, -6728, -6498, -6272, -6050, -5832, -5618, -5408,
|
||||
-5202, -5000, -4802, -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362,
|
||||
-3200, -3042, -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800,
|
||||
-1682, -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722,
|
||||
-648, -578, -512, -450, -392, -338, -288, -242, -200, -162, -128,
|
||||
-98, -72, -50, -32, -18, -8, -2, 0, 2, 8, 18,
|
||||
32, 50, 72, 98, 128, 162, 200, 242, 288, 338, 392,
|
||||
450, 512, 578, 648, 722, 800, 882, 968, 1058, 1152, 1250,
|
||||
1352, 1458, 1568, 1682, 1800, 1922, 2048, 2178, 2312, 2450, 2592,
|
||||
2738, 2888, 3042, 3200, 3362, 3528, 3698, 3872, 4050, 4232, 4418,
|
||||
4608, 4802, 5000, 5202, 5408, 5618, 5832, 6050, 6272, 6498, 6728,
|
||||
6962, 7200, 7442, 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522,
|
||||
9800, 10082, 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800,
|
||||
13122, 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562,
|
||||
16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, 20808,
|
||||
21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, 25088, 25538,
|
||||
25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, 29768, 30258, 30752,
|
||||
31250, 31752, 32258
|
||||
};
|
||||
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int32_t hist = stream->adpcm_history1_32;
|
||||
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
int16_t sample;
|
||||
|
||||
if (!(sample_byte & 1)) hist = 0;
|
||||
sample = hist + squares[sample_byte+128];
|
||||
|
||||
hist = outbuf[sample_count] = clamp16(sample);
|
||||
}
|
||||
stream->adpcm_history1_32=hist;
|
||||
}
|
@ -342,6 +342,10 @@
|
||||
RelativePath=".\meta\xbox_xwav.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\aifc.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
@ -406,6 +410,10 @@
|
||||
RelativePath=".\coding\xa_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\sdx2_decoder.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libmeta_la_LDFLAGS =
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c aifc.c
|
||||
|
||||
EXTRA_DIST = meta.h
|
||||
|
171
src/meta/aifc.c
Normal file
171
src/meta/aifc.c
Normal file
@ -0,0 +1,171 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Audio Interchange File Format AIFF-C */
|
||||
|
||||
/* for reading integers inexplicably packed into 80 bit floats */
|
||||
uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
|
||||
uint8_t buf[10];
|
||||
int32_t exponent;
|
||||
int32_t mantissa;
|
||||
int i;
|
||||
|
||||
if (read_streamfile(buf,offset,10,streamFile) != 10) return 0;
|
||||
|
||||
exponent = ((buf[0]<<8)|(buf[1]))&0x7fff;
|
||||
exponent -= 16383;
|
||||
|
||||
mantissa = 0;
|
||||
for (i=0;i<8;i++) {
|
||||
int32_t shift = exponent-7-i*8;
|
||||
if (shift >= 0)
|
||||
mantissa |= buf[i+2] << shift;
|
||||
else if (shift > -8)
|
||||
mantissa |= buf[i+2] >> -shift;
|
||||
}
|
||||
|
||||
return mantissa*((buf[0]&0x80)?-1:1);
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[260];
|
||||
|
||||
off_t file_size = -1;
|
||||
int channel_count = 0;
|
||||
int sample_count = 0;
|
||||
int sample_size = 0;
|
||||
int sample_rate = 0;
|
||||
int coding_type = -1;
|
||||
off_t start_offset = -1;
|
||||
int interleave = -1;
|
||||
|
||||
int FormatVersionChunkFound = 0;
|
||||
int CommonChunkFound = 0;
|
||||
int SoundDataChunkFound = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("aifc",filename_extension(filename)) &&
|
||||
strcasecmp("afc",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x464F524D || /* "FORM" */
|
||||
(uint32_t)read_32bitBE(8,streamFile)!=0x41494643 || /* "AIFC" */
|
||||
/* check that file = header (8) + data */
|
||||
read_32bitBE(4,streamFile)+8!=get_streamfile_size(streamFile)) goto fail;
|
||||
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
off_t current_chunk = 0xc; /* start with first chunk within FORM */
|
||||
|
||||
while (current_chunk < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile);
|
||||
|
||||
/* chunks must be padded to an even number of bytes but chunk
|
||||
* size does not include that padding */
|
||||
if (chunk_size % 2) chunk_size++;
|
||||
|
||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x46564552: /* FVER */
|
||||
/* only one per file */
|
||||
if (FormatVersionChunkFound) goto fail;
|
||||
FormatVersionChunkFound = 1;
|
||||
|
||||
/* specific size */
|
||||
if (chunk_size != 4) goto fail;
|
||||
|
||||
/* Version 1 of AIFF-C spec timestamp */
|
||||
if ((uint32_t)read_32bitBE(current_chunk+8,streamFile) !=
|
||||
0xA2805140) goto fail;
|
||||
break;
|
||||
case 0x434F4D4D: /* COMM */
|
||||
/* only one per file */
|
||||
if (CommonChunkFound) goto fail;
|
||||
CommonChunkFound = 1;
|
||||
|
||||
channel_count = read_16bitBE(current_chunk+8,streamFile);
|
||||
if (channel_count <= 0) goto fail;
|
||||
|
||||
sample_count = (uint32_t)read_32bitBE(current_chunk+0xa,streamFile);
|
||||
|
||||
sample_size = read_16bitBE(current_chunk+0xe,streamFile);
|
||||
|
||||
sample_rate = read80bitSANE(current_chunk+0x10,streamFile);
|
||||
|
||||
switch (read_32bitBE(current_chunk+0x1a,streamFile)) {
|
||||
case 0x53445832: /* SDX2 */
|
||||
coding_type = coding_SDX2;
|
||||
interleave = 1;
|
||||
break;
|
||||
default:
|
||||
/* we should probably support uncompressed here */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* we don't check the human-readable portion */
|
||||
|
||||
break;
|
||||
case 0x53534E44: /* SSND */
|
||||
/* at most one per file */
|
||||
if (SoundDataChunkFound) goto fail;
|
||||
SoundDataChunkFound = 1;
|
||||
|
||||
start_offset = current_chunk + 16 + read_32bitBE(current_chunk+8,streamFile);
|
||||
break;
|
||||
default:
|
||||
/* spec says we can skip unrecognized chunks */
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += 8+chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* we require at least these */
|
||||
if (!FormatVersionChunkFound || !CommonChunkFound || !SoundDataChunkFound)
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_AIFC;
|
||||
|
||||
/* open the file, set up each channel */
|
||||
{
|
||||
int i;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
||||
start_offset+i*interleave;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -91,4 +91,6 @@ VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_wsi(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_aifc(STREAMFILE * streamFile);
|
||||
|
||||
#endif
|
||||
|
@ -61,6 +61,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_sadb,
|
||||
init_vgmstream_ps2_bmdx,
|
||||
init_vgmstream_wsi,
|
||||
init_vgmstream_aifc,
|
||||
};
|
||||
|
||||
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
||||
@ -287,6 +288,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case coding_ogg_vorbis:
|
||||
#endif
|
||||
case coding_SDX2:
|
||||
return 1;
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_block_size-4)*2;
|
||||
@ -328,6 +330,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
case coding_PCM16BE:
|
||||
return 2;
|
||||
case coding_PCM8:
|
||||
case coding_SDX2:
|
||||
return 1;
|
||||
case coding_NDS_IMA:
|
||||
return vgmstream->interleave_block_size;
|
||||
@ -470,6 +473,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->channels);
|
||||
break;
|
||||
#endif
|
||||
case coding_SDX2:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_sdx2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,6 +666,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
snprintf(temp,TEMPSIZE,"Vorbis");
|
||||
break;
|
||||
#endif
|
||||
case coding_SDX2:
|
||||
snprintf(temp,TEMPSIZE,"Squareroot-delta-exact (SDX2) 8-bit DPCM");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
||||
}
|
||||
@ -891,6 +904,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
case meta_DSP_WSI:
|
||||
snprintf(temp,TEMPSIZE,".wsi header");
|
||||
break;
|
||||
case meta_AIFC:
|
||||
snprintf(temp,TEMPSIZE,"Audio Interchange File Format AIFF-C");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ typedef enum {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
coding_ogg_vorbis, /* vorbis */
|
||||
#endif
|
||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression */
|
||||
} coding_t;
|
||||
|
||||
/* The layout type specifies how the sound data is laid out in the file */
|
||||
@ -137,6 +138,8 @@ typedef enum {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
meta_ogg_vorbis, /* ogg vorbis */
|
||||
#endif
|
||||
|
||||
meta_AIFC, /* Audio Interchange File Format AIFF-C */
|
||||
} meta_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -61,6 +61,7 @@ gchar *vgmstream_exts [] = {
|
||||
"sad",
|
||||
"bmdx",
|
||||
"wsi",
|
||||
"aifc",
|
||||
/* terminator */
|
||||
NULL
|
||||
};
|
||||
|
@ -119,6 +119,7 @@ char * extension_list[] = {
|
||||
"sad\0SAD Audio File (*.SAD)\0",
|
||||
"bmdx\0BMDX Audio File (*.BMDX)\0",
|
||||
"wsi\0WSI Audio File (*.WSI)\0",
|
||||
"aifc\0AIFC Audio File (*.AIFC)\0",
|
||||
};
|
||||
|
||||
void about(HWND hwndParent) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user