.mwv, RIFF with Level-5 "0x555" ADPCM (new decoder)

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@551 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2009-01-04 15:36:06 +00:00
parent 87bb59f622
commit ac3fef6f7e
12 changed files with 157 additions and 5 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2008 Adam Gashlin, Fastelbja, Ronny Elfert
Copyright (c) 2008-2009 Adam Gashlin, Fastelbja, Ronny Elfert
Portions Copyright (c) 2004-2008, Marko Kreen
Portions Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>

View File

@ -206,6 +206,7 @@ etc:
- .bgw (FFXI PS-like ADPCM)
- .de2 (MS ADPCM)
- .kcey (EACS IMA ADPCM)
- .mwv (Level-5 0x555 ADPCM)
- .ogg, .logg (Ogg Vorbis)
- .rsf (CCITT G.721 ADPCM)
- .spw (FFXI PS-like ADPCM)

View File

@ -16,7 +16,8 @@ CODING_OBJS=coding/adx_decoder.o \
coding/nwa_decoder.o \
coding/msadpcm_decoder.o \
coding/aica_decoder.o \
coding/nds_procyon_decoder.o
coding/nds_procyon_decoder.o \
coding/l5_555_decoder.o
LAYOUT_OBJS=layout/ast_blocked.o \
layout/blocked.o \

View File

@ -24,5 +24,6 @@ libcoding_la_SOURCES += nwa_decoder.c
libcoding_la_SOURCES += aica_decoder.c
libcoding_la_SOURCES += msadpcm_decoder.c
libcoding_la_SOURCES += nds_procyon_decoder.c
libcoding_la_SOURCES += l5_555_decoder.c
EXTRA_DIST = coding.h g72x_state.h

View File

@ -78,4 +78,6 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
#endif

View File

@ -0,0 +1,58 @@
#include "coding.h"
#include "../util.h"
static const int32_t l5_scales[32] = {
0x00001000, 0x0000144E, 0x000019C5, 0x000020B4, 0x00002981, 0x000034AC, 0x000042D9, 0x000054D6,
0x00006BAB, 0x000088A4, 0x0000AD69, 0x0000DC13, 0x0001174C, 0x00016275, 0x0001C1D8, 0x00023AE5,
0x0002D486, 0x0003977E, 0x00048EEE, 0x0005C8F3, 0x00075779, 0x0009513E, 0x000BD31C, 0x000F01B5,
0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1
};
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i=first_sample;
int32_t sample_count;
int framesin = first_sample/32;
uint16_t header = (uint16_t)read_16bitLE(framesin*0x12+stream->offset,stream->streamfile);
int32_t pos_scale = l5_scales[(header>>5)&0x1f];
int32_t neg_scale = l5_scales[header&0x1f];
int coef_index = (header >> 10) & 0x1f;
int16_t hist1 = stream->adpcm_history1_16;
int16_t hist2 = stream->adpcm_history2_16;
int16_t hist3 = stream->adpcm_history3_16;
int32_t coef1 = stream->adpcm_coef_3by32[coef_index*3];
int32_t coef2 = stream->adpcm_coef_3by32[coef_index*3+1];
int32_t coef3 = stream->adpcm_coef_3by32[coef_index*3+2];
/*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n",
(unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/
first_sample = first_sample%32;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int sample_byte = read_8bit(framesin*0x12+stream->offset+2+i/2,stream->streamfile);
int nibble = (i&1?
get_low_nibble_signed(sample_byte):
get_high_nibble_signed(sample_byte));
int32_t prediction =
-(hist1 * coef1 + hist2 * coef2 + hist3 * coef3);
if (nibble >= 0)
{
outbuf[sample_count] = clamp16((prediction + nibble * pos_scale) >> 12);
}
else
{
outbuf[sample_count] = clamp16((prediction + nibble * neg_scale) >> 12);
}
hist3 = hist2;
hist2 = hist1;
hist1 = outbuf[sample_count];
}
stream->adpcm_history1_16 = hist1;
stream->adpcm_history2_16 = hist2;
stream->adpcm_history3_16 = hist3;
}

View File

@ -790,6 +790,10 @@
RelativePath=".\coding\ima_decoder.c"
>
</File>
<File
RelativePath=".\coding\l5_555_decoder.c"
>
</File>
<File
RelativePath=".\coding\mpeg_decoder.c"
>

View File

@ -104,10 +104,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
int FormatChunkFound = 0;
int DataChunkFound = 0;
/* Level-5 mwv */
int mwv = 0;
off_t mwv_pflt_offset = -1;
off_t mwv_ctrl_offset = -1;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("wav",filename_extension(filename)) &&
strcasecmp("lwav",filename_extension(filename))) goto fail;
strcasecmp("lwav",filename_extension(filename)))
{
if (strcasecmp("mwv",filename_extension(filename)))
goto fail;
else
mwv = 1;
}
/* check header */
if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */
@ -126,7 +137,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
{
off_t current_chunk = 0xc; /* start with first chunk */
while (current_chunk < file_size) {
while (current_chunk < file_size && current_chunk < riff_size+8) {
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
off_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
@ -156,6 +167,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
goto fail;
}
break;
case 0x555: /* Level-5 0x555 ADPCM */
if (!mwv) goto fail;
coding_type = coding_L5_555;
interleave = 0x12;
break;
default:
goto fail;
}
@ -196,6 +212,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
}
}
break;
case 0x70666c74: /* pflt */
if (!mwv) break; /* ignore if not in an mwv */
/* predictor filters */
mwv_pflt_offset = current_chunk;
break;
case 0x6374726c: /* ctrl */
if (!mwv) break; /* ignore if not in an mwv */
/* loops! */
if (read_32bitLE(current_chunk+8, streamFile))
{
loop_flag = 1;
}
mwv_ctrl_offset = current_chunk;
break;
default:
/* ignorance is bliss */
break;
@ -214,6 +244,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
case coding_PCM8_U_int:
sample_count = data_size/channel_count;
break;
case coding_L5_555:
sample_count = data_size/0x12/channel_count*32;
break;
}
/* build the VGMSTREAM */
@ -247,12 +280,39 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = loop_end_offset;
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
}
else if (mwv && mwv_ctrl_offset != -1)
{
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12,
streamFile);
vgmstream->loop_end_sample = sample_count;
}
}
else
{
vgmstream->meta_type = meta_RIFF_WAVE;
}
if (mwv)
{
int i;
if (coding_type == coding_L5_555)
{
if (mwv_pflt_offset == -1 ||
read_32bitLE(mwv_pflt_offset+8, streamFile) != 3 ||
read_32bitLE(mwv_pflt_offset+12, streamFile) != 0x20)
goto fail;
}
for (i = 0; i < 0x60; i++)
{
int c;
for (c = 0; c < channel_count; c++)
vgmstream->ch[c].adpcm_coef_3by32[i] = read_32bitLE(
mwv_pflt_offset+16+i*4, streamFile
);
}
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
}
/* open the file, set up each channel */
{
int i;

View File

@ -596,6 +596,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
switch (vgmstream->coding_type) {
case coding_CRI_ADX:
case coding_CRI_ADX_enc:
case coding_L5_555:
return 32;
case coding_NGC_DSP:
return 14;
@ -684,6 +685,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
switch (vgmstream->coding_type) {
case coding_CRI_ADX:
case coding_CRI_ADX_enc:
case coding_L5_555:
return 18;
case coding_NGC_DSP:
return 8;
@ -1035,6 +1037,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
case coding_L5_555:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_l5_555(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
}
}
@ -1359,6 +1369,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case coding_NDS_PROCYON:
snprintf(temp,TEMPSIZE,"Procyon Studio Digital Sound Elements NDS 4-bit APDCM");
break;
case coding_L5_555:
snprintf(temp,TEMPSIZE,"Level-5 0x555 ADPCM");
break;
default:
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
}
@ -2007,7 +2020,10 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_RSTM_shrunken:
snprintf(temp,TEMPSIZE,"Nintendo RSTM header, corrupted by Atlus");
break;
default:
case meta_RIFF_WAVE_MWV:
snprintf(temp,TEMPSIZE,"RIFF WAVE header with .mwv flavoring");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
}
concatn(length,desc,temp);

View File

@ -96,6 +96,7 @@ typedef enum {
coding_MSADPCM, /* Microsoft ADPCM */
coding_AICA, /* Yamaha AICA ADPCM */
coding_L5_555, /* Level-5 0x555 */
} coding_t;
/* The layout type specifies how the sound data is laid out in the file */
@ -344,6 +345,7 @@ typedef enum {
meta_RIFF_WAVE_POS, /* .wav + .pos for looping */
meta_RIFF_WAVE_labl_Marker, /* RIFF w/ loop Markers in LIST-adtl-labl */
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
meta_NWA, /* Visual Art's NWA */
meta_NWA_NWAINFOINI, /* NWA w/ NWAINFO.INI for looping */
meta_NWA_GAMEEXEINI, /* NWA w/ Gameexe.ini for looping */
@ -370,6 +372,7 @@ typedef struct {
/* adpcm */
int16_t adpcm_coef[16]; /* for formats with decode coefficients built in */
int32_t adpcm_coef_3by32[0x60]; /* for Level-5 0x555 */
union {
int16_t adpcm_history1_16; /* previous sample */
int32_t adpcm_history1_32;
@ -378,6 +381,10 @@ typedef struct {
int16_t adpcm_history2_16; /* previous previous sample */
int32_t adpcm_history2_32;
};
union {
int16_t adpcm_history3_16;
int32_t adpcm_history3_32;
};
int adpcm_step_index; /* for IMA */
int adpcm_scale; /* for MS ADPCM */

View File

@ -157,6 +157,7 @@ gchar *vgmstream_exts [] = {
"thp",
"rwar",
"aax",
"mwv",
/* terminator */
NULL
};

View File

@ -219,6 +219,7 @@ char * extension_list[] = {
"thp\0THP Audio File (*.THP)\0",
"rwar\0RWAR Audio File (*.RWSD)\0",
"aax\0AAX Audio File (*.AAX)\0",
"mwv\0MWV Audio File (*.MWV)\0",
};
void about(HWND hwndParent) {