mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 15:00:11 +01:00
starting support for WS ADPCM, decoder not in place but layout is handled properly
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@282 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
253dd60d66
commit
0903e46346
@ -9,7 +9,8 @@ CODING_OBJS=coding/adx_decoder.o \
|
|||||||
coding/xa_decoder.o \
|
coding/xa_decoder.o \
|
||||||
coding/eaxa_decoder.o \
|
coding/eaxa_decoder.o \
|
||||||
coding/ogg_vorbis_decoder.o \
|
coding/ogg_vorbis_decoder.o \
|
||||||
coding/sdx2_decoder.o
|
coding/sdx2_decoder.o \
|
||||||
|
coding/ws_decoder.o
|
||||||
|
|
||||||
LAYOUT_OBJS=layout/ast_blocked.o \
|
LAYOUT_OBJS=layout/ast_blocked.o \
|
||||||
layout/blocked.o \
|
layout/blocked.o \
|
||||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
|||||||
AM_MAKEFLAGS=-f Makefile.unix
|
AM_MAKEFLAGS=-f Makefile.unix
|
||||||
|
|
||||||
libcoding_la_LDFLAGS =
|
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 sdx2_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 ws_decoder.c
|
||||||
|
|
||||||
EXTRA_DIST = coding.h g72x_state.h
|
EXTRA_DIST = coding.h g72x_state.h
|
||||||
|
@ -39,4 +39,6 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t sa
|
|||||||
|
|
||||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
|
|
||||||
|
void decode_ws(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
20
src/coding/ws_decoder.c
Normal file
20
src/coding/ws_decoder.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include "coding.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
/* Westwood Studios ADPCM */
|
||||||
|
|
||||||
|
/* Based on Valery V. Ansimovsky's WS-AUD.txt */
|
||||||
|
|
||||||
|
void decode_ws(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) {
|
||||||
|
outbuf[sample_count] = 0;
|
||||||
|
}
|
||||||
|
stream->adpcm_history1_32=hist;
|
||||||
|
}
|
@ -80,6 +80,10 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* for VBR these may change */
|
||||||
|
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||||
|
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||||
|
|
||||||
if (frame_size == 0) {
|
if (frame_size == 0) {
|
||||||
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame;
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,6 +11,13 @@ void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
|||||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||||
vgmstream->current_block_size + 8;
|
vgmstream->current_block_size + 8;
|
||||||
|
|
||||||
|
if (vgmstream->coding_type == coding_WS) {
|
||||||
|
/* this only works if the output sample size is 8 bit */
|
||||||
|
vgmstream->ws_output_samples = read_16bitLE(
|
||||||
|
vgmstream->current_block_offset+2,
|
||||||
|
vgmstream->ch[0].streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
for (i=0;i<vgmstream->channels;i++) {
|
for (i=0;i<vgmstream->channels;i++) {
|
||||||
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
vgmstream->ch[i].offset = vgmstream->current_block_offset +
|
||||||
8 + vgmstream->current_block_size*i;
|
8 + vgmstream->current_block_size*i;
|
||||||
|
@ -422,6 +422,10 @@
|
|||||||
RelativePath=".\coding\sdx2_decoder.c"
|
RelativePath=".\coding\sdx2_decoder.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\ws_decoder.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -9,6 +9,7 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
|
|||||||
char filename[260];
|
char filename[260];
|
||||||
|
|
||||||
coding_t coding_type = -1;
|
coding_t coding_type = -1;
|
||||||
|
off_t format_offset;
|
||||||
|
|
||||||
int channel_count;
|
int channel_count;
|
||||||
int new_type = 0; /* if 0 is old type */
|
int new_type = 0; /* if 0 is old type */
|
||||||
@ -22,32 +23,36 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
|
|||||||
/* check for 0x0000DEAF chunk marker for first chunk */
|
/* check for 0x0000DEAF chunk marker for first chunk */
|
||||||
if (read_32bitLE(0x10,streamFile)==0x0000DEAF) { /* new */
|
if (read_32bitLE(0x10,streamFile)==0x0000DEAF) { /* new */
|
||||||
new_type = 1;
|
new_type = 1;
|
||||||
} else if (read_32bitLE(0x08,streamFile)==0x0000DEAF) { /* old (?) */
|
} else if (read_32bitLE(0x0C,streamFile)==0x0000DEAF) { /* old */
|
||||||
new_type = 0;
|
new_type = 0;
|
||||||
} else goto fail;
|
} else goto fail;
|
||||||
|
|
||||||
if (!new_type) goto fail; /* TODO: not yet supported */
|
if (new_type)
|
||||||
|
format_offset = 0xa;
|
||||||
|
else
|
||||||
|
format_offset = 0x6;
|
||||||
|
|
||||||
/* get channel count */
|
/* get channel count */
|
||||||
if (read_8bit(0xa,streamFile) & 1)
|
if (read_8bit(format_offset,streamFile) & 1)
|
||||||
channel_count = 2;
|
channel_count = 2;
|
||||||
else
|
else
|
||||||
channel_count = 1;
|
channel_count = 1;
|
||||||
|
|
||||||
if (channel_count == 2) goto fail; /* TODO: not yet supported */
|
if (channel_count == 2) goto fail; /* TODO: not yet supported (largely
|
||||||
|
because not yet seen) */
|
||||||
|
|
||||||
/* get output format */
|
/* get output format */
|
||||||
if (read_8bit(0xa,streamFile) & 2)
|
if (read_8bit(format_offset+1,streamFile) & 2)
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = 2;
|
||||||
else
|
else
|
||||||
bytes_per_sample = 1;
|
bytes_per_sample = 1;
|
||||||
|
|
||||||
if (bytes_per_sample == 1) goto fail; /* TODO: not yet supported */
|
|
||||||
|
|
||||||
/* check codec type */
|
/* check codec type */
|
||||||
switch (read_8bit(0xb,streamFile)) {
|
switch (read_8bit(format_offset+1,streamFile)) {
|
||||||
case 1: /* Westwood custom */
|
case 1: /* Westwood custom */
|
||||||
goto fail; /* TODO: not yet supported */
|
coding_type = coding_WS;
|
||||||
|
/* shouldn't happen? */
|
||||||
|
if (bytes_per_sample != 1) goto fail;
|
||||||
break;
|
break;
|
||||||
case 99: /* IMA ADPCM */
|
case 99: /* IMA ADPCM */
|
||||||
coding_type = coding_IMA;
|
coding_type = coding_IMA;
|
||||||
@ -63,7 +68,28 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
|
|||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
/* fill in the vital statistics */
|
||||||
vgmstream->num_samples = read_32bitLE(0x06,streamFile)/bytes_per_sample/channel_count;
|
if (new_type) {
|
||||||
|
vgmstream->num_samples = read_32bitLE(0x06,streamFile)/bytes_per_sample/channel_count;
|
||||||
|
} else {
|
||||||
|
/* Doh, no output size in old type files. We have to read through the
|
||||||
|
* file looking at chunk headers! Crap! */
|
||||||
|
int32_t out_size = 0;
|
||||||
|
off_t current_offset = 0x8;
|
||||||
|
off_t file_size = get_streamfile_size(streamFile);
|
||||||
|
|
||||||
|
while (current_offset < file_size) {
|
||||||
|
int16_t chunk_size;
|
||||||
|
chunk_size = read_16bitLE(current_offset,streamFile);
|
||||||
|
out_size += read_16bitLE(current_offset+2,streamFile);
|
||||||
|
/* while we're here might as well check for valid chunks */
|
||||||
|
if (read_32bitLE(current_offset+4,streamFile) != 0x0000DEAF) goto fail;
|
||||||
|
current_offset+=8+chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgmstream->num_samples = out_size/bytes_per_sample/channel_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* they tend to not actually have data for the last odd sample */
|
||||||
if (vgmstream->num_samples & 1) vgmstream->num_samples--;
|
if (vgmstream->num_samples & 1) vgmstream->num_samples--;
|
||||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x00,streamFile);
|
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x00,streamFile);
|
||||||
|
|
||||||
|
@ -312,6 +312,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
return 64;
|
return 64;
|
||||||
case coding_EAXA:
|
case coding_EAXA:
|
||||||
return 28;
|
return 28;
|
||||||
|
case coding_WS:
|
||||||
|
return vgmstream->ws_output_samples;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -357,6 +359,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
return 36;
|
return 36;
|
||||||
case coding_EAXA:
|
case coding_EAXA:
|
||||||
return 1; // the frame is variant in size
|
return 1; // the frame is variant in size
|
||||||
|
case coding_WS:
|
||||||
|
return vgmstream->current_block_size;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -502,6 +506,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
samples_to_do);
|
samples_to_do);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case coding_WS:
|
||||||
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
decode_ws(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
|
vgmstream->channels,vgmstream->samples_into_block,
|
||||||
|
samples_to_do);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,6 +708,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||||||
case coding_IMA:
|
case coding_IMA:
|
||||||
snprintf(temp,TEMPSIZE,"4-bit IMA ADPCM");
|
snprintf(temp,TEMPSIZE,"4-bit IMA ADPCM");
|
||||||
break;
|
break;
|
||||||
|
case coding_WS:
|
||||||
|
snprintf(temp,TEMPSIZE,"Westwood Studios ADPCM");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ typedef enum {
|
|||||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression */
|
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression */
|
||||||
coding_DVI_IMA, /* DVI (bare IMA, high nibble first), aka ADP4 */
|
coding_DVI_IMA, /* DVI (bare IMA, high nibble first), aka ADP4 */
|
||||||
coding_IMA, /* bare IMA, low nibble first */
|
coding_IMA, /* bare IMA, low nibble first */
|
||||||
|
coding_WS, /* Westwood Studios' custom VBR ADPCM */
|
||||||
} coding_t;
|
} coding_t;
|
||||||
|
|
||||||
/* The layout type specifies how the sound data is laid out in the file */
|
/* The layout type specifies how the sound data is laid out in the file */
|
||||||
@ -228,6 +229,8 @@ typedef struct {
|
|||||||
uint8_t ea_compression_version;
|
uint8_t ea_compression_version;
|
||||||
uint8_t ea_platform;
|
uint8_t ea_platform;
|
||||||
|
|
||||||
|
int32_t ws_output_samples; /* output samples for this block */
|
||||||
|
|
||||||
void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream */
|
void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream */
|
||||||
|
|
||||||
/* Data the codec needs for the whole stream. This is for codecs too
|
/* Data the codec needs for the whole stream. This is for codecs too
|
||||||
|
Loading…
Reference in New Issue
Block a user