mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-23 22:41:05 +01:00
.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:
parent
87bb59f622
commit
ac3fef6f7e
2
COPYING
2
COPYING
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
58
src/coding/l5_555_decoder.c
Normal file
58
src/coding/l5_555_decoder.c
Normal 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;
|
||||
}
|
@ -790,6 +790,10 @@
|
||||
RelativePath=".\coding\ima_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\l5_555_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\mpeg_decoder.c"
|
||||
>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -157,6 +157,7 @@ gchar *vgmstream_exts [] = {
|
||||
"thp",
|
||||
"rwar",
|
||||
"aax",
|
||||
"mwv",
|
||||
/* terminator */
|
||||
NULL
|
||||
};
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user